Merge "Fixed bug when converting augmentation in Instance Identifier"
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / StatisticsUpdateCommiter.java
1 /*
2  * Copyright IBM Corporation, 2013.  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.md.statistics.manager;
9
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.concurrent.ConcurrentMap;
13
14 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsData;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsDataBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.AggregateFlowStatisticsUpdate;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsData;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowStatisticsDataBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.FlowsStatisticsUpdate;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.OpendaylightFlowStatisticsListener;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.aggregate.flow.statistics.AggregateFlowStatisticsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.statistics.FlowTableStatisticsBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.Queue;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.queues.QueueKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.queue.rev130925.QueueId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatisticsBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
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.Node;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatisticsBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatch;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericQueueStatistics;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.flow.capable.node.connector.statistics.FlowCapableNodeConnectorStatisticsBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsData;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.FlowCapableNodeConnectorQueueStatisticsDataBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.OpendaylightQueueStatisticsListener;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.QueueStatisticsUpdate;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.flow.capable.node.connector.queue.statistics.FlowCapableNodeConnectorQueueStatisticsBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.queue.statistics.rev131216.queue.id.and.statistics.map.QueueIdAndStatisticsMap;
109 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
110 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
111 import org.slf4j.Logger;
112 import org.slf4j.LoggerFactory;
113
114 /**
115  * Class implement statistics manager related listener interface and augment all the 
116  * received statistics data to data stores.
117  * TODO: Need to add error message listener and clean-up the associated tx id 
118  * if it exists in the tx-id cache.
119  * @author vishnoianil
120  *
121  */
122 public class StatisticsUpdateCommiter implements OpendaylightGroupStatisticsListener,
123         OpendaylightMeterStatisticsListener, 
124         OpendaylightFlowStatisticsListener,
125         OpendaylightPortStatisticsListener,
126         OpendaylightFlowTableStatisticsListener,
127         OpendaylightQueueStatisticsListener{
128     
129     public final static Logger sucLogger = LoggerFactory.getLogger(StatisticsUpdateCommiter.class);
130
131     private final StatisticsProvider statisticsManager;
132     
133     private final int unaccountedFlowsCounter = 1;
134
135     public StatisticsUpdateCommiter(final StatisticsProvider manager){
136
137         this.statisticsManager = manager;
138     }
139     
140     public StatisticsProvider getStatisticsManager(){
141         return statisticsManager;
142     }
143    
144     @Override
145     public void onMeterConfigStatsUpdated(MeterConfigStatsUpdated notification) {
146         //Check if response is for the request statistics-manager sent.
147         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
148             return;
149         
150         //Add statistics to local cache
151         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
152         if(!cache.containsKey(notification.getId())){
153             cache.put(notification.getId(), new NodeStatistics());
154         }
155         cache.get(notification.getId()).setMeterConfigStats(notification.getMeterConfigStats());
156         
157         //Publish data to configuration data store
158         NodeKey key = new NodeKey(notification.getId());
159         
160         List<MeterConfigStats> eterConfigStatsList = notification.getMeterConfigStats();
161         
162         for(MeterConfigStats meterConfigStats : eterConfigStatsList){
163             DataModificationTransaction it = this.statisticsManager.startChange();
164             MeterBuilder meterBuilder = new MeterBuilder();
165             MeterKey meterKey = new MeterKey(meterConfigStats.getMeterId());
166             meterBuilder.setKey(meterKey);
167             
168             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
169                                                                                         .augmentation(FlowCapableNode.class)
170                                                                                         .child(Meter.class,meterKey).toInstance();
171             
172             NodeMeterConfigStatsBuilder meterConfig= new NodeMeterConfigStatsBuilder();
173             MeterConfigStatsBuilder stats = new MeterConfigStatsBuilder();
174             stats.fieldsFrom(meterConfigStats);
175             meterConfig.setMeterConfigStats(stats.build());
176             
177             //Update augmented data
178             meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
179             it.putOperationalData(meterRef, meterBuilder.build());
180             it.commit();
181
182         }
183     }
184
185     @Override
186     public void onMeterStatisticsUpdated(MeterStatisticsUpdated notification) {
187         
188         //Check if response is for the request statistics-manager sent.
189         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
190             return;
191
192         //Add statistics to local cache
193         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
194         if(!cache.containsKey(notification.getId())){
195             cache.put(notification.getId(), new NodeStatistics());
196         }
197         cache.get(notification.getId()).setMeterStatistics(notification.getMeterStats());
198         
199         NodeKey key = new NodeKey(notification.getId());
200         
201         List<MeterStats> meterStatsList = notification.getMeterStats();
202         
203         for(MeterStats meterStats : meterStatsList){
204
205             //Publish data to configuration data store
206             DataModificationTransaction it = this.statisticsManager.startChange();
207             MeterBuilder meterBuilder = new MeterBuilder();
208             MeterKey meterKey = new MeterKey(meterStats.getMeterId());
209             meterBuilder.setKey(meterKey);
210             
211             InstanceIdentifier<Meter> meterRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
212                                                                                         .augmentation(FlowCapableNode.class)
213                                                                                         .child(Meter.class,meterKey).toInstance();
214             
215             NodeMeterStatisticsBuilder meterStatsBuilder= new NodeMeterStatisticsBuilder();
216             MeterStatisticsBuilder stats = new MeterStatisticsBuilder();
217             stats.fieldsFrom(meterStats);
218             meterStatsBuilder.setMeterStatistics(stats.build());
219
220             //Update augmented data
221             meterBuilder.addAugmentation(NodeMeterStatistics.class, meterStatsBuilder.build());
222             it.putOperationalData(meterRef, meterBuilder.build());
223             it.commit();
224         }
225     }
226
227     @Override
228     public void onGroupDescStatsUpdated(GroupDescStatsUpdated notification) {
229         
230         //Check if response is for the request statistics-manager sent.
231         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
232             return;
233
234         //Add statistics to local cache
235         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
236         if(!cache.containsKey(notification.getId())){
237             cache.put(notification.getId(), new NodeStatistics());
238         }
239         cache.get(notification.getId()).setGroupDescStats(notification.getGroupDescStats());
240         
241         //Publish data to configuration data store
242         NodeKey key = new NodeKey(notification.getId());
243         List<GroupDescStats> groupDescStatsList = notification.getGroupDescStats();
244
245         for(GroupDescStats groupDescStats : groupDescStatsList){
246             DataModificationTransaction it = this.statisticsManager.startChange();
247             
248             GroupBuilder groupBuilder = new GroupBuilder();
249             GroupKey groupKey = new GroupKey(groupDescStats.getGroupId());
250             groupBuilder.setKey(groupKey);
251             
252             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
253                                                                                         .augmentation(FlowCapableNode.class)
254                                                                                         .child(Group.class,groupKey).toInstance();
255
256             NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
257             GroupDescBuilder stats = new GroupDescBuilder();
258             stats.fieldsFrom(groupDescStats);
259             groupDesc.setGroupDesc(stats.build());
260             
261             //Update augmented data
262             groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
263
264             it.putOperationalData(groupRef, groupBuilder.build());
265             it.commit();
266         }
267     }
268
269     @Override
270     public void onGroupStatisticsUpdated(GroupStatisticsUpdated notification) {
271         
272         //Check if response is for the request statistics-manager sent.
273         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
274             return;
275
276         //Add statistics to local cache
277         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
278         if(!cache.containsKey(notification.getId())){
279             cache.put(notification.getId(), new NodeStatistics());
280         }
281         cache.get(notification.getId()).setGroupStatistics(notification.getGroupStats());
282         
283         //Publish data to configuration data store
284         NodeKey key = new NodeKey(notification.getId());
285         List<GroupStats> groupStatsList = notification.getGroupStats();
286
287         for(GroupStats groupStats : groupStatsList){
288             DataModificationTransaction it = this.statisticsManager.startChange();
289             
290             GroupBuilder groupBuilder = new GroupBuilder();
291             GroupKey groupKey = new GroupKey(groupStats.getGroupId());
292             groupBuilder.setKey(groupKey);
293             
294             InstanceIdentifier<Group> groupRef = InstanceIdentifier.builder(Nodes.class).child(Node.class,key)
295                                                                                         .augmentation(FlowCapableNode.class)
296                                                                                         .child(Group.class,groupKey).toInstance();
297
298             NodeGroupStatisticsBuilder groupStatisticsBuilder= new NodeGroupStatisticsBuilder();
299             GroupStatisticsBuilder stats = new GroupStatisticsBuilder();
300             stats.fieldsFrom(groupStats);
301             groupStatisticsBuilder.setGroupStatistics(stats.build());
302             
303             //Update augmented data
304             groupBuilder.addAugmentation(NodeGroupStatistics.class, groupStatisticsBuilder.build());
305             it.putOperationalData(groupRef, groupBuilder.build());
306             it.commit();
307         }
308     }
309     
310     @Override
311     public void onMeterFeaturesUpdated(MeterFeaturesUpdated notification) {
312
313         //Add statistics to local cache
314         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
315         if(!cache.containsKey(notification.getId())){
316             cache.put(notification.getId(), new NodeStatistics());
317         }
318         MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder();
319         meterFeature.setMeterBandSupported(notification.getMeterBandSupported());
320         meterFeature.setMeterCapabilitiesSupported(notification.getMeterCapabilitiesSupported());
321         meterFeature.setMaxBands(notification.getMaxBands());
322         meterFeature.setMaxColor(notification.getMaxColor());
323         meterFeature.setMaxMeter(notification.getMaxMeter());
324         
325         cache.get(notification.getId()).setMeterFeatures(meterFeature.build());
326         
327         //Publish data to configuration data store
328         DataModificationTransaction it = this.statisticsManager.startChange();
329         NodeKey key = new NodeKey(notification.getId());
330         NodeRef ref = getNodeRef(key);
331         
332         final NodeBuilder nodeData = new NodeBuilder(); 
333         nodeData.setKey(key);
334         
335         NodeMeterFeaturesBuilder nodeMeterFeatures= new NodeMeterFeaturesBuilder();
336         nodeMeterFeatures.setMeterFeatures(meterFeature.build());
337         
338         //Update augmented data
339         nodeData.addAugmentation(NodeMeterFeatures.class, nodeMeterFeatures.build());
340         
341         InstanceIdentifier<? extends Object> refValue = ref.getValue();
342         it.putOperationalData(refValue, nodeData.build());
343         it.commit();
344     }
345     
346     @Override
347     public void onGroupFeaturesUpdated(GroupFeaturesUpdated notification) {
348
349         //Add statistics to local cache
350         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
351         if(!cache.containsKey(notification.getId())){
352             cache.put(notification.getId(), new NodeStatistics());
353         }
354         
355         GroupFeaturesBuilder groupFeatures = new GroupFeaturesBuilder();
356         groupFeatures.setActions(notification.getActions());
357         groupFeatures.setGroupCapabilitiesSupported(notification.getGroupCapabilitiesSupported());
358         groupFeatures.setGroupTypesSupported(notification.getGroupTypesSupported());
359         groupFeatures.setMaxGroups(notification.getMaxGroups());
360         cache.get(notification.getId()).setGroupFeatures(groupFeatures.build());
361         
362         //Publish data to configuration data store
363         DataModificationTransaction it = this.statisticsManager.startChange();
364         NodeKey key = new NodeKey(notification.getId());
365         NodeRef ref = getNodeRef(key);
366         
367         final NodeBuilder nodeData = new NodeBuilder(); 
368         nodeData.setKey(key);
369         
370         NodeGroupFeaturesBuilder nodeGroupFeatures= new NodeGroupFeaturesBuilder();
371         nodeGroupFeatures.setGroupFeatures(groupFeatures.build());
372         
373         //Update augmented data
374         nodeData.addAugmentation(NodeGroupFeatures.class, nodeGroupFeatures.build());
375         
376         InstanceIdentifier<? extends Object> refValue = ref.getValue();
377         it.putOperationalData(refValue, nodeData.build());
378         it.commit();
379     }
380
381     @Override
382     public void onFlowsStatisticsUpdate(FlowsStatisticsUpdate notification) {
383         
384         //Check if response is for the request statistics-manager sent.
385         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
386             return;
387
388         NodeKey key = new NodeKey(notification.getId());
389         sucLogger.debug("Received flow stats update : {}",notification.toString());
390         
391         for(FlowAndStatisticsMapList map: notification.getFlowAndStatisticsMapList()){
392             short tableId = map.getTableId();
393             
394             DataModificationTransaction it = this.statisticsManager.startChange();
395
396             boolean foundOriginalFlow = false;
397
398             FlowBuilder flowBuilder = new FlowBuilder();
399
400             FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
401
402             FlowBuilder flow = new FlowBuilder();
403             flow.setContainerName(map.getContainerName());
404             flow.setBufferId(map.getBufferId());
405             flow.setCookie(map.getCookie());
406             flow.setCookieMask(map.getCookieMask());
407             flow.setFlags(map.getFlags());
408             flow.setFlowName(map.getFlowName());
409             flow.setHardTimeout(map.getHardTimeout());
410             if(map.getFlowId() != null)
411                 flow.setId(new FlowId(map.getFlowId().getValue()));
412             flow.setIdleTimeout(map.getIdleTimeout());
413             flow.setInstallHw(map.isInstallHw());
414             flow.setInstructions(map.getInstructions());
415             if(map.getFlowId()!= null)
416                 flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
417             flow.setMatch(map.getMatch());
418             flow.setOutGroup(map.getOutGroup());
419             flow.setOutPort(map.getOutPort());
420             flow.setPriority(map.getPriority());
421             flow.setStrict(map.isStrict());
422             flow.setTableId(tableId);
423                 
424             Flow flowRule = flow.build();
425                 
426             FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
427             stats.setByteCount(map.getByteCount());
428             stats.setPacketCount(map.getPacketCount());
429             stats.setDuration(map.getDuration());
430                 
431             GenericStatistics flowStats = stats.build();
432                 
433             //Add statistics to local cache
434             ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
435             if(!cache.containsKey(notification.getId())){
436                 cache.put(notification.getId(), new NodeStatistics());
437             }
438             if(!cache.get(notification.getId()).getFlowAndStatsMap().containsKey(tableId)){
439                 cache.get(notification.getId()).getFlowAndStatsMap().put(tableId, new HashMap<Flow,GenericStatistics>());
440             }
441             cache.get(notification.getId()).getFlowAndStatsMap().get(tableId).put(flowRule,flowStats);
442                 
443             //Augment the data to the flow node
444
445             FlowStatisticsBuilder flowStatistics = new FlowStatisticsBuilder();
446             flowStatistics.setByteCount(flowStats.getByteCount());
447             flowStatistics.setPacketCount(flowStats.getPacketCount());
448             flowStatistics.setDuration(flowStats.getDuration());
449             flowStatistics.setContainerName(map.getContainerName());
450             flowStatistics.setBufferId(map.getBufferId());
451             flowStatistics.setCookie(map.getCookie());
452             flowStatistics.setCookieMask(map.getCookieMask());
453             flowStatistics.setFlags(map.getFlags());
454             flowStatistics.setFlowName(map.getFlowName());
455             flowStatistics.setHardTimeout(map.getHardTimeout());
456             flowStatistics.setIdleTimeout(map.getIdleTimeout());
457             flowStatistics.setInstallHw(map.isInstallHw());
458             flowStatistics.setInstructions(map.getInstructions());
459             flowStatistics.setMatch(map.getMatch());
460             flowStatistics.setOutGroup(map.getOutGroup());
461             flowStatistics.setOutPort(map.getOutPort());
462             flowStatistics.setPriority(map.getPriority());
463             flowStatistics.setStrict(map.isStrict());
464             flowStatistics.setTableId(tableId);
465
466             flowStatisticsData.setFlowStatistics(flowStatistics.build());
467                 
468             sucLogger.debug("Flow : {}",flowRule.toString());
469             sucLogger.debug("Statistics to augment : {}",flowStatistics.build().toString());
470
471             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
472                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
473             
474             Table table= (Table)it.readConfigurationData(tableRef);
475
476             //TODO: Not a good way to do it, need to figure out better way.
477             //TODO: major issue in any alternate approach is that flow key is incrementally assigned 
478             //to the flows stored in data store.
479             if(table != null){
480
481                 for(Flow existingFlow : table.getFlow()){
482                     sucLogger.debug("Existing flow in data store : {}",existingFlow.toString());
483                     if(flowEquals(flowRule,existingFlow)){
484                         InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
485                                 .augmentation(FlowCapableNode.class)
486                                 .child(Table.class, new TableKey(tableId))
487                                 .child(Flow.class,existingFlow.getKey()).toInstance();
488                         flowBuilder.setKey(existingFlow.getKey());
489                         flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
490                         sucLogger.info("Found matching flow in the datastore, augmenting statistics");
491                         foundOriginalFlow = true;
492                         it.putOperationalData(flowRef, flowBuilder.build());
493                         it.commit();
494                         break;
495                     }
496                 }
497             }
498             
499             if(!foundOriginalFlow){
500                 sucLogger.debug("Associated original flow is not found in data store. Augmenting flow in operational data store");
501                 //TODO: Temporary fix: format [ 1+tableid+1+unaccounted flow counter]
502                 long flowKey = Long.parseLong(new String("1"+Short.toString(tableId)+"1"+Integer.toString(this.unaccountedFlowsCounter)));
503                 FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
504                 InstanceIdentifier<Flow> flowRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
505                         .augmentation(FlowCapableNode.class)
506                         .child(Table.class, new TableKey(tableId))
507                         .child(Flow.class,newFlowKey).toInstance();
508                 flowBuilder.setKey(newFlowKey);
509                 flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
510                 sucLogger.info("Flow was no present in data store, augmenting statistics as an unaccounted flow");
511                 it.putOperationalData(flowRef, flowBuilder.build());
512                 it.commit();
513             }
514         }
515     }
516
517     @Override
518     public void onAggregateFlowStatisticsUpdate(AggregateFlowStatisticsUpdate notification) {
519         //Check if response is for the request statistics-manager sent.
520         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
521             return;
522
523         NodeKey key = new NodeKey(notification.getId());
524         sucLogger.debug("Received aggregate flow statistics update : {}",notification.toString());
525         
526         Short tableId = this.statisticsManager.getMultipartMessageManager().getTableIdForTxId(notification.getTransactionId());
527         if(tableId != null){
528             
529             DataModificationTransaction it = this.statisticsManager.startChange();
530
531             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
532                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
533
534             AggregateFlowStatisticsDataBuilder aggregateFlowStatisticsDataBuilder = new AggregateFlowStatisticsDataBuilder();
535             AggregateFlowStatisticsBuilder aggregateFlowStatisticsBuilder = new AggregateFlowStatisticsBuilder();
536             aggregateFlowStatisticsBuilder.setByteCount(notification.getByteCount());
537             aggregateFlowStatisticsBuilder.setFlowCount(notification.getFlowCount());
538             aggregateFlowStatisticsBuilder.setPacketCount(notification.getPacketCount());
539             aggregateFlowStatisticsDataBuilder.setAggregateFlowStatistics(aggregateFlowStatisticsBuilder.build());
540             
541             ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
542             if(!cache.containsKey(notification.getId())){
543                 cache.put(notification.getId(), new NodeStatistics());
544             }
545             cache.get(notification.getId()).getTableAndAggregateFlowStatsMap().put(tableId,aggregateFlowStatisticsBuilder.build());
546             
547             sucLogger.debug("Augment aggregate statistics: {} for table {} on Node {}",aggregateFlowStatisticsBuilder.build().toString(),tableId,key);
548
549             TableBuilder tableBuilder = new TableBuilder();
550             tableBuilder.setKey(new TableKey(tableId));
551             tableBuilder.addAugmentation(AggregateFlowStatisticsData.class, aggregateFlowStatisticsDataBuilder.build());
552             it.putOperationalData(tableRef, tableBuilder.build());
553             it.commit();
554
555         }
556     }
557
558     @Override
559     public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate notification) {
560         //Check if response is for the request statistics-manager sent.
561         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
562             return;
563
564         NodeKey key = new NodeKey(notification.getId());
565         sucLogger.debug("Received port stats update : {}",notification.toString());
566         
567         //Add statistics to local cache
568         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
569         if(!cache.containsKey(notification.getId())){
570             cache.put(notification.getId(), new NodeStatistics());
571         }
572
573
574         List<NodeConnectorStatisticsAndPortNumberMap> portsStats = notification.getNodeConnectorStatisticsAndPortNumberMap();
575         for(NodeConnectorStatisticsAndPortNumberMap portStats : portsStats){
576             
577             DataModificationTransaction it = this.statisticsManager.startChange();
578
579             FlowCapableNodeConnectorStatisticsBuilder statisticsBuilder 
580                                             = new FlowCapableNodeConnectorStatisticsBuilder();
581             statisticsBuilder.setBytes(portStats.getBytes());
582             statisticsBuilder.setCollisionCount(portStats.getCollisionCount());
583             statisticsBuilder.setDuration(portStats.getDuration());
584             statisticsBuilder.setPackets(portStats.getPackets());
585             statisticsBuilder.setReceiveCrcError(portStats.getReceiveCrcError());
586             statisticsBuilder.setReceiveDrops(portStats.getReceiveDrops());
587             statisticsBuilder.setReceiveErrors(portStats.getReceiveErrors());
588             statisticsBuilder.setReceiveFrameError(portStats.getReceiveFrameError());
589             statisticsBuilder.setReceiveOverRunError(portStats.getReceiveOverRunError());
590             statisticsBuilder.setTransmitDrops(portStats.getTransmitDrops());
591             statisticsBuilder.setTransmitErrors(portStats.getTransmitErrors());
592             
593             //Update data in the cache
594             cache.get(notification.getId()).getNodeConnectorStats().put(portStats.getNodeConnectorId(), statisticsBuilder.build());
595             
596             //Augment data to the node-connector
597             FlowCapableNodeConnectorStatisticsDataBuilder statisticsDataBuilder = 
598                     new FlowCapableNodeConnectorStatisticsDataBuilder();
599             
600             statisticsDataBuilder.setFlowCapableNodeConnectorStatistics(statisticsBuilder.build());
601             
602             InstanceIdentifier<NodeConnector> nodeConnectorRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).child(NodeConnector.class, new NodeConnectorKey(portStats.getNodeConnectorId())).toInstance();
603             
604             NodeConnector nodeConnector = (NodeConnector)it.readOperationalData(nodeConnectorRef);
605             
606             if(nodeConnector != null){
607                 sucLogger.debug("Augmenting port statistics {} to port {}",statisticsDataBuilder.build().toString(),nodeConnectorRef.toString());
608                 NodeConnectorBuilder nodeConnectorBuilder = new NodeConnectorBuilder();
609                 nodeConnectorBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class, statisticsDataBuilder.build());
610                 it.putOperationalData(nodeConnectorRef, nodeConnectorBuilder.build());
611                 it.commit();
612             }
613         }
614     }
615
616     @Override
617     public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate notification) {
618         //Check if response is for the request statistics-manager sent.
619         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
620             return;
621
622         NodeKey key = new NodeKey(notification.getId());
623         sucLogger.debug("Received flow table statistics update : {}",notification.toString());
624         
625         List<FlowTableAndStatisticsMap> flowTablesStatsList = notification.getFlowTableAndStatisticsMap();
626         for (FlowTableAndStatisticsMap ftStats : flowTablesStatsList){
627             
628             DataModificationTransaction it = this.statisticsManager.startChange();
629
630             InstanceIdentifier<Table> tableRef = InstanceIdentifier.builder(Nodes.class).child(Node.class, key)
631                     .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(ftStats.getTableId().getValue())).toInstance();
632             
633             FlowTableStatisticsDataBuilder statisticsDataBuilder = new FlowTableStatisticsDataBuilder();
634             
635             FlowTableStatisticsBuilder statisticsBuilder = new FlowTableStatisticsBuilder();
636             statisticsBuilder.setActiveFlows(ftStats.getActiveFlows());
637             statisticsBuilder.setPacketsLookedUp(ftStats.getPacketsLookedUp());
638             statisticsBuilder.setPacketsMatched(ftStats.getPacketsMatched());
639             
640             statisticsDataBuilder.setFlowTableStatistics(statisticsBuilder.build());
641             
642             ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
643             if(!cache.containsKey(notification.getId())){
644                 cache.put(notification.getId(), new NodeStatistics());
645             }
646             cache.get(notification.getId()).getFlowTableAndStatisticsMap().put(ftStats.getTableId().getValue(),statisticsBuilder.build());
647             
648             sucLogger.debug("Augment flow table statistics: {} for table {} on Node {}",statisticsBuilder.build().toString(),ftStats.getTableId(),key);
649             
650             TableBuilder tableBuilder = new TableBuilder();
651             tableBuilder.setKey(new TableKey(ftStats.getTableId().getValue()));
652             tableBuilder.addAugmentation(FlowTableStatisticsData.class, statisticsDataBuilder.build());
653             it.putOperationalData(tableRef, tableBuilder.build());
654             it.commit();
655         }
656     }
657
658     @Override
659     public void onQueueStatisticsUpdate(QueueStatisticsUpdate notification) {
660         
661         //Check if response is for the request statistics-manager sent.
662         if(this.statisticsManager.getMultipartMessageManager().removeTxId(notification.getTransactionId()) == null)
663             return;
664
665         NodeKey key = new NodeKey(notification.getId());
666         sucLogger.debug("Received queue stats update : {}",notification.toString());
667         
668         //Add statistics to local cache
669         ConcurrentMap<NodeId, NodeStatistics> cache = this.statisticsManager.getStatisticsCache();
670         if(!cache.containsKey(notification.getId())){
671             cache.put(notification.getId(), new NodeStatistics());
672         }
673         
674         List<QueueIdAndStatisticsMap> queuesStats = notification.getQueueIdAndStatisticsMap();
675         for(QueueIdAndStatisticsMap swQueueStats : queuesStats){
676             
677             if(!cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().containsKey(swQueueStats.getNodeConnectorId())){
678                 cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap().put(swQueueStats.getNodeConnectorId(), new HashMap<QueueId,GenericQueueStatistics>());
679             }
680             
681             FlowCapableNodeConnectorQueueStatisticsDataBuilder queueStatisticsDataBuilder = new FlowCapableNodeConnectorQueueStatisticsDataBuilder();
682             
683             FlowCapableNodeConnectorQueueStatisticsBuilder queueStatisticsBuilder = new FlowCapableNodeConnectorQueueStatisticsBuilder();
684             
685             queueStatisticsBuilder.fieldsFrom(swQueueStats);
686             
687             queueStatisticsDataBuilder.setFlowCapableNodeConnectorQueueStatistics(queueStatisticsBuilder.build());
688             
689             cache.get(notification.getId()).getNodeConnectorAndQueuesStatsMap()
690                                             .get(swQueueStats.getNodeConnectorId())
691                                             .put(swQueueStats.getQueueId(), queueStatisticsBuilder.build());
692             
693             
694             DataModificationTransaction it = this.statisticsManager.startChange();
695
696             InstanceIdentifier<Queue> queueRef 
697                     = InstanceIdentifier.builder(Nodes.class)
698                                         .child(Node.class, key)
699                                         .child(NodeConnector.class, new NodeConnectorKey(swQueueStats.getNodeConnectorId()))
700                                         .augmentation(FlowCapableNodeConnector.class)
701                                         .child(Queue.class, new QueueKey(swQueueStats.getQueueId())).toInstance();
702             
703             QueueBuilder queueBuilder = new QueueBuilder();
704             queueBuilder.addAugmentation(FlowCapableNodeConnectorQueueStatisticsData.class, queueStatisticsDataBuilder.build());
705             queueBuilder.setKey(new QueueKey(swQueueStats.getQueueId()));
706
707             sucLogger.info("Augmenting queue statistics {} of queue {} to port {}"
708                                         ,queueStatisticsDataBuilder.build().toString(),
709                                         swQueueStats.getQueueId(),
710                                         swQueueStats.getNodeConnectorId());
711             
712             it.putOperationalData(queueRef, queueBuilder.build());
713             it.commit();
714             
715         }
716         
717     }
718
719     private NodeRef getNodeRef(NodeKey nodeKey){
720         InstanceIdentifierBuilder<?> builder = InstanceIdentifier.builder(Nodes.class).child(Node.class, nodeKey);
721         return new NodeRef(builder.toInstance());
722     }
723     
724     public boolean flowEquals(Flow statsFlow, Flow storedFlow) {
725         if (statsFlow.getClass() != storedFlow.getClass()) {
726             return false;
727         }
728         if (statsFlow.getBufferId()== null) {
729             if (storedFlow.getBufferId() != null) {
730                 return false;
731             }
732         } else if(!statsFlow.getBufferId().equals(storedFlow.getBufferId())) {
733             return false;
734         }
735         if (statsFlow.getContainerName()== null) {
736             if (storedFlow.getContainerName()!= null) {
737                 return false;
738             }
739         } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
740             return false;
741         }
742         if (statsFlow.getCookie()== null) {
743             if (storedFlow.getCookie()!= null) {
744                 return false;
745             }
746         } else if(!statsFlow.getCookie().equals(storedFlow.getCookie())) {
747             return false;
748         }
749         if (statsFlow.getMatch()== null) {
750             if (storedFlow.getMatch() != null) {
751                 return false;
752             }
753         } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
754         else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
755             return false;
756         }
757         if (statsFlow.getHardTimeout() == null) {
758             if (storedFlow.getHardTimeout() != null) {
759                 return false;
760             }
761         } else if(!statsFlow.getHardTimeout().equals(storedFlow.getHardTimeout() )) {
762             return false;
763         }
764         if (statsFlow.getIdleTimeout()== null) {
765             if (storedFlow.getIdleTimeout() != null) {
766                 return false;
767             }
768         } else if(!statsFlow.getIdleTimeout().equals(storedFlow.getIdleTimeout())) {
769             return false;
770         }
771         if (statsFlow.getPriority() == null) {
772             if (storedFlow.getPriority() != null) {
773                 return false;
774             }
775         } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
776             return false;
777         }
778         if (statsFlow.getTableId() == null) {
779             if (storedFlow.getTableId() != null) {
780                 return false;
781             }
782         } else if(!statsFlow.getTableId().equals(storedFlow.getTableId())) {
783             return false;
784         }
785         return true;
786     }
787     
788     /**
789      * Explicit equals method to compare the 'match' for flows stored in the data-stores and flow fetched from the switch.
790      * Usecase: e.g If user don't set any ethernet source and destination address for match,data store will store null for 
791      * these address.
792      * e.g [_ethernetMatch=EthernetMatch [_ethernetDestination=null, _ethernetSource=null, _ethernetType=
793      * EthernetType [_type=EtherType [_value=2048], _mask=null, augmentation=[]]
794      * 
795      * But when you fetch the flows from switch, openflow driver library converts all zero bytes of mac address in the 
796      * message stream to 00:00:00:00:00:00. Following string shows how library interpret the zero mac address bytes and 
797      * eventually when translator convert it to MD-SAL match, this is how it looks 
798      * [_ethernetDestination=EthernetDestination [_address=MacAddress [_value=00:00:00:00:00:00], _mask=null, augmentation=[]], 
799      * _ethernetSource=EthernetSource [_address=MacAddress [_value=00:00:00:00:00:00], _mask=null, augmentation=[]], 
800      * _ethernetType=EthernetType [_type=EtherType [_value=2048], _mask=null, augmentation=[]]
801      * 
802      * Similarly for inPort, if user/application don't set any value for it, FRM will store null value for it in data store. 
803      * When we fetch the same flow (with its statistics) from switch, plugin converts its value to openflow:X:0.
804      *  e.g _inPort=Uri [_value=openflow:1:0]  
805      * 
806      * So this custom equals method add additional check to take care of these scenario, in case any match element is null in data-store-flow, but not
807      * in the flow fetched from switch.
808      * 
809      * @param statsFlow
810      * @param storedFlow
811      * @return
812      */
813     public boolean matchEquals(Match statsFlow, Match storedFlow) {
814         if (statsFlow == storedFlow) {
815             return true;
816         }
817         if (storedFlow.getClass() != statsFlow.getClass()) {
818             return false;
819         }
820         if (storedFlow.getEthernetMatch() == null) {
821             if (statsFlow.getEthernetMatch() != null) {
822                 if(!statsFlow.getEthernetMatch().getEthernetDestination().getAddress().getValue().equals("00:00:00:00:00:00") ||
823                         !statsFlow.getEthernetMatch().getEthernetSource().getAddress().getValue().equals("00:00:00:00:00:00")){
824                     return false;
825                 }
826             }
827         } else if(!EthernetMatchEquals(statsFlow.getEthernetMatch(),storedFlow.getEthernetMatch())) {
828             return false;
829         }
830         if (storedFlow.getIcmpv4Match()== null) {
831             if (statsFlow.getIcmpv4Match() != null) {
832                 return false;
833             }
834         } else if(!storedFlow.getIcmpv4Match().equals(statsFlow.getIcmpv4Match())) {
835             return false;
836         }
837         if (storedFlow.getIcmpv6Match() == null) {
838             if (statsFlow.getIcmpv6Match() != null) {
839                 return false;
840             }
841         } else if(!storedFlow.getIcmpv6Match().equals(statsFlow.getIcmpv6Match())) {
842             return false;
843         }
844         if (storedFlow.getInPhyPort() == null) {
845             if (statsFlow.getInPhyPort() != null) {
846                 return false;
847             }
848         } else if(!storedFlow.getInPhyPort().equals(statsFlow.getInPhyPort())) {
849             return false;
850         }
851         if (storedFlow.getInPort()== null) {
852             if (statsFlow.getInPort() != null) {
853                 String[] portArr = statsFlow.getInPort().getValue().split(":");
854                 if(portArr.length >= 3){
855                     if(Integer.parseInt(portArr[2]) != 0){
856                         return false;
857                     }
858                 }
859             }
860         } else if(!storedFlow.getInPort().equals(statsFlow.getInPort())) {
861             return false;
862         }
863         if (storedFlow.getIpMatch()== null) {
864             if (statsFlow.getIpMatch() != null) {
865                 return false;
866             }
867         } else if(!storedFlow.getIpMatch().equals(statsFlow.getIpMatch())) {
868             return false;
869         }
870         if (storedFlow.getLayer3Match()== null) {
871             if (statsFlow.getLayer3Match() != null) {
872                 Ipv4Match ipv4Match = (Ipv4Match)statsFlow.getLayer3Match();
873                 if(!ipv4Match.getIpv4Source().getValue().equals("0.0.0.0/0") ||
874                         !ipv4Match.getIpv4Destination().getValue().equals("0.0.0.0/0")){
875                     return false;
876                 }
877             }
878         } else if(!storedFlow.getLayer3Match().equals(statsFlow.getLayer3Match())) {
879             return false;
880         }
881         if (storedFlow.getLayer4Match()== null) {
882             if (statsFlow.getLayer4Match() != null) {
883                 TcpMatch tcpMatch = (TcpMatch)statsFlow.getLayer4Match();
884                 if(!tcpMatch.getTcpDestinationPort().getValue().equals(0) ||
885                     !tcpMatch.getTcpSourcePort().getValue().equals(0)){
886                         return false;
887                 }
888             }
889         } else if(!storedFlow.getLayer4Match().equals(statsFlow.getLayer4Match())) {
890             return false;
891         }
892         if (storedFlow.getMetadata() == null) {
893             if (statsFlow.getMetadata() != null) {
894                 return false;
895             }
896         } else if(!storedFlow.getMetadata().equals(statsFlow.getMetadata())) {
897             return false;
898         }
899         if (storedFlow.getProtocolMatchFields() == null) {
900             if (statsFlow.getProtocolMatchFields() != null) {
901                 return false;
902             }
903         } else if(!storedFlow.getProtocolMatchFields().equals(statsFlow.getProtocolMatchFields())) {
904             return false;
905         }
906         if (storedFlow.getTunnel()== null) {
907             if (statsFlow.getTunnel() != null) {
908                 return false;
909             }
910         } else if(!storedFlow.getTunnel().equals(statsFlow.getTunnel())) {
911             return false;
912         }
913         if (storedFlow.getVlanMatch()== null) {
914             if (statsFlow.getVlanMatch() != null) {
915                 VlanMatch vlanMatch = statsFlow.getVlanMatch();
916                 if(!vlanMatch.getVlanId().getVlanId().getValue().equals(0) ||
917                         !vlanMatch.getVlanPcp().getValue().equals((short)0)){
918                     return false;
919                 }
920             }
921         } else if(!storedFlow.getVlanMatch().equals(statsFlow.getVlanMatch())) {
922             return false;
923         }
924         return true;
925     }
926
927     public boolean EthernetMatchEquals(EthernetMatch statsEtherMatch, EthernetMatch storedEtherMatch) {
928         if (statsEtherMatch == storedEtherMatch) {
929             return true;
930         }
931         if (storedEtherMatch.getEthernetDestination()== null) {
932             if (statsEtherMatch.getEthernetDestination() != null) {
933                 if(!statsEtherMatch.getEthernetDestination().getAddress().getValue().equals("00:00:00:00:00:00")){
934                     return false;
935                 }
936             }
937         } else if(!storedEtherMatch.getEthernetDestination().equals(statsEtherMatch.getEthernetDestination())) {
938             return false;
939         }
940         if (storedEtherMatch.getEthernetSource() == null) {
941             if (statsEtherMatch.getEthernetSource() != null) {
942                 if(!statsEtherMatch.getEthernetSource().getAddress().getValue().equals("00:00:00:00:00:00")){
943                     return false;
944                 }
945             }
946         } else if(!storedEtherMatch.getEthernetSource().equals(statsEtherMatch.getEthernetSource())) {
947             return false;
948         }
949         if (storedEtherMatch.getEthernetType() == null) {
950             if (statsEtherMatch.getEthernetType() != null) {
951                 if(!statsEtherMatch.getEthernetType().getType().getValue().equals(0)){
952                     return false;
953                 }
954             }
955         } else if(!storedEtherMatch.getEthernetType().equals(statsEtherMatch.getEthernetType())) {
956             return false;
957         }
958         return true;
959     }
960 }