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