Merge "BUG-625: migrate InventoryAndReadAdapter"
[controller.git] / opendaylight / md-sal / compatibility / sal-compatibility / src / main / java / org / opendaylight / controller / sal / compatibility / InventoryAndReadAdapter.java
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.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import java.util.concurrent.CopyOnWriteArrayList;
19
20 import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
21 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
22 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
23 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
24 import org.opendaylight.controller.sal.core.ConstructionException;
25 import org.opendaylight.controller.sal.core.Edge;
26 import org.opendaylight.controller.sal.core.Node;
27 import org.opendaylight.controller.sal.core.NodeConnector;
28 import org.opendaylight.controller.sal.core.NodeTable;
29 import org.opendaylight.controller.sal.core.Property;
30 import org.opendaylight.controller.sal.core.UpdateType;
31 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
32 import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
33 import org.opendaylight.controller.sal.reader.FlowOnNode;
34 import org.opendaylight.controller.sal.reader.IPluginInReadService;
35 import org.opendaylight.controller.sal.reader.IPluginOutReadService;
36 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
37 import org.opendaylight.controller.sal.reader.NodeDescription;
38 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetAllFlowsStatisticsFromAllFlowTablesInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.GetFlowStatisticsFromFlowTableInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatistics;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.Link;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.Bytes;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.node.connector.statistics.Packets;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatistics;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetNodeConnectorStatisticsInputBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
84 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
85 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 public class InventoryAndReadAdapter implements IPluginInReadService, IPluginInInventoryService, OpendaylightInventoryListener, OpendaylightFlowStatisticsListener, OpendaylightFlowTableStatisticsListener, OpendaylightPortStatisticsListener {
90     private static final Logger LOG = LoggerFactory.getLogger(InventoryAndReadAdapter.class);
91     private static final short OPENFLOWV10_TABLE_ID = 0;
92
93     private final InventoryNotificationProvider inventoryNotificationProvider = new InventoryNotificationProvider();
94     private final Map<PathArgument,List<PathArgument>> nodeToNodeConnectorsMap = new ConcurrentHashMap<>();
95     private List<IPluginOutInventoryService> inventoryPublisher = new CopyOnWriteArrayList<>();
96     private List<IPluginOutReadService> statisticsPublisher = new CopyOnWriteArrayList<>();
97
98     private OpendaylightFlowTableStatisticsService flowTableStatisticsService;
99     private OpendaylightPortStatisticsService nodeConnectorStatisticsService;
100     private OpendaylightFlowStatisticsService flowStatisticsService;
101     private FlowTopologyDiscoveryService topologyDiscovery;
102     private DataProviderService dataProviderService;
103     private DataBrokerService dataService;
104
105     public DataBrokerService getDataService() {
106         return dataService;
107     }
108
109     public void setDataService(final DataBrokerService dataService) {
110         this.dataService = dataService;
111     }
112
113     public DataProviderService getDataProviderService() {
114         return dataProviderService;
115     }
116
117     public void setDataProviderService(final DataProviderService dataProviderService) {
118         this.dataProviderService = dataProviderService;
119     }
120
121     public OpendaylightFlowStatisticsService getFlowStatisticsService() {
122         return flowStatisticsService;
123     }
124
125     public void setFlowStatisticsService(final OpendaylightFlowStatisticsService flowStatisticsService) {
126         this.flowStatisticsService = flowStatisticsService;
127     }
128
129     public OpendaylightPortStatisticsService getNodeConnectorStatisticsService() {
130         return nodeConnectorStatisticsService;
131     }
132
133     public void setNodeConnectorStatisticsService(final OpendaylightPortStatisticsService nodeConnectorStatisticsService) {
134         this.nodeConnectorStatisticsService = nodeConnectorStatisticsService;
135     }
136
137     public OpendaylightFlowTableStatisticsService getFlowTableStatisticsService() {
138         return flowTableStatisticsService;
139     }
140
141     public void setFlowTableStatisticsService(final OpendaylightFlowTableStatisticsService flowTableStatisticsService) {
142         this.flowTableStatisticsService = flowTableStatisticsService;
143     }
144
145     public FlowTopologyDiscoveryService getTopologyDiscovery() {
146         return topologyDiscovery;
147     }
148
149     public void setTopologyDiscovery(final FlowTopologyDiscoveryService topologyDiscovery) {
150         this.topologyDiscovery = topologyDiscovery;
151     }
152
153     public List<IPluginOutReadService> getStatisticsPublisher() {
154         return statisticsPublisher;
155     }
156
157     public void setStatisticsPublisher(final List<IPluginOutReadService> statisticsPublisher) {
158         this.statisticsPublisher = statisticsPublisher;
159     }
160
161     public List<IPluginOutInventoryService> getInventoryPublisher() {
162         return inventoryPublisher;
163     }
164
165     public void setInventoryPublisher(final List<IPluginOutInventoryService> inventoryPublisher) {
166         this.inventoryPublisher = inventoryPublisher;
167     }
168
169     public void startAdapter() {
170         inventoryNotificationProvider.setDataProviderService(getDataProviderService());
171         inventoryNotificationProvider.setInventoryPublisher(getInventoryPublisher());
172         // inventoryNotificationProvider.start();
173     }
174
175     public boolean setInventoryPublisher(final IPluginOutInventoryService listener) {
176         return getInventoryPublisher().add(listener);
177     }
178
179     public boolean unsetInventoryPublisher(final IPluginOutInventoryService listener) {
180         return getInventoryPublisher().remove(listener);
181     }
182
183     public boolean setReadPublisher(final IPluginOutReadService listener) {
184         return getStatisticsPublisher().add(listener);
185     }
186
187     public Boolean unsetReadPublisher(final IPluginOutReadService listener) {
188         if (listener != null) {
189             return getStatisticsPublisher().remove(listener);
190         }
191         return false;
192     }
193
194     protected DataModificationTransaction startChange() {
195         return getDataProviderService().beginTransaction();
196     }
197
198     @Override
199     public long getTransmitRate(final NodeConnector connector) {
200         final FlowCapableNodeConnector nodeConnector = this.readOperFlowCapableNodeConnector(NodeMapping.toNodeConnectorRef(connector));
201         return nodeConnector.getCurrentSpeed().longValue();
202     }
203
204     private FlowCapableNode readOperFlowCapableNode(final NodeRef ref) {
205         final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node =
206                 (org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node)getDataService().readOperationalData(ref.getValue());
207         if (node == null) {
208             return null;
209         }
210
211         return node.getAugmentation(FlowCapableNode.class);
212     }
213
214     private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node readConfigNode(final Node node) {
215         final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeRef =
216                 InstanceIdentifier.builder(Nodes.class)
217                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, InventoryMapping.toNodeKey(node))
218                 .build();
219
220         return (org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node) startChange().readConfigurationData(nodeRef);
221     }
222
223     private org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector readConfigNodeConnector(final NodeConnector connector) {
224         final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector> nodeConnectorRef =
225                 InstanceIdentifier.builder(Nodes.class)
226                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, InventoryMapping.toNodeKey(connector.getNode()))
227                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class, InventoryMapping.toNodeConnectorKey(connector))
228                 .toInstance();
229
230         return((org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector) startChange().readConfigurationData(nodeConnectorRef));
231     }
232
233     /**
234      * Read a table of a node from configuration data store.
235      *
236      * @param node Node id
237      * @param id Table id
238      * @return Table contents, or null if not present
239      */
240     private Table readConfigTable(final Node node, final short id) {
241         final InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class)
242                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, InventoryMapping.toNodeKey(node))
243                 .augmentation(FlowCapableNode.class)
244                 .child(Table.class, new TableKey(id))
245                 .build();
246
247         return (Table) startChange().readConfigurationData(tableRef);
248     }
249
250     @Override
251     public List<FlowOnNode> readAllFlow(final Node node, final boolean cached) {
252         final ArrayList<FlowOnNode> output = new ArrayList<>();
253         final Table table = readConfigTable(node, OPENFLOWV10_TABLE_ID);
254         if (table != null) {
255             final List<Flow> flows = table.getFlow();
256             LOG.trace("Number of flows installed in table 0 of node {} : {}", node, flows.size());
257
258             for (final Flow flow : flows) {
259                 final FlowStatisticsData statsFromDataStore = flow.getAugmentation(FlowStatisticsData.class);
260                 if (statsFromDataStore != null) {
261                     final FlowOnNode it = new FlowOnNode(ToSalConversionsUtils.toFlow(flow, node));
262                     output.add(addFlowStats(it, statsFromDataStore.getFlowStatistics()));
263                 }
264             }
265         }
266
267         // TODO (main): Shall we send request to the switch? It will make async request to the switch.
268         // Once the plugin receives a response, it will let the adaptor know through onFlowStatisticsUpdate()
269         // If we assume that md-sal statistics manager will always be running, then it is not required
270         // But if not, then sending request will collect the latest data for adaptor at least.
271         getFlowStatisticsService().getAllFlowsStatisticsFromAllFlowTables(
272                 new GetAllFlowsStatisticsFromAllFlowTablesInputBuilder().setNode(NodeMapping.toNodeRef(node)).build());
273         return output;
274     }
275
276     @Override
277     public List<NodeConnectorStatistics> readAllNodeConnector(final Node node, final boolean cached) {
278         final ArrayList<NodeConnectorStatistics> ret = new ArrayList<>();
279
280         final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node dsNode = readConfigNode(node);
281         if (dsNode != null) {
282             for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector dsNodeConnector : dsNode.getNodeConnector()) {
283                 final FlowCapableNodeConnectorStatistics stats = (dsNodeConnector.getAugmentation(FlowCapableNodeConnectorStatisticsData.class));
284                 if (stats != null) {
285                     try {
286                         ret.add(toNodeConnectorStatistics(stats.getFlowCapableNodeConnectorStatistics(), dsNode.getId(), dsNodeConnector.getId()));
287                     } catch (ConstructionException e) {
288                         LOG.warn("Failed to instantiate node connector statistics for node {} connector {}, ignoring it",
289                                 dsNode.getId(), dsNodeConnector.getId(), e);
290                     }
291                 }
292             }
293         }
294
295         //TODO: Refer TODO (main)
296         getNodeConnectorStatisticsService().getAllNodeConnectorsStatistics(
297                 new GetAllNodeConnectorsStatisticsInputBuilder().setNode(NodeMapping.toNodeRef(node)).build());
298         return ret;
299     }
300
301     @Override
302     public List<NodeTableStatistics> readAllNodeTable(final Node node, final boolean cached) {
303         final NodeRef nodeRef = NodeMapping.toNodeRef(node);
304
305         final ArrayList<NodeTableStatistics> ret = new ArrayList<>();
306         final FlowCapableNode dsFlowCapableNode = this.readOperFlowCapableNode(nodeRef);
307         if (dsFlowCapableNode != null) {
308             for (final Table table : dsFlowCapableNode.getTable()) {
309                 final FlowTableStatisticsData tableStats = table.getAugmentation(FlowTableStatisticsData.class);
310                 if (tableStats != null) {
311                     try {
312                         ret.add(toNodeTableStatistics(tableStats.getFlowTableStatistics(), table.getId(), node));
313                     } catch (ConstructionException e) {
314                         LOG.warn("Failed to instantiate table statistics for node {} table {}, ignoring it", node, table.getId(), e);
315                     }
316                 }
317             }
318         }
319
320         //TODO: Refer TODO (main)
321         getFlowTableStatisticsService().getFlowTablesStatistics(new GetFlowTablesStatisticsInputBuilder().setNode(nodeRef).build());
322         return ret;
323     }
324
325     @Override
326     public NodeDescription readDescription(final Node node, final boolean cached) {
327         return this.toNodeDescription(NodeMapping.toNodeRef(node));
328     }
329
330     @Override
331     public FlowOnNode readFlow(final Node node, final org.opendaylight.controller.sal.flowprogrammer.Flow targetFlow, final boolean cached) {
332         FlowOnNode ret = null;
333         final Table table = readConfigTable(node, OPENFLOWV10_TABLE_ID);
334         if (table != null) {
335             final List<Flow> flows = table.getFlow();
336             InventoryAndReadAdapter.LOG.trace("Number of flows installed in table 0 of node {} : {}", node, flows.size());
337
338             for (final Flow mdsalFlow : flows) {
339                 if(FromSalConversionsUtils.flowEquals(mdsalFlow, MDFlowMapping.toMDSalflow(targetFlow))) {
340                     final FlowStatisticsData statsFromDataStore = mdsalFlow.getAugmentation(FlowStatisticsData.class);
341                     if (statsFromDataStore != null) {
342                         InventoryAndReadAdapter.LOG.debug("Found matching flow in the data store flow table ");
343                         ret = addFlowStats(new FlowOnNode(targetFlow), statsFromDataStore.getFlowStatistics());
344
345                         // FIXME: break; ?
346                     }
347                 }
348             }
349         }
350
351         //TODO: Refer TODO (main)
352         final GetFlowStatisticsFromFlowTableInputBuilder input = new GetFlowStatisticsFromFlowTableInputBuilder().setNode(NodeMapping.toNodeRef(node));
353         input.fieldsFrom(MDFlowMapping.toMDSalflow(targetFlow));
354         getFlowStatisticsService().getFlowStatisticsFromFlowTable(input.build());
355         return ret;
356     }
357
358     @Override
359     public NodeConnectorStatistics readNodeConnector(final NodeConnector connector, final boolean cached) {
360         final NodeConnectorId ncId = InventoryMapping.toNodeConnectorKey(connector).getId();
361
362         NodeConnectorStatistics ret = null;
363         final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nodeConnectorFromDS = readConfigNodeConnector(connector);
364         if (nodeConnectorFromDS != null) {
365             final FlowCapableNodeConnectorStatistics stats = nodeConnectorFromDS.getAugmentation(FlowCapableNodeConnectorStatisticsData.class);
366             if (stats != null) {
367                 try {
368                     ret = toNodeConnectorStatistics(stats.getFlowCapableNodeConnectorStatistics(),
369                             InventoryMapping.toNodeKey(connector.getNode()).getId(), ncId);
370                 } catch (ConstructionException e) {
371                     LOG.warn("Failed to instantiate node connector statistics for connector {}, ignoring it",
372                             connector, e);
373                 }
374             }
375         }
376
377         getNodeConnectorStatisticsService().getNodeConnectorStatistics(
378                 new GetNodeConnectorStatisticsInputBuilder().setNode(NodeMapping.toNodeRef(connector.getNode())).setNodeConnectorId(ncId).build());
379         return ret;
380     }
381
382     @Override
383     public NodeTableStatistics readNodeTable(final NodeTable nodeTable, final boolean cached) {
384         NodeTableStatistics nodeStats = null;
385         final Table table = readConfigTable(nodeTable.getNode(), (short) nodeTable.getID());
386         if (table != null) {
387             final FlowTableStatisticsData tableStats = table.getAugmentation(FlowTableStatisticsData.class);
388             if (tableStats != null) {
389                 try {
390                     nodeStats = toNodeTableStatistics(tableStats.getFlowTableStatistics(), table.getId(), nodeTable.getNode());
391                 } catch (ConstructionException e) {
392                     LOG.warn("Failed to instantiate table statistics for node {} table {}, ignoring it",
393                             nodeTable.getNode(), table.getId(), e);
394                 }
395             }
396         }
397
398         //TODO: Refer TODO (main)
399         getFlowTableStatisticsService().getFlowTablesStatistics(
400                 new GetFlowTablesStatisticsInputBuilder().setNode(NodeMapping.toNodeRef(nodeTable.getNode())).build());
401         return nodeStats;
402     }
403
404     @Override
405     public void onNodeConnectorRemoved(final NodeConnectorRemoved update) {
406         // Never received
407     }
408
409     @Override
410     public void onNodeRemoved(final NodeRemoved notification) {
411         this.removeNodeConnectors(notification.getNodeRef().getValue());
412         try {
413             final Node aDNode = NodeMapping.toADNode(notification.getNodeRef());
414             this.publishNodeUpdate(aDNode, UpdateType.REMOVED, Collections.<Property>emptySet());
415         } catch (ConstructionException e) {
416             LOG.warn("Failed to construct node for {}, not propagating update", notification.getNodeRef(), e);
417         }
418     }
419
420     @Override
421     public void onNodeConnectorUpdated(final NodeConnectorUpdated update) {
422         final NodeConnectorRef ref = update.getNodeConnectorRef();
423         final UpdateType updateType;
424         if (!this.isKnownNodeConnector(ref.getValue())) {
425             this.recordNodeConnector(ref.getValue());
426             updateType = UpdateType.ADDED;
427         } else {
428             updateType = UpdateType.CHANGED;
429         }
430
431         try {
432             final NodeConnector nodeConnector;
433             nodeConnector = NodeMapping.toADNodeConnector(ref);
434             this.publishNodeConnectorUpdate(nodeConnector, updateType, NodeMapping.toADNodeConnectorProperties(update));
435         } catch (ConstructionException e) {
436             LOG.warn("Failed to construct node connector for {}, not reporting the update", ref, e);
437         }
438     }
439
440     @Override
441     public void onNodeUpdated(final NodeUpdated notification) {
442         final NodeRef ref = notification.getNodeRef();
443
444         final UpdateType updateType;
445         if (dataService.readOperationalData(ref.getValue()) == null) {
446             updateType = UpdateType.ADDED;
447         } else {
448             updateType = UpdateType.CHANGED;
449         }
450
451         final Node aDNode;
452         try {
453             aDNode = NodeMapping.toADNode(ref);
454         } catch (ConstructionException e) {
455             LOG.warn("Failed to construct node for {}, not reporting the update", ref, e);
456             return;
457         }
458
459         this.publishNodeUpdate(aDNode, updateType, NodeMapping.toADNodeProperties(notification));
460         for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) {
461             final NodeDescription description = this.toNodeDescription(ref);
462             if (description != null) {
463                 final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeRef =
464                         InstanceIdentifier.builder(Nodes.class)
465                         .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId()))
466                         .toInstance();
467                 try {
468                     statsPublisher.descriptionStatisticsUpdated(NodeMapping.toADNode(nodeRef), description);
469                 } catch (ConstructionException e) {
470                     LOG.warn("Failed to construct node for {}, not reporting the update to publisher {}", nodeRef, statsPublisher, e);
471                 }
472             }
473         }
474     }
475
476     @Override
477     public ConcurrentMap<Node,Map<String,Property>> getNodeProps() {
478         final ConcurrentHashMap<Node,Map<String,Property>> props = new ConcurrentHashMap<>();
479         final Nodes nodes = this.readOperAllMDNodes();
480         for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node : nodes.getNode()) {
481             final FlowCapableNode fcn = node.getAugmentation(FlowCapableNode.class);
482             if (fcn != null) {
483                 final ConcurrentHashMap<String,Property> perNodePropMap = new ConcurrentHashMap<String, Property>();
484                 final HashSet<Property> perNodeProps = NodeMapping.toADNodeProperties(fcn, node.getId());
485                 if (perNodeProps != null) {
486                     for (final Property perNodeProp : perNodeProps) {
487                         perNodePropMap.put(perNodeProp.getName(), perNodeProp);
488                     }
489                 }
490
491                 try {
492                     final Node adNode = new Node(NodeMapping.MD_SAL_TYPE, NodeMapping.toADNodeId(node.getId()));
493                     props.put(adNode, perNodePropMap);
494                 } catch (ConstructionException e) {
495                     LOG.warn("Failed to construct node for {}, skipping it", node, e);
496                 }
497             }
498         }
499         return props;
500     }
501
502     private Nodes readOperAllMDNodes() {
503         final TypeSafeDataReader reader = TypeSafeDataReader.forReader(getDataService());
504         return reader.readOperationalData(InstanceIdentifier.builder(Nodes.class).build());
505     }
506
507     @Override
508     public ConcurrentMap<NodeConnector,Map<String,Property>> getNodeConnectorProps(final Boolean refresh) {
509         final ConcurrentHashMap<NodeConnector,Map<String,Property>> props = new ConcurrentHashMap<>();
510         for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node node : this.readOperAllMDNodes().getNode()) {
511             for (final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc : node.getNodeConnector()) {
512                 final FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class);
513                 if (fcnc != null) {
514                     final ConcurrentHashMap<String,Property> ncpsm = new ConcurrentHashMap<>();
515                     final HashSet<Property> ncps = NodeMapping.toADNodeConnectorProperties(fcnc);
516                     if (ncps != null) {
517                         for (final Property p : ncps) {
518                             ncpsm.put(p.getName(), p);
519                         }
520                     }
521
522                     try {
523                         props.put(NodeMapping.toADNodeConnector(nc.getId(), node.getId()), ncpsm);
524                     } catch (ConstructionException e) {
525                         LOG.warn("Failed to instantiate node {} connector {}, not reporting it", node.getId(), nc.getId(), e);
526                     }
527                 }
528             }
529         }
530         return props;
531     }
532
533     private FlowCapableNodeConnector readOperFlowCapableNodeConnector(final NodeConnectorRef ref) {
534         final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector nc =
535                 (org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector)
536                 getDataService().readOperationalData(ref.getValue());
537         return nc.getAugmentation(FlowCapableNodeConnector.class);
538     }
539
540     private static NodeConnectorStatistics toNodeConnectorStatistics(final org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.NodeConnectorStatistics nodeConnectorStatistics, final NodeId nodeId, final NodeConnectorId nodeConnectorId) throws ConstructionException {
541         final NodeConnectorStatistics it = new NodeConnectorStatistics();
542
543         final Packets packets = nodeConnectorStatistics.getPackets();
544         it.setReceivePacketCount(packets.getReceived().longValue());
545         it.setTransmitPacketCount(packets.getTransmitted().longValue());
546
547         final Bytes bytes = nodeConnectorStatistics.getBytes();
548         it.setReceiveByteCount(bytes.getReceived().longValue());
549         it.setTransmitByteCount(bytes.getTransmitted().longValue());
550
551         it.setReceiveDropCount(nodeConnectorStatistics.getReceiveDrops().longValue());
552         it.setTransmitDropCount(nodeConnectorStatistics.getTransmitDrops().longValue());
553         it.setReceiveErrorCount(nodeConnectorStatistics.getReceiveErrors().longValue());
554         it.setTransmitErrorCount(nodeConnectorStatistics.getTransmitErrors().longValue());
555         it.setReceiveFrameErrorCount(nodeConnectorStatistics.getReceiveFrameError().longValue());
556         it.setReceiveOverRunErrorCount(nodeConnectorStatistics.getReceiveOverRunError().longValue());
557         it.setReceiveCRCErrorCount(nodeConnectorStatistics.getReceiveCrcError().longValue());
558         it.setCollisionCount(nodeConnectorStatistics.getCollisionCount().longValue());
559
560         final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector> nodeConnectorRef =
561                 InstanceIdentifier.builder(Nodes.class)
562                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(nodeId))
563                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector.class, new NodeConnectorKey(nodeConnectorId))
564                 .build();
565         it.setNodeConnector(NodeMapping.toADNodeConnector(new NodeConnectorRef(nodeConnectorRef)));
566         return it;
567     }
568
569     private static NodeTableStatistics toNodeTableStatistics(final FlowTableStatistics tableStats, final Short tableId, final Node node) throws ConstructionException {
570         final NodeTableStatistics it = new NodeTableStatistics();
571         it.setActiveCount(tableStats.getActiveFlows().getValue().intValue());
572         it.setLookupCount(tableStats.getPacketsLookedUp().getValue().longValue());
573         it.setMatchedCount(tableStats.getPacketsMatched().getValue().longValue());
574         it.setName(tableId.toString());
575         it.setNodeTable(new NodeTable(NodeMapping.MD_SAL_TYPE, tableId, node));
576         return it;
577     }
578
579     private NodeDescription toNodeDescription(final NodeRef nodeRef) {
580         final FlowCapableNode capableNode = this.readOperFlowCapableNode(nodeRef);
581         if (capableNode == null) {
582             return null;
583         }
584
585         final NodeDescription it = new NodeDescription();
586         it.setManufacturer(capableNode.getManufacturer());
587         it.setSerialNumber(capableNode.getSerialNumber());
588         it.setSoftware(capableNode.getSoftware());
589         it.setDescription(capableNode.getDescription());
590         return it;
591     }
592
593     public Edge toADEdge(final Link link) throws ConstructionException {
594         NodeConnectorRef _source = link.getSource();
595         NodeConnector _aDNodeConnector = NodeMapping.toADNodeConnector(_source);
596         NodeConnectorRef _destination = link.getDestination();
597         NodeConnector _aDNodeConnector_1 = NodeMapping.toADNodeConnector(_destination);
598         Edge _edge = new Edge(_aDNodeConnector, _aDNodeConnector_1);
599         return _edge;
600     }
601
602     /**
603      * OpendaylightFlowStatisticsListener interface implementation
604      */
605     @Override
606     public void onAggregateFlowStatisticsUpdate(final AggregateFlowStatisticsUpdate notification) {
607         // Ignoring this notification as there does not seem to be a way to bubble this up to AD-SAL
608     }
609
610     @Override
611     public void onFlowsStatisticsUpdate(final FlowsStatisticsUpdate notification) {
612         final ArrayList<FlowOnNode> adsalFlowsStatistics = new ArrayList<>();
613         final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeRef =
614                 InstanceIdentifier.builder(Nodes.class)
615                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId()))
616                 .build();
617
618         final Node aDNode;
619         try {
620             aDNode = NodeMapping.toADNode(nodeRef);
621         } catch (ConstructionException e) {
622             LOG.warn("Failed to construct node for {}, ignoring it", notification.getId(), e);
623             return;
624         }
625
626         for (final FlowAndStatisticsMapList flowStats : notification.getFlowAndStatisticsMapList()) {
627             if (flowStats.getTableId() == 0) {
628                 adsalFlowsStatistics.add(InventoryAndReadAdapter.toFlowOnNode(flowStats, aDNode));
629             }
630         }
631         for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) {
632             statsPublisher.nodeFlowStatisticsUpdated(aDNode, adsalFlowsStatistics);
633         }
634     }
635
636     /**
637      * OpendaylightFlowTableStatisticsListener interface implementation
638      */
639     @Override
640     public void onFlowTableStatisticsUpdate(final FlowTableStatisticsUpdate notification) {
641         ArrayList<NodeTableStatistics> adsalFlowTableStatistics = new ArrayList<>();
642         for (final FlowTableAndStatisticsMap stats : notification.getFlowTableAndStatisticsMap()) {
643             if (stats.getTableId().getValue() == 0) {
644                 final NodeTableStatistics it = new NodeTableStatistics();
645                 it.setActiveCount(stats.getActiveFlows().getValue().intValue());
646                 it.setLookupCount(stats.getPacketsLookedUp().getValue().longValue());
647                 it.setMatchedCount(stats.getPacketsMatched().getValue().longValue());
648                 adsalFlowTableStatistics.add(it);
649             }
650         }
651
652         final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeRef =
653                 InstanceIdentifier.builder(Nodes.class)
654                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId()))
655                 .build();
656
657         final Node aDNode;
658         try {
659             aDNode = NodeMapping.toADNode(nodeRef);
660         } catch (ConstructionException e) {
661             LOG.warn("Failed to construct node for {}, ignoring it", notification.getId(), e);
662             return;
663         }
664
665         for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) {
666             statsPublisher.nodeTableStatisticsUpdated(aDNode, adsalFlowTableStatistics);
667         }
668     }
669
670     /**
671      * OpendaylightPortStatisticsUpdate interface implementation
672      */
673     @Override
674     public void onNodeConnectorStatisticsUpdate(final NodeConnectorStatisticsUpdate notification) {
675         final ArrayList<NodeConnectorStatistics> adsalPortStatistics = new ArrayList<NodeConnectorStatistics>();
676         for (final NodeConnectorStatisticsAndPortNumberMap nodeConnectorStatistics : notification.getNodeConnectorStatisticsAndPortNumberMap()) {
677             try {
678                 adsalPortStatistics.add(toNodeConnectorStatistics(
679                         nodeConnectorStatistics, notification.getId(), nodeConnectorStatistics.getNodeConnectorId()));
680             } catch (ConstructionException e) {
681                 LOG.warn("Failed to create statistics for node {} connector {}, not updating them",
682                         notification.getId(), nodeConnectorStatistics.getNodeConnectorId(), e);
683             }
684         }
685
686         final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeRef =
687                 InstanceIdentifier.builder(Nodes.class)
688                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class, new NodeKey(notification.getId()))
689                 .build();
690
691         final Node aDNode;
692         try {
693             aDNode = NodeMapping.toADNode(nodeRef);
694         } catch (ConstructionException e) {
695             LOG.warn("Failed to construct node for {}, ignoring it", notification.getId(), e);
696             return;
697         }
698
699         for (final IPluginOutReadService statsPublisher : getStatisticsPublisher()) {
700             statsPublisher.nodeConnectorStatisticsUpdated(aDNode, adsalPortStatistics);
701         }
702     }
703
704     private static FlowOnNode toFlowOnNode(final FlowAndStatisticsMapList flowAndStatsMap, final Node node) {
705         final FlowOnNode it = new FlowOnNode(ToSalConversionsUtils.toFlow(flowAndStatsMap, node));
706         return addFlowStats(it, flowAndStatsMap);
707     }
708
709     private static FlowOnNode addFlowStats(final FlowOnNode node, final GenericStatistics stats) {
710         node.setByteCount(stats.getByteCount().getValue().longValue());
711         node.setPacketCount(stats.getPacketCount().getValue().longValue());
712         node.setDurationSeconds(stats.getDuration().getSecond().getValue().intValue());
713         node.setDurationNanoseconds(stats.getDuration().getNanosecond().getValue().intValue());
714         return node;
715     }
716
717     @Override
718     public Set<Node> getConfiguredNotConnectedNodes() {
719         return Collections.emptySet();
720     }
721
722     private void publishNodeUpdate(final Node node, final UpdateType updateType, final Set<Property> properties) {
723         for (final IPluginOutInventoryService publisher : getInventoryPublisher()) {
724             publisher.updateNode(node, updateType, properties);
725         }
726     }
727
728     private void publishNodeConnectorUpdate(final NodeConnector nodeConnector, final UpdateType updateType, final Set<Property> properties) {
729         for (final IPluginOutInventoryService publisher : getInventoryPublisher()) {
730             publisher.updateNodeConnector(nodeConnector, updateType, properties);
731         }
732     }
733
734     private boolean isKnownNodeConnector(final InstanceIdentifier<? extends Object> nodeConnectorIdentifier) {
735         final List<PathArgument> path = nodeConnectorIdentifier.getPath();
736         if (path.size() >= 3) {
737             final PathArgument nodePath = path.get(1);
738             final PathArgument nodeConnectorPath = path.get(2);
739             final List<PathArgument> nodeConnectors = nodeToNodeConnectorsMap.get(nodePath);
740             if (nodeConnectors != null) {
741                 return nodeConnectors.contains(nodeConnectorPath);
742             }
743         }
744         return false;
745     }
746
747     private boolean recordNodeConnector(final InstanceIdentifier<? extends Object> nodeConnectorIdentifier) {
748         final List<PathArgument> path = nodeConnectorIdentifier.getPath();
749         if (path.size() < 3) {
750             return false;
751         }
752
753         final PathArgument nodePath = path.get(1);
754         final PathArgument nodeConnectorPath = path.get(2);
755
756         synchronized (this) {
757             List<PathArgument> nodeConnectors = this.nodeToNodeConnectorsMap.get(nodePath);
758             if (nodeConnectors == null) {
759                 nodeConnectors = new ArrayList<>();
760                 this.nodeToNodeConnectorsMap.put(nodePath, nodeConnectors);
761             }
762
763             return nodeConnectors.add(nodeConnectorPath);
764         }
765     }
766
767     private List<PathArgument> removeNodeConnectors(final InstanceIdentifier<? extends Object> nodeIdentifier) {
768         return this.nodeToNodeConnectorsMap.remove(nodeIdentifier.getPath().get(1));
769     }
770 }