Merge "Bug 1577: Gates access to Shard actor until its initialized"
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / impl / StatListenCommitMeter.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
9 package org.opendaylight.controller.md.statistics.manager.impl;
10
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
19 import org.opendaylight.controller.md.statistics.manager.StatRpcMsgManager.TransactionCacheContainer;
20 import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
21 import org.opendaylight.controller.md.statistics.manager.StatisticsManager.StatDataStoreOperation;
22 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterConfigStatsUpdated;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterFeaturesUpdated;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.MeterStatisticsUpdated;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStats;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterConfigStatsBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterStatistics;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.OpendaylightMeterStatisticsListener;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeatures;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterConfigStatsBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatistics;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.meter.MeterStatisticsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.config.stats.reply.MeterConfigStats;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.meter.statistics.reply.MeterStats;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 import com.google.common.base.Optional;
53
54 /**
55  * statistics-manager
56  * org.opendaylight.controller.md.statistics.manager.impl
57  *
58  * StatListenCommitMeter
59  * Class is a NotifyListener for MeterStatistics and DataChangeListener for Config/DataStore for Meter node.
60  * All expected (registered) MeterStatistics will be builded and commit to Operational/DataStore.
61  * DataChangeEven should call create/delete Meter in Operational/DS
62  *
63  */
64 public class StatListenCommitMeter extends StatAbstractListenCommit<Meter, OpendaylightMeterStatisticsListener>
65                                             implements OpendaylightMeterStatisticsListener {
66
67     private static final Logger LOG = LoggerFactory.getLogger(StatListenCommitMeter.class);
68
69     public StatListenCommitMeter(final StatisticsManager manager, final DataBroker db,
70             final NotificationProviderService nps) {
71         super(manager, db, nps, Meter.class);
72     }
73
74     @Override
75     protected InstanceIdentifier<Meter> getWildCardedRegistrationPath() {
76         return InstanceIdentifier.create(Nodes.class).child(Node.class)
77                 .augmentation(FlowCapableNode.class).child(Meter.class);
78     }
79
80     @Override
81     protected OpendaylightMeterStatisticsListener getStatNotificationListener() {
82         return this;
83     }
84
85     @Override
86     public void onMeterConfigStatsUpdated(final MeterConfigStatsUpdated notification) {
87         final TransactionId transId = notification.getTransactionId();
88         final NodeId nodeId = notification.getId();
89         if ( ! isExpectedStatistics(transId, nodeId)) {
90             LOG.debug("STAT-MANAGER - MeterConfigStatsUpdated: unregistred notification detect TransactionId {}", transId);
91             return;
92         }
93         if (notification.isMoreReplies()) {
94             manager.getRpcMsgManager().addNotification(notification, nodeId);
95             return;
96         }
97         final List<MeterConfigStats> meterConfStat = notification.getMeterConfigStats() != null
98                 ? new ArrayList<>(notification.getMeterConfigStats()) : new ArrayList<MeterConfigStats>(10);
99         final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
100         if (txContainer.isPresent()) {
101             final List<? extends TransactionAware> cacheNotifs = txContainer.get().getNotifications();
102             for (final TransactionAware notif : cacheNotifs) {
103                 if (notif instanceof MeterConfigStatsUpdated) {
104                     meterConfStat.addAll(((MeterConfigStatsUpdated) notif).getMeterConfigStats());
105                 }
106             }
107         }
108         final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId));
109         manager.enqueue(new StatDataStoreOperation() {
110             @Override
111             public void applyOperation(final ReadWriteTransaction tx) {
112                 /* Notification for continue collecting statistics */
113                 notifyToCollectNextStatistics(nodeIdent);
114                 comitConfMeterStats(meterConfStat, nodeIdent, tx);
115             }
116         });
117     }
118
119     @Override
120     public void onMeterFeaturesUpdated(final MeterFeaturesUpdated notification) {
121         final TransactionId transId = notification.getTransactionId();
122         final NodeId nodeId = notification.getId();
123         if ( ! isExpectedStatistics(transId, nodeId)) {
124             LOG.debug("STAT-MANAGER - MeterFeaturesUpdated: unregistred notification detect TransactionId {}", transId);
125             return;
126         }
127         if (notification.isMoreReplies()) {
128             manager.getRpcMsgManager().addNotification(notification, nodeId);
129             return;
130         }
131         final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
132         if ( ! txContainer.isPresent()) {
133             return;
134         }
135         final MeterFeatures stats = new MeterFeaturesBuilder(notification).build();
136         final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
137                 .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
138         final InstanceIdentifier<MeterFeatures> meterFeatureIdent = nodeIdent
139                 .augmentation(NodeMeterFeatures.class).child(MeterFeatures.class);
140
141         manager.enqueue(new StatDataStoreOperation() {
142             @Override
143             public void applyOperation(final ReadWriteTransaction tx) {
144                 /* Notification for continue collecting statistics */
145                 notifyToCollectNextStatistics(nodeIdent);
146                 Optional<Node> node = Optional.absent();
147                 try {
148                     node = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet();
149                 }
150                 catch (final ReadFailedException e) {
151                     LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e);
152                 }
153                 if (node.isPresent()) {
154                     tx.put(LogicalDatastoreType.OPERATIONAL, meterFeatureIdent, stats);
155                 }
156             }
157         });
158     }
159
160     @Override
161     public void onMeterStatisticsUpdated(final MeterStatisticsUpdated notification) {
162         final TransactionId transId = notification.getTransactionId();
163         final NodeId nodeId = notification.getId();
164         if ( ! isExpectedStatistics(transId, nodeId)) {
165             LOG.debug("STAT-MANAGER - MeterStatisticsUpdated: unregistred notification detect TransactionId {}", transId);
166             return;
167         }
168         if (notification.isMoreReplies()) {
169             manager.getRpcMsgManager().addNotification(notification, nodeId);
170             return;
171         }
172         final List<MeterStats> meterStat = notification.getMeterStats() != null
173                 ? new ArrayList<>(notification.getMeterStats()) : new ArrayList<MeterStats>(10);
174         final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
175         if (txContainer.isPresent()) {
176             final List<? extends TransactionAware> cacheNotifs = txContainer.get().getNotifications();
177             for (final TransactionAware notif : cacheNotifs) {
178                 if (notif instanceof MeterConfigStatsUpdated) {
179                     meterStat.addAll(((MeterStatisticsUpdated) notif).getMeterStats());
180                 }
181             }
182         }
183         final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId));
184         manager.enqueue(new StatDataStoreOperation() {
185             @Override
186             public void applyOperation(final ReadWriteTransaction tx) {
187                 statMeterCommit(meterStat, nodeIdent, tx);
188                 /* Notification for continue collecting statistics */
189                 notifyToCollectNextStatistics(nodeIdent);
190             }
191         });
192     }
193
194     private void statMeterCommit(final List<MeterStats> meterStats,
195             final InstanceIdentifier<Node> nodeIdent, final ReadWriteTransaction trans) {
196
197         final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
198         for (final MeterStats mStat : meterStats) {
199             final MeterStatistics stats = new MeterStatisticsBuilder(mStat).build();
200
201             final MeterKey mKey = new MeterKey(mStat.getMeterId());
202             final InstanceIdentifier<MeterStatistics> msIdent = fNodeIdent
203                     .child(Meter.class, mKey).augmentation(NodeMeterStatistics.class)
204                     .child(MeterStatistics.class);
205             /* Meter Statistics commit */
206             Optional<FlowCapableNode> fNode = Optional.absent();
207             try {
208                 fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
209             }
210             catch (final ReadFailedException e) {
211                 LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
212             }
213             if (fNode.isPresent()) {
214                 trans.put(LogicalDatastoreType.OPERATIONAL, msIdent, stats);
215             }
216         }
217     }
218
219     private void comitConfMeterStats(final List<MeterConfigStats> meterConfStat,
220             final InstanceIdentifier<Node> nodeIdent, final ReadWriteTransaction trans) {
221
222         final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
223         final List<MeterKey> deviceMeterKeys = new ArrayList<>();
224
225         for (final MeterConfigStats meterConf : meterConfStat) {
226             final MeterBuilder meterBuilder = new MeterBuilder(meterConf);
227             if (meterConf.getMeterId() != null) {
228                 final MeterKey meterKey = new MeterKey(meterConf.getMeterId());
229                 meterBuilder.setKey(meterKey);
230                 final InstanceIdentifier<Meter> meterRef = nodeIdent
231                         .augmentation(FlowCapableNode.class).child(Meter.class,meterKey);
232                 final NodeMeterConfigStatsBuilder meterConfig = new NodeMeterConfigStatsBuilder();
233                 meterConfig.setMeterConfigStats(new MeterConfigStatsBuilder(meterConf).build());
234                 //Update augmented data
235                 meterBuilder.addAugmentation(NodeMeterConfigStats.class, meterConfig.build());
236                 deviceMeterKeys.add(meterKey);
237                 Optional<FlowCapableNode> fNode = Optional.absent();
238                 try {
239                     fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
240                 }
241                 catch (final ReadFailedException e) {
242                     LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
243                 }
244                 if (fNode.isPresent()) {
245                     trans.put(LogicalDatastoreType.OPERATIONAL, meterRef, meterBuilder.build());
246                 }
247             }
248         }
249         /* Delete all not presented Meter Nodes */
250         deleteAllNotPresentedNodes(fNodeIdent, trans, deviceMeterKeys);
251     }
252
253     private void deleteAllNotPresentedNodes(final InstanceIdentifier<FlowCapableNode> fNodeIdent,
254             final ReadWriteTransaction trans, final List<MeterKey> deviceMeterKeys) {
255         /* Delete all not presented meters */
256         final Optional<FlowCapableNode> fNode = readLatestConfiguration(fNodeIdent);
257
258         if ( ! fNode.isPresent()) {
259             LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent);
260             return;
261         }
262         final List<Meter> existMeters = fNode.get().getMeter() != null
263                 ? fNode.get().getMeter() : Collections.<Meter> emptyList();
264         /* Add all existed groups paths - no updated paths has to be removed */
265         for (final Meter meter : existMeters) {
266             if (deviceMeterKeys.remove(meter.getKey())) {
267                 break; // Meter still exist on device
268             }
269             final InstanceIdentifier<Meter> delMeterIdent = fNodeIdent.child(Meter.class, meter.getKey());
270             Optional<Meter> delMeter = Optional.absent();
271             try {
272                 delMeter = trans.read(LogicalDatastoreType.OPERATIONAL, delMeterIdent).checkedGet();
273             }
274             catch (final ReadFailedException e) {
275                 // NOOP - probably another transaction delete that node
276             }
277             if (delMeter.isPresent()) {
278                 trans.delete(LogicalDatastoreType.OPERATIONAL, delMeterIdent);
279             }
280         }
281     }
282 }
283