Merge "BUG-509: Rename MutableDataTree to DataTreeModification"
[controller.git] / opendaylight / md-sal / compatibility / sal-compatibility / src / main / java / org / opendaylight / controller / sal / compatibility / InventoryAndReadAdapter.xtend
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.sal.compatibility
9
10 import java.util.ArrayList
11 import java.util.Collections
12 import java.util.List
13 import java.util.Map
14 import java.util.Set
15 import java.util.concurrent.ConcurrentHashMap
16 import java.util.concurrent.CopyOnWriteArrayList
17 import java.util.concurrent.locks.Lock
18 import java.util.concurrent.locks.ReentrantLock
19 import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader
20 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
21 import org.opendaylight.controller.sal.binding.api.data.DataProviderService
22 import org.opendaylight.controller.sal.core.Edge
23 import org.opendaylight.controller.sal.core.Node
24 import org.opendaylight.controller.sal.core.NodeTable
25 import org.opendaylight.controller.sal.core.UpdateType
26 import org.opendaylight.controller.sal.flowprogrammer.Flow
27 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService
28 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService
29 import org.opendaylight.controller.sal.reader.FlowOnNode
30 import org.opendaylight.controller.sal.reader.IPluginInReadService
31 import org.opendaylight.controller.sal.reader.IPluginOutReadService
32 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics
33 import org.opendaylight.controller.sal.reader.NodeDescription
34 import org.opendaylight.controller.sal.reader.NodeTableStatistics
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.Link
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatistics
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsInputBuilder
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService
75 import org.opendaylight.yangtools.yang.binding.DataObject
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
77 import org.slf4j.LoggerFactory
78
79 import static extension org.opendaylight.controller.sal.common.util.Arguments.*
80 import static extension org.opendaylight.controller.sal.compatibility.NodeMapping.*
81
82 class InventoryAndReadAdapter implements IPluginInReadService,
83                                              IPluginInInventoryService,
84                                              OpendaylightInventoryListener,
85                                              OpendaylightFlowStatisticsListener,
86                                              OpendaylightFlowTableStatisticsListener,
87                                              OpendaylightPortStatisticsListener {
88
89     private static val LOG = LoggerFactory.getLogger(InventoryAndReadAdapter);
90
91     private static val OPENFLOWV10_TABLE_ID = new Integer(0).shortValue;
92     @Property
93     DataBrokerService dataService;
94
95     @Property
96     DataProviderService dataProviderService;
97
98     @Property
99     OpendaylightFlowStatisticsService flowStatisticsService;
100
101     @Property
102     OpendaylightPortStatisticsService nodeConnectorStatisticsService;
103     
104     @Property
105     OpendaylightFlowTableStatisticsService flowTableStatisticsService;
106
107     @Property
108     FlowTopologyDiscoveryService topologyDiscovery;
109     
110     @Property
111     List<IPluginOutReadService> statisticsPublisher = new CopyOnWriteArrayList<IPluginOutReadService>();
112
113     @Property
114     List<IPluginOutInventoryService> inventoryPublisher = new CopyOnWriteArrayList<IPluginOutInventoryService>();
115
116     private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider();
117
118     private final Map<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>> nodeToNodeConnectorsMap = new ConcurrentHashMap<InstanceIdentifier.PathArgument, List<InstanceIdentifier.PathArgument>>();
119
120     private final Lock nodeToNodeConnectorsLock = new ReentrantLock();
121
122
123     def startAdapter(){
124         inventoryNotificationProvider.dataProviderService = dataProviderService;
125         inventoryNotificationProvider.inventoryPublisher = inventoryPublisher;
126         // inventoryNotificationProvider.start();
127     }
128
129     def start(){
130     }
131
132     def setInventoryPublisher(IPluginOutInventoryService listener){
133         inventoryPublisher.add(listener);
134     }
135
136     def unsetInventoryPublisher(IPluginOutInventoryService listener){
137         inventoryPublisher.remove(listener);
138     }
139
140     def setReadPublisher(IPluginOutReadService listener) {
141         statisticsPublisher.add(listener);
142     }
143     
144     def unsetReadPublisher (IPluginOutReadService listener) {
145         if( listener != null)
146             statisticsPublisher.remove(listener);
147     }
148
149     protected def startChange() {
150         return dataProviderService.beginTransaction;
151     }
152
153     override getTransmitRate(org.opendaylight.controller.sal.core.NodeConnector connector) {
154         val nodeConnector = readFlowCapableNodeConnector(connector.toNodeConnectorRef);
155         return nodeConnector.currentSpeed
156     }
157
158     override readAllFlow(Node node, boolean cached) {
159
160         val output = new ArrayList<FlowOnNode>();
161         val tableRef = InstanceIdentifier.builder(Nodes)
162                                         .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
163                                         .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
164         
165         val it = this.startChange();
166         
167         val table= it.readConfigurationData(tableRef) as Table;
168         
169         if(table != null){
170             LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
171             
172             for(flow : table.flow){
173                 
174                 val adsalFlow = ToSalConversionsUtils.toFlow(flow,node);
175                 val statsFromDataStore = flow.getAugmentation(FlowStatisticsData);
176                 
177                 if(statsFromDataStore != null){
178                     val it = new FlowOnNode(adsalFlow);
179                     byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
180                     packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
181                     durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
182                     durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
183                     
184                     output.add(it);
185                 }
186             }
187         }
188         
189         //TODO (main): Shell we send request to the switch? It will make async request to the switch.
190         // Once plugin receive response, it will let adaptor know through onFlowStatisticsUpdate()
191         // If we assume that md-sal statistics manager will always be running, then its not required
192         // But if not, then sending request will collect the latest data for adaptor atleast.
193         val input = new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
194         input.setNode(node.toNodeRef);
195         flowStatisticsService.getAllFlowsStatisticsFromAllFlowTables(input.build)
196         
197         return output;
198     }
199
200     override readAllNodeConnector(Node node, boolean cached) {
201         
202         val ret = new ArrayList<NodeConnectorStatistics>();
203         val nodeRef = InstanceIdentifier.builder(Nodes)
204                                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
205                                     .toInstance();
206         
207         val provider = this.startChange();
208         
209         val dsNode= provider.readConfigurationData(nodeRef) as org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
210         
211          if(dsNode != null){
212              
213              for (dsNodeConnector : dsNode.nodeConnector){
214                 val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
215                                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
216                                     .child(NodeConnector, dsNodeConnector.key)
217                                     .toInstance();
218                  
219                  val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
220                  
221                  if(nodeConnectorFromDS != null){
222                      val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
223                      
224                     ret.add(toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,dsNode.id,dsNodeConnector.id));
225                  }
226              }
227          }
228
229         //TODO: Refer TODO (main)
230         val input = new GetAllNodeConnectorsStatisticsInputBuilder();
231         input.setNode(node.toNodeRef);
232         nodeConnectorStatisticsService.getAllNodeConnectorsStatistics(input.build());
233         return ret;
234     }
235
236     override readAllNodeTable(Node node, boolean cached) {
237         val ret = new ArrayList<NodeTableStatistics>();
238         
239         val dsFlowCapableNode= readFlowCapableNode(node.toNodeRef)
240         
241          if(dsFlowCapableNode != null){
242              
243              for (table : dsFlowCapableNode.table){
244                  
245                  val tableStats = table.getAugmentation(FlowTableStatisticsData);
246                  
247                  if(tableStats != null){
248                      ret.add(toNodeTableStatistics(tableStats.flowTableStatistics,table.id,node));
249                  }
250              }
251          }
252
253         //TODO: Refer TODO (main)
254         val input = new GetFlowTablesStatisticsInputBuilder();
255         input.setNode(node.toNodeRef);
256         flowTableStatisticsService.getFlowTablesStatistics(input.build);
257         return ret;
258     }
259
260     override readDescription(Node node, boolean cached) {
261         return toNodeDescription(node.toNodeRef);
262     }
263
264     override readFlow(Node node, Flow targetFlow, boolean cached) {
265         var FlowOnNode ret= null;
266         
267         val tableRef = InstanceIdentifier.builder(Nodes)
268                                         .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(node))
269                                         .augmentation(FlowCapableNode).child(Table, new TableKey(OPENFLOWV10_TABLE_ID)).toInstance();
270         
271         val it = this.startChange();
272         
273         val table= it.readConfigurationData(tableRef) as Table;
274         
275         if(table != null){
276             LOG.trace("Number of flows installed in table 0 of node {} : {}",node,table.flow.size);
277             
278             for(mdsalFlow : table.flow){
279                 if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))){
280                     val statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData);
281                     
282                     if(statsFromDataStore != null){
283                         LOG.debug("Found matching flow in the data store flow table ");
284                         val it = new FlowOnNode(targetFlow);
285                         byteCount =  statsFromDataStore.flowStatistics.byteCount.value.longValue;
286                         packetCount = statsFromDataStore.flowStatistics.packetCount.value.longValue;
287                         durationSeconds = statsFromDataStore.flowStatistics.duration.second.value.intValue;
288                         durationNanoseconds = statsFromDataStore.flowStatistics.duration.nanosecond.value.intValue;
289                         
290                         ret = it;
291                     }
292                 }            
293             }
294         }
295         
296         //TODO: Refer TODO (main)
297         val input = new GetFlowStatisticsFromFlowTableInputBuilder;
298         input.setNode(node.toNodeRef);
299         input.fieldsFrom(MDFlowMapping.toMDSalflow(targetFlow));
300         flowStatisticsService.getFlowStatisticsFromFlowTable(input.build)
301         
302         return ret;
303         
304     }
305
306     override readNodeConnector(org.opendaylight.controller.sal.core.NodeConnector connector, boolean cached) {
307         var NodeConnectorStatistics  nodeConnectorStatistics = null;
308     
309         val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
310                                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(connector.node))
311                                     .child(NodeConnector, InventoryMapping.toNodeConnectorKey(connector))
312                                     .toInstance();
313          val provider = this.startChange();
314                  
315          val nodeConnectorFromDS = provider.readConfigurationData(nodeConnectorRef) as NodeConnector;
316                  
317          if(nodeConnectorFromDS != null){
318             val nodeConnectorStatsFromDs = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData) as FlowCapableNodeConnectorStatistics;
319             if(nodeConnectorStatsFromDs != null) {
320                 nodeConnectorStatistics = toNodeConnectorStatistics(nodeConnectorStatsFromDs.flowCapableNodeConnectorStatistics,
321                                                                         InventoryMapping.toNodeKey(connector.node).id,
322                                                                         InventoryMapping.toNodeConnectorKey(connector).id);
323             }
324         }
325
326         //TODO: Refer TODO (main)
327         val input = new GetNodeConnectorStatisticsInputBuilder();
328         input.setNode(connector.node.toNodeRef);
329         input.setNodeConnectorId(InventoryMapping.toNodeConnectorKey(connector).id);
330         nodeConnectorStatisticsService.getNodeConnectorStatistics(input.build());
331         return nodeConnectorStatistics;
332     }
333
334     override readNodeTable(NodeTable nodeTable, boolean cached) {
335         var NodeTableStatistics nodeStats = null
336         
337         val tableRef = InstanceIdentifier.builder(Nodes)
338                                         .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node, InventoryMapping.toNodeKey(nodeTable.node))
339                                         .augmentation(FlowCapableNode).child(Table, new TableKey(nodeTable.ID as Short)).toInstance();
340         
341         val it = this.startChange();
342         
343         val table= it.readConfigurationData(tableRef) as Table;
344         
345         if(table != null){
346             val tableStats = table.getAugmentation(FlowTableStatisticsData);
347                  
348              if(tableStats != null){
349                  nodeStats =  toNodeTableStatistics(tableStats.flowTableStatistics,table.id,nodeTable.node);
350             }
351         }
352
353         //TODO: Refer TODO (main)
354         val input = new GetFlowTablesStatisticsInputBuilder();
355         input.setNode(nodeTable.node.toNodeRef);
356         flowTableStatisticsService.getFlowTablesStatistics(input.build);
357         
358         return nodeStats;
359     }
360
361     override onNodeConnectorRemoved(NodeConnectorRemoved update) {
362         // Never received
363     }
364
365     override onNodeRemoved(NodeRemoved notification) {
366         val properties = Collections.<org.opendaylight.controller.sal.core.Property>emptySet();
367
368         removeNodeConnectors(notification.nodeRef.value);
369
370         publishNodeUpdate(notification.nodeRef.toADNode, UpdateType.REMOVED, properties);
371     }
372
373     override onNodeConnectorUpdated(NodeConnectorUpdated update) {
374         var updateType = UpdateType.CHANGED;
375         if(!isKnownNodeConnector(update.nodeConnectorRef.value)){
376             updateType = UpdateType.ADDED;
377             recordNodeConnector(update.nodeConnectorRef.value);
378         }
379
380         var nodeConnector = update.nodeConnectorRef.toADNodeConnector
381
382         publishNodeConnectorUpdate(nodeConnector , updateType , update.toADNodeConnectorProperties);
383     }
384
385     override onNodeUpdated(NodeUpdated notification) {
386         val InstanceIdentifier<? extends DataObject> identifier = notification.nodeRef.value  as InstanceIdentifier<? extends DataObject>;
387
388         var updateType = UpdateType.CHANGED;
389         if ( this._dataService.readOperationalData(identifier) == null ){
390             updateType = UpdateType.ADDED;
391         }
392         publishNodeUpdate(notification.nodeRef.toADNode, updateType, notification.toADNodeProperties);
393
394         //Notify the listeners of IPluginOutReadService
395
396         for (statsPublisher : statisticsPublisher){
397             val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
398             val description = notification.nodeRef.toNodeDescription
399             if(description != null) {
400               statsPublisher.descriptionStatisticsUpdated(nodeRef.toADNode,description);
401             }
402         }
403     }
404
405     override getNodeProps() {
406         val props = new ConcurrentHashMap<Node, Map<String, org.opendaylight.controller.sal.core.Property>>()
407         
408         val nodes = readAllMDNodes()
409         for (node : nodes.node ) {
410             val fcn = node.getAugmentation(FlowCapableNode)
411             if(fcn != null) {
412                 val perNodeProps = fcn.toADNodeProperties(node.id)
413                 val perNodePropMap = new ConcurrentHashMap<String, org.opendaylight.controller.sal.core.Property>
414                 if(perNodeProps != null ) {
415                     for(perNodeProp : perNodeProps) {
416                         perNodePropMap.put(perNodeProp.name,perNodeProp)
417                     }
418                 }
419                 props.put(new Node(MD_SAL_TYPE, node.id.toADNodeId),perNodePropMap)
420             }
421         }
422         return props;
423     }
424     
425     private def readAllMDNodes() {
426         val nodesRef = InstanceIdentifier.builder(Nodes)
427             .toInstance
428         val reader = TypeSafeDataReader.forReader(dataService)
429         return reader.readOperationalData(nodesRef)
430     }
431     
432     private def readAllMDNodeConnectors(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node) {
433         val nodeRef = InstanceIdentifier.builder(Nodes)
434             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(node.id))
435             .toInstance
436         val reader = TypeSafeDataReader.forReader(dataService)
437         return reader.readOperationalData(nodeRef).nodeConnector
438     }
439
440     override getNodeConnectorProps(Boolean refresh) {
441         // Note, because the MD-SAL has a unified data store, we can ignore the Boolean refresh, as we have no secondary 
442         // data store to refresh from
443         val props = new ConcurrentHashMap<org.opendaylight.controller.sal.core.NodeConnector, Map<String, org.opendaylight.controller.sal.core.Property>>()
444         val nodes = readAllMDNodes()
445         for (node : nodes.node) {
446             val ncs = node.readAllMDNodeConnectors
447             if(ncs != null) {
448                 for( nc : ncs ) {
449                     val fcnc = nc.getAugmentation(FlowCapableNodeConnector)
450                     if(fcnc != null) {
451                         val ncps = fcnc.toADNodeConnectorProperties
452                         val ncpsm = new ConcurrentHashMap<String, org.opendaylight.controller.sal.core.Property>
453                         if(ncps != null) {
454                             for(p : ncps) {
455                                 ncpsm.put(p.name,p)
456                             }
457                         }  
458                         props.put(nc.id.toADNodeConnector(node.id),ncpsm)
459                     }
460                 }
461             }
462         }
463         return props
464     }
465
466     private def FlowCapableNode readFlowCapableNode(NodeRef ref) {
467         val dataObject = dataService.readOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
468         if(dataObject != null) {
469             val node = dataObject.checkInstanceOf(
470                 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node);
471             return node.getAugmentation(FlowCapableNode);
472         }
473         return null;
474     }
475
476     private def FlowCapableNodeConnector readFlowCapableNodeConnector(NodeConnectorRef ref) {
477         val dataObject = dataService.readOperationalData(ref.value as InstanceIdentifier<? extends DataObject>);
478         val node = dataObject.checkInstanceOf(
479             NodeConnector);
480         return node.getAugmentation(FlowCapableNodeConnector);
481     }
482
483     private def toNodeConnectorStatistics(
484         org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, NodeId nodeId, NodeConnectorId nodeConnectorId) {
485             
486             val it = new NodeConnectorStatistics();
487             
488             receivePacketCount = nodeConnectorStatistics.packets.received.longValue;
489             transmitPacketCount = nodeConnectorStatistics.packets.transmitted.longValue;
490             
491             receiveByteCount = nodeConnectorStatistics.bytes.received.longValue;
492             transmitByteCount = nodeConnectorStatistics.bytes.transmitted.longValue;
493             
494             receiveDropCount = nodeConnectorStatistics.receiveDrops.longValue;
495             transmitDropCount = nodeConnectorStatistics.transmitDrops.longValue;
496             
497             receiveErrorCount = nodeConnectorStatistics.receiveErrors.longValue;
498             transmitErrorCount = nodeConnectorStatistics.transmitErrors.longValue;
499             
500             receiveFrameErrorCount = nodeConnectorStatistics.receiveFrameError.longValue;
501             receiveOverRunErrorCount = nodeConnectorStatistics.receiveOverRunError.longValue;
502             receiveCRCErrorCount = nodeConnectorStatistics.receiveCrcError.longValue;
503             collisionCount = nodeConnectorStatistics.collisionCount.longValue;
504             
505             val nodeConnectorRef = InstanceIdentifier.builder(Nodes)
506                                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(nodeId))
507                                 .child(NodeConnector,new NodeConnectorKey(nodeConnectorId)).toInstance;
508             
509             nodeConnector = NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef));
510             
511             return it;
512     }
513
514     private def toNodeTableStatistics(
515         FlowTableStatistics tableStats,
516         Short tableId,Node node){
517         var it = new NodeTableStatistics();
518         
519         activeCount = tableStats.activeFlows.value.intValue;
520         lookupCount = tableStats.packetsLookedUp.value.intValue;
521         matchedCount = tableStats.packetsMatched.value.intValue;
522         name = tableId.toString;
523         nodeTable = new NodeTable(NodeMapping.MD_SAL_TYPE,tableId,node);
524         return it;
525     }
526     
527     private def toNodeDescription(NodeRef nodeRef){
528         val capableNode = readFlowCapableNode(nodeRef);
529         if(capableNode !=null) {
530             val it = new NodeDescription()
531             manufacturer = capableNode.manufacturer
532             serialNumber = capableNode.serialNumber
533             software = capableNode.software
534             description = capableNode.description
535             
536             return it;
537          }
538          return null;
539     }
540     
541     
542     def Edge toADEdge(Link link) {
543         new Edge(link.source.toADNodeConnector,link.destination.toADNodeConnector)
544     }
545     
546     /*
547      * OpendaylightFlowStatisticsListener interface implementation
548      */
549     override onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
550         //Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL
551     }
552     
553     override onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
554         
555         val adsalFlowsStatistics = new ArrayList<FlowOnNode>();
556         val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
557         
558         for(flowStats : notification.flowAndStatisticsMapList){
559             if(flowStats.tableId == 0)
560                 adsalFlowsStatistics.add(toFlowOnNode(flowStats,nodeRef.toADNode));
561         }
562         
563         for (statsPublisher : statisticsPublisher){
564             statsPublisher.nodeFlowStatisticsUpdated(nodeRef.toADNode,adsalFlowsStatistics);
565         }
566         
567     }
568     /*
569      * OpendaylightFlowTableStatisticsListener interface implementation
570      */    
571     override onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
572         var adsalFlowTableStatistics = new ArrayList<NodeTableStatistics>();
573         
574         for(stats : notification.flowTableAndStatisticsMap){
575             if (stats.tableId.value == 0){
576                 val it = new NodeTableStatistics();
577                 activeCount = stats.activeFlows.value.intValue;
578                 lookupCount = stats.packetsLookedUp.value.longValue;
579                 matchedCount = stats.packetsMatched.value.longValue;
580                 
581                 adsalFlowTableStatistics.add(it);
582             }
583         }
584         for (statsPublisher : statisticsPublisher){
585             val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
586             statsPublisher.nodeTableStatisticsUpdated(nodeRef.toADNode,adsalFlowTableStatistics);
587         }
588     }
589     
590     /*
591      * OpendaylightPortStatisticsUpdate interface implementation
592      */
593     override onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
594         
595         val adsalPortStatistics  = new ArrayList<NodeConnectorStatistics>();
596         
597         for(nodeConnectorStatistics : notification.nodeConnectorStatisticsAndPortNumberMap){
598             adsalPortStatistics.add(toNodeConnectorStatistics(nodeConnectorStatistics,notification.id,nodeConnectorStatistics.nodeConnectorId));
599         }
600         
601         for (statsPublisher : statisticsPublisher){
602             val nodeRef = InstanceIdentifier.builder(Nodes).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node,new NodeKey(notification.id)).toInstance;
603             statsPublisher.nodeConnectorStatisticsUpdated(nodeRef.toADNode,adsalPortStatistics);
604         }
605         
606     }
607     
608     private static def toFlowOnNode (FlowAndStatisticsMapList flowAndStatsMap,Node node){
609         
610         val it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap,node));
611         
612         byteCount = flowAndStatsMap.byteCount.value.longValue;
613         packetCount = flowAndStatsMap.packetCount.value.longValue;
614         durationSeconds = flowAndStatsMap.duration.second.value.intValue;
615         durationNanoseconds = flowAndStatsMap.duration.nanosecond.value.intValue;
616         
617         return it;
618     }
619
620     override  getConfiguredNotConnectedNodes() {
621         return Collections.emptySet();
622     }
623
624
625     private def publishNodeUpdate(Node node, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
626         for( publisher : inventoryPublisher){
627             publisher.updateNode(node, updateType, properties);
628         }
629     }
630
631     private def publishNodeConnectorUpdate(org.opendaylight.controller.sal.core.NodeConnector nodeConnector, UpdateType updateType, Set<org.opendaylight.controller.sal.core.Property> properties){
632         for( publisher : inventoryPublisher){
633             publisher.updateNodeConnector(nodeConnector, updateType, properties);
634         }
635     }
636
637     private def isKnownNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
638         if(nodeConnectorIdentifier.path.size() < 3) {
639             return false;
640         }
641
642         val nodePath = nodeConnectorIdentifier.path.get(1);
643         val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
644
645         val nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
646
647         if(nodeConnectors == null){
648             return false;
649         }
650         return nodeConnectors.contains(nodeConnectorPath);
651     }
652
653
654     private def recordNodeConnector(InstanceIdentifier<? extends Object> nodeConnectorIdentifier){
655         if(nodeConnectorIdentifier.path.size() < 3) {
656             return false;
657         }
658
659         val nodePath = nodeConnectorIdentifier.path.get(1);
660         val nodeConnectorPath = nodeConnectorIdentifier.getPath().get(2);
661
662         nodeToNodeConnectorsLock.lock();
663
664         try {
665             var nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
666
667             if(nodeConnectors == null){
668                 nodeConnectors = new ArrayList<InstanceIdentifier.PathArgument>();
669                 nodeToNodeConnectorsMap.put(nodePath, nodeConnectors);
670             }
671
672             nodeConnectors.add(nodeConnectorPath);
673         } finally {
674             nodeToNodeConnectorsLock.unlock();
675         }
676     }
677
678     private def removeNodeConnectors(InstanceIdentifier<? extends Object> nodeIdentifier){
679         val nodePath = nodeIdentifier.path.get(1);
680
681         nodeToNodeConnectorsMap.remove(nodePath);
682     }
683 }