Switch to MD-SAL APIs
[openflowplugin.git] / applications / topology-manager / src / main / java / org / opendaylight / openflowplugin / applications / topology / manager / TerminationPointChangeListenerImpl.java
index a5c48579cb8114dcf82984b31942d8dc3015e352..6831af0bcb6648222a97c0c4a87a19762b364a86 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  */
 package org.opendaylight.openflowplugin.applications.topology.manager;
 
-
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-
-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.node.TerminationPointBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.util.Map.Entry;
-import java.util.Map;
-import java.util.Set;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nonnull;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.apache.aries.blueprint.annotation.service.Reference;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.topology.inventory.rev131030.InventoryNodeConnectorBuilder;
+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.TpId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class TerminationPointChangeListenerImpl extends DataChangeListenerImpl {
-    private final static Logger LOG = LoggerFactory.getLogger(TerminationPointChangeListenerImpl.class);
+@Singleton
+public class TerminationPointChangeListenerImpl extends DataTreeChangeListenerImpl<FlowCapableNodeConnector> {
+    private static final Logger LOG = LoggerFactory.getLogger(TerminationPointChangeListenerImpl.class);
 
-    public TerminationPointChangeListenerImpl(final DataBroker dataBroker, final OperationProcessor operationProcessor) {
+    @Inject
+    public TerminationPointChangeListenerImpl(@Reference final DataBroker dataBroker,
+                                              final OperationProcessor operationProcessor) {
         super(operationProcessor, dataBroker,
-                InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class)
-                .child(NodeConnector.class)
-                .augmentation(FlowCapableNodeConnector.class)
-                .build());
+              InstanceIdentifier.builder(Nodes.class).child(Node.class).child(NodeConnector.class)
+                      .augmentation(FlowCapableNodeConnector.class).build());
         this.operationProcessor = operationProcessor;
     }
 
     @Override
-    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-        processAddedTerminationPoints(change.getCreatedData());
-        processUpdatedTerminationPoints(change.getUpdatedData());
-        processRemovedTerminationPoints(change.getRemovedPaths());
-    }
-
-    /**
-     * @param removedPaths
-     */
-    private void processRemovedTerminationPoints(Set<InstanceIdentifier<?>> removedNodes) {
-        for (final InstanceIdentifier<?> removedNode : removedNodes) {
-            InstanceIdentifier<TerminationPoint> iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint(provideTopologyTerminationPointId(removedNode), removedNode);
-            if (iiToTopologyTerminationPoint != null) {
-                operationProcessor.enqueueOperation(new TopologyOperation() {
-
-                    @Override
-                    public void applyOperation(ReadWriteTransaction transaction) {
-                        transaction.delete(LogicalDatastoreType.OPERATIONAL, removedNode);
-                    }
-                });
-
-            } else {
-                LOG.debug("Instance identifier to inventory wasn't translated to topology while deleting termination point.");
+    public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<FlowCapableNodeConnector>> modifications) {
+        for (DataTreeModification<FlowCapableNodeConnector> modification : modifications) {
+            switch (modification.getRootNode().getModificationType()) {
+                case WRITE:
+                    processAddedTerminationPoints(modification);
+                    break;
+                case SUBTREE_MODIFIED:
+                    processUpdatedTerminationPoints(modification);
+                    break;
+                case DELETE:
+                    processRemovedTerminationPoints(modification);
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unhandled modification type: {}" + modification.getRootNode().getModificationType());
             }
         }
     }
 
-    /**
-     * @param updatedData
-     */
-    private void processUpdatedTerminationPoints(Map<InstanceIdentifier<?>, DataObject> updatedData) {
-        // TODO Auto-generated method stub
+    @Override
+    @PreDestroy
+    public void close() throws Exception {
+        super.close();
     }
 
-    private void processAddedTerminationPoints(Map<InstanceIdentifier<?>, DataObject> addedDatas) {
-        for (Entry<InstanceIdentifier<?>, DataObject> addedData : addedDatas.entrySet()) {
-            createData(addedData.getKey(), addedData.getValue());
+    private void processRemovedTerminationPoints(final DataTreeModification<FlowCapableNodeConnector> modification) {
+        final InstanceIdentifier<FlowCapableNodeConnector> removedNode = modification.getRootPath().getRootIdentifier();
+        final TpId terminationPointId = provideTopologyTerminationPointId(removedNode);
+        final InstanceIdentifier<TerminationPoint> iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint(
+                terminationPointId, removedNode);
+
+        if (iiToTopologyTerminationPoint != null) {
+            final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology
+                    .rev131021.network.topology.topology.Node>
+                    node = iiToTopologyTerminationPoint.firstIdentifierOf(
+                    org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network
+                            .topology.topology.Node.class);
+            operationProcessor.enqueueOperation(manager -> {
+                Optional<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network
+                        .topology.topology.Node>
+                        nodeOptional = Optional.empty();
+                try {
+                    nodeOptional = manager.readFromTransaction(LogicalDatastoreType.OPERATIONAL, node).get();
+                } catch (InterruptedException | ExecutionException e) {
+                    LOG.warn("Error occurred when trying to read NodeConnector: {}", e.getMessage());
+                    LOG.debug("Error occurred when trying to read NodeConnector.. ", e);
+                }
+                if (nodeOptional.isPresent()) {
+                    TopologyManagerUtil.removeAffectedLinks(terminationPointId, manager, II_TO_TOPOLOGY);
+                    manager.addDeleteOperationToTxChain(LogicalDatastoreType.OPERATIONAL,
+                                                         iiToTopologyTerminationPoint);
+                }
+            });
+        } else {
+            LOG.debug(
+                    "Instance identifier to inventory wasn't translated to topology while deleting termination point.");
         }
     }
 
-    protected void createData(InstanceIdentifier<?> iiToNodeInInventory, final DataObject data) {
-        final TerminationPointBuilder terminationPointBuilder = new TerminationPointBuilder();
+    private void processUpdatedTerminationPoints(final DataTreeModification<FlowCapableNodeConnector> modification) {
+        // TODO Auto-generated method stub
+    }
 
+    private void processAddedTerminationPoints(final DataTreeModification<FlowCapableNodeConnector> modification) {
+        final InstanceIdentifier<FlowCapableNodeConnector> iiToNodeInInventory = modification.getRootPath()
+                .getRootIdentifier();
         TpId terminationPointIdInTopology = provideTopologyTerminationPointId(iiToNodeInInventory);
         if (terminationPointIdInTopology != null) {
-            terminationPointBuilder.setTpId(terminationPointIdInTopology);
-            InstanceIdentifier<TerminationPoint> iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint(terminationPointIdInTopology, iiToNodeInInventory);
-            sendToTransactionChain(terminationPointBuilder.build(), iiToTopologyTerminationPoint);
+            InstanceIdentifier<TerminationPoint> iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint(
+                    terminationPointIdInTopology, iiToNodeInInventory);
+            TerminationPoint point = prepareTopologyTerminationPoint(terminationPointIdInTopology, iiToNodeInInventory);
+            sendToTransactionChain(point, iiToTopologyTerminationPoint);
+            removeLinks(modification.getRootNode().getDataAfter(), point);
         } else {
             LOG.debug("Inventory node connector key is null. Data can't be written to topology termination point");
         }
     }
 
-    /**
-     * @param terminationPointIdInTopology
-     * @return
-     */
-    private InstanceIdentifier<TerminationPoint> provideIIToTopologyTerminationPoint(TpId terminationPointIdInTopology, InstanceIdentifier<?> iiToNodeInInventory) {
+    private void removeLinks(final FlowCapableNodeConnector flowCapNodeConnector, final TerminationPoint point) {
+        operationProcessor.enqueueOperation(manager -> {
+            if (flowCapNodeConnector.getState() != null && flowCapNodeConnector.getState().isLinkDown()
+                    || flowCapNodeConnector.getConfiguration() != null
+                        && flowCapNodeConnector.getConfiguration().isPORTDOWN()) {
+                TopologyManagerUtil.removeAffectedLinks(point.getTpId(), manager, II_TO_TOPOLOGY);
+            }
+        });
+    }
+
+    private static TerminationPoint prepareTopologyTerminationPoint(final TpId terminationPointIdInTopology,
+                                                                    final
+                                                                    InstanceIdentifier<FlowCapableNodeConnector>
+                                                                            iiToNodeInInventory) {
+        final InventoryNodeConnector inventoryNodeConnector = new InventoryNodeConnectorBuilder()
+                .setInventoryNodeConnectorRef(
+                        new NodeConnectorRef(iiToNodeInInventory.firstIdentifierOf(NodeConnector.class))).build();
+        final TerminationPointBuilder terminationPointBuilder = new TerminationPointBuilder();
+        terminationPointBuilder.setTpId(terminationPointIdInTopology);
+        terminationPointBuilder.addAugmentation(InventoryNodeConnector.class, inventoryNodeConnector);
+        return terminationPointBuilder.build();
+    }
+
+    private InstanceIdentifier<TerminationPoint> provideIIToTopologyTerminationPoint(
+            final TpId terminationPointIdInTopology,
+            final InstanceIdentifier<FlowCapableNodeConnector> iiToNodeInInventory) {
         NodeId nodeIdInTopology = provideTopologyNodeId(iiToNodeInInventory);
-        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node> iiToTopologyNode = provideIIToTopologyNode(nodeIdInTopology);
-        return iiToTopologyNode.builder().child(TerminationPoint.class, new TerminationPointKey(terminationPointIdInTopology)).build();
+        if (terminationPointIdInTopology != null && nodeIdInTopology != null) {
+            InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology
+                    .rev131021.network.topology.topology.Node>
+                    iiToTopologyNode = provideIIToTopologyNode(nodeIdInTopology);
+            return iiToTopologyNode.builder()
+                    .child(TerminationPoint.class, new TerminationPointKey(terminationPointIdInTopology)).build();
+        } else {
+            LOG.debug(
+                    "Value of termination point ID in topology is null. Instance identifier to topology can't be "
+                            + "built");
+            return null;
+        }
     }
 
-    /**
-     * @param iiToNodeInInventory
-     * @return
-     */
-    private TpId provideTopologyTerminationPointId(InstanceIdentifier<?> iiToNodeInInventory) {
-        NodeConnectorKey inventoryNodeConnectorKey = iiToNodeInInventory.firstKeyOf(NodeConnector.class, NodeConnectorKey.class);
+    private static TpId provideTopologyTerminationPointId(
+            final InstanceIdentifier<FlowCapableNodeConnector> iiToNodeInInventory) {
+        NodeConnectorKey inventoryNodeConnectorKey = iiToNodeInInventory.firstKeyOf(NodeConnector.class);
         if (inventoryNodeConnectorKey != null) {
             return new TpId(inventoryNodeConnectorKey.getId().getValue());
         }