Merge "Prevent ConfigPusher from killing its thread"
[controller.git] / opendaylight / md-sal / compatibility / sal-compatibility / src / main / java / org / opendaylight / controller / sal / compatibility / InventoryAndReadAdapter.xtend
index d5fbd041e4a45d593d3d744e2aa6f5e90bc42288..60e43247c2810383f49b05a24699d14c1c1f355b 100644 (file)
@@ -1,8 +1,17 @@
+/*
+ * Copyright (c) 2014 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.controller.sal.compatibility
 
 import java.util.ArrayList
 import java.util.Collections
 import java.util.List
+import java.util.Set
+import java.util.concurrent.CopyOnWriteArrayList;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService
 import org.opendaylight.controller.sal.core.Edge
@@ -64,6 +73,9 @@ import org.slf4j.LoggerFactory
 
 import static extension org.opendaylight.controller.sal.common.util.Arguments.*
 import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
+import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
+import java.util.concurrent.ConcurrentHashMap
+import java.util.Map
 
 class InventoryAndReadAdapter implements IPluginInReadService,
                                                                                         IPluginInInventoryService,
@@ -90,15 +102,23 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     @Property
     OpendaylightFlowTableStatisticsService flowTableStatisticsService;
 
-    @Property
-    IPluginOutInventoryService inventoryPublisher;
-
     @Property
     FlowTopologyDiscoveryService topologyDiscovery;
     
     @Property
-    List<IPluginOutReadService> statisticsPublisher = new ArrayList<IPluginOutReadService>();
-       
+    List<IPluginOutReadService> statisticsPublisher = new CopyOnWriteArrayList<IPluginOutReadService>();
+
+    @Property
+    List<IPluginOutInventoryService> inventoryPublisher = new CopyOnWriteArrayList<IPluginOutInventoryService>();
+
+       def setInventoryPublisher(IPluginOutInventoryService listener){
+        inventoryPublisher.add(listener);
+       }
+
+       def unsetInventoryPublisher(IPluginOutInventoryService listener){
+        inventoryPublisher.remove(listener);
+       }
+
     def setReadPublisher(IPluginOutReadService listener) {
        statisticsPublisher.add(listener);
     }
@@ -129,12 +149,12 @@ class InventoryAndReadAdapter implements IPluginInReadService,
                val table= it.readConfigurationData(tableRef) as Table;
                
                if(table != null){
-                       LOG.info("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+                       LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
                        
                        for(flow : table.flow){
                                
-                               val adsalFlow = ToSalConversionsUtils.toFlow(flow);
-                               val statsFromDataStore = flow.getAugmentation(FlowStatisticsData) as FlowStatisticsData;
+                               val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
+                               val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
                                
                                if(statsFromDataStore != null){
                                        val it = new FlowOnNode(adsalFlow);
@@ -204,7 +224,7 @@ class InventoryAndReadAdapter implements IPluginInReadService,
                        
                        for (table : dsFlowCapableNode.table){
                                
-                               val tableStats = table.getAugmentation(FlowTableStatisticsData) as FlowTableStatisticsData;
+                               val tableStats = table.getAugmentation(FlowTableStatisticsData);
                                
                                if(tableStats != null){
                                        ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
@@ -235,11 +255,11 @@ class InventoryAndReadAdapter implements IPluginInReadService,
                val table= it.readConfigurationData(tableRef) as Table;
                
                if(table != null){
-                       LOG.info("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
+                       LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
                        
                        for(mdsalFlow : table.flow){
                                if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
-                                       val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData) as FlowStatisticsData;
+                                       val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
                                        
                                        if(statsFromDataStore != null){
                                                LOG.debug("Found matching flow in the data store flow table ");
@@ -305,7 +325,7 @@ class InventoryAndReadAdapter implements IPluginInReadService,
                val table= it.readConfigurationData(tableRef) as Table;
                
                if(table != null){
-                       val tableStats = table.getAugmentation(FlowTableStatisticsData) as FlowTableStatisticsData;
+                       val tableStats = table.getAugmentation(FlowTableStatisticsData);
                                
                        if(tableStats != null){
                                nodeStats =  toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
@@ -327,7 +347,7 @@ class InventoryAndReadAdapter implements IPluginInReadService,
     override onNodeRemoved(NodeRemoved notification) {
         val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
 
-        inventoryPublisher.updateNode(notification.nodeRef.toADNode, UpdateType.REMOVED, properties);
+        publishNodeUpdate(notification.nodeRef.toADNode, UpdateType.REMOVED, properties);
     }
 
     override onNodeConnectorUpdated(NodeConnectorUpdated update) {
@@ -338,44 +358,98 @@ class InventoryAndReadAdapter implements IPluginInReadService,
 
         var nodeConnector = update.nodeConnectorRef.toADNodeConnector
 
-        inventoryPublisher.updateNodeConnector(nodeConnector , updateType , update.toADNodeConnectorProperties);
+        publishNodeConnectorUpdate(nodeConnector , updateType , update.toADNodeConnectorProperties);
     }
 
     override onNodeUpdated(NodeUpdated notification) {
-        val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
         val InstanceIdentifier<? extends DataObject> identifier = notification.nodeRef.value  as InstanceIdentifier<? extends DataObject>;
 
         var updateType = UpdateType.CHANGED;
         if ( this._dataService.readOperationalData(identifier) == null ){
             updateType = UpdateType.ADDED;
         }
-        inventoryPublisher.updateNode(notification.nodeRef.toADNode, updateType, properties);
+        publishNodeUpdate(notification.nodeRef.toADNode, updateType, notification.toADNodeProperties);
         
                //Notify the listeners of IPluginOutReadService
         
         for (statsPublisher : statisticsPublisher){
                        val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
-                       statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,toNodeDescription(notification.nodeRef));
+            val description = notification.nodeRef.toNodeDescription
+            if(description != null) {
+                         statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
+                       }
                }
     }
 
     override getNodeProps() {
-
-        // FIXME: Read from MD-SAL inventory service
-        return null;
+        val props = new ConcurrentHashMap<Node, Map<String, org.opendaylight.controller.sal.core.Property>>()
+        
+        val nodes = readAllMDNodes()
+        for (node : nodes.node ) {
+            val fcn = node.getAugmentation(FlowCapableNode)
+            if(fcn != null) {
+                val perNodeProps = fcn.toADNodeProperties(node.id)
+                val perNodePropMap = new ConcurrentHashMap<String, org.opendaylight.controller.sal.core.Property>
+                if(perNodeProps != null ) {
+                    for(perNodeProp : perNodeProps) {
+                        perNodePropMap.put(perNodeProp.name,perNodeProp)
+                    }
+                }
+                props.put(new Node(MD_SAL_TYPE, node.id.toADNodeId),perNodePropMap)
+            }
+        }
+        return props;
+    }
+    
+    private def readAllMDNodes() {
+        val nodesRef = InstanceIdentifier.builder(Nodes)
+            .toInstance
+        val reader = TypeSafeDataReader.forReader(dataService)
+        return reader.readOperationalData(nodesRef)
+    }
+    
+    private def readAllMDNodeConnectors(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node) {
+        val nodeRef = InstanceIdentifier.builder(Nodes)
+            .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(node.id))
+            .toInstance
+        val reader = TypeSafeDataReader.forReader(dataService)
+        return reader.readOperationalData(nodeRef).nodeConnector
     }
 
     override getNodeConnectorProps(Boolean refresh) {
-
-        // FIXME: Read from MD-SAL Invcentory Service
-        return null;
+        // Note, because the MD-SAL has a unified data store, we can ignore the Boolean refresh, as we have no secondary 
+        // data store to refresh from
+        val props = new ConcurrentHashMap<org.opendaylight.controller.sal.core.NodeConnector, Map<String, org.opendaylight.controller.sal.core.Property>>()
+        val nodes = readAllMDNodes()
+        for (node : nodes.node) {
+            val ncs = node.readAllMDNodeConnectors
+            if(ncs != null) {
+                for( nc : ncs ) {
+                    val fcnc = nc.getAugmentation(FlowCapableNodeConnector)
+                    if(fcnc != null) {
+                        val ncps = fcnc.toADNodeConnectorProperties
+                        val ncpsm = new ConcurrentHashMap<String, org.opendaylight.controller.sal.core.Property>
+                        if(ncps != null) {
+                            for(p : ncps) {
+                                ncpsm.put(p.name,p)
+                            }
+                        }  
+                        props.put(nc.id.toADNodeConnector(node.id),ncpsm)
+                    }
+                }
+            }
+        }
+        return props
     }
 
     private def FlowCapableNode readFlowCapableNode(NodeRef ref) {
         val dataObject = dataService.readOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
-        val node = dataObject.checkInstanceOf(
-            org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node);
-        return node.getAugmentation(FlowCapableNode);
+        if(dataObject != null) {
+            val node = dataObject.checkInstanceOf(
+                org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node);
+            return node.getAugmentation(FlowCapableNode);
+        }
+        return null;
     }
 
     private def FlowCapableNodeConnector readFlowCapableNodeConnector(NodeConnectorRef ref) {
@@ -431,14 +505,16 @@ class InventoryAndReadAdapter implements IPluginInReadService,
        
        private def toNodeDescription(NodeRef nodeRef){
                val capableNode = readFlowCapableNode(nodeRef);
-
-        val it = new NodeDescription()
-        manufacturer = capableNode.manufacturer
-        serialNumber = capableNode.serialNumber
-        software = capableNode.software
-        description = capableNode.description
-        
-        return it;
+        if(capableNode !=null) {
+            val it = new NodeDescription()
+            manufacturer = capableNode.manufacturer
+            serialNumber = capableNode.serialNumber
+            software = capableNode.software
+            description = capableNode.description
+            
+            return it;
+         }
+         return null;
        }
     
     
@@ -450,20 +526,20 @@ class InventoryAndReadAdapter implements IPluginInReadService,
         * OpendaylightFlowStatisticsListener interface implementation
         */
        override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
-               throw new UnsupportedOperationException("TODO: auto-generated method stub")
+        //Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL
        }
        
        override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
                
                val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
+               val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
                
                for(flowStats : notification.flowAndStatisticsMapList){
                        if(flowStats.tableId == 0)
-                               adsalFlowsStatistics.add(toFlowOnNode(flowStats));
+                               adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
                }
                
                for (statsPublisher : statisticsPublisher){
-                       val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
                        statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
                }
                
@@ -508,9 +584,9 @@ class InventoryAndReadAdapter implements IPluginInReadService,
                
        }
        
-       private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap){
+       private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
                
-               val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap));
+               val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
                
                byteCount = flowAndStatsMap.byteCount.value.longValue;
                packetCount = flowAndStatsMap.packetCount.value.longValue;
@@ -519,4 +595,21 @@ class InventoryAndReadAdapter implements IPluginInReadService,
                
                return it;
        }
+
+       override  getConfiguredNotConnectedNodes() {
+        return Collections.emptySet();
+       }
+
+
+       private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+           for( publisher : inventoryPublisher){
+               publisher.updateNode(node, updateType, properties);
+           }
+       }
+
+       private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
+           for( publisher : inventoryPublisher){
+               publisher.updateNodeConnector(nodeConnector, updateType, properties);
+           }
+       }
 }