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