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