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