/* * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * 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.openflowplugin.applications.topology.manager; 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; @Singleton public class TerminationPointChangeListenerImpl extends DataTreeChangeListenerImpl { private static final Logger LOG = LoggerFactory.getLogger(TerminationPointChangeListenerImpl.class); @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()); this.operationProcessor = operationProcessor; } @Override public void onDataTreeChanged(@Nonnull Collection> modifications) { for (DataTreeModification 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()); } } } @Override @PreDestroy public void close() throws Exception { super.close(); } private void processRemovedTerminationPoints(final DataTreeModification modification) { final InstanceIdentifier removedNode = modification.getRootPath().getRootIdentifier(); final TpId terminationPointId = provideTopologyTerminationPointId(removedNode); final InstanceIdentifier iiToTopologyTerminationPoint = provideIIToTopologyTerminationPoint( terminationPointId, removedNode); if (iiToTopologyTerminationPoint != null) { final InstanceIdentifier 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 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."); } } private void processUpdatedTerminationPoints(final DataTreeModification modification) { // TODO Auto-generated method stub } private void processAddedTerminationPoints(final DataTreeModification modification) { final InstanceIdentifier iiToNodeInInventory = modification.getRootPath() .getRootIdentifier(); TpId terminationPointIdInTopology = provideTopologyTerminationPointId(iiToNodeInInventory); if (terminationPointIdInTopology != null) { InstanceIdentifier 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"); } } 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 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 provideIIToTopologyTerminationPoint( final TpId terminationPointIdInTopology, final InstanceIdentifier iiToNodeInInventory) { NodeId nodeIdInTopology = provideTopologyNodeId(iiToNodeInInventory); if (terminationPointIdInTopology != null && nodeIdInTopology != null) { InstanceIdentifier 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; } } private static TpId provideTopologyTerminationPointId( final InstanceIdentifier iiToNodeInInventory) { NodeConnectorKey inventoryNodeConnectorKey = iiToNodeInInventory.firstKeyOf(NodeConnector.class); if (inventoryNodeConnectorKey != null) { return new TpId(inventoryNodeConnectorKey.getId().getValue()); } return null; } }