Merge "Bug 1948: Separate out restconf features."
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / impl / StatListenCommitGroup.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.transaction.rev131103.TransactionAware;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupDescStatsUpdated;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupFeaturesUpdated;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.GroupStatisticsUpdated;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStats;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupDescStatsBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupStatistics;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.OpendaylightGroupStatisticsListener;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.desc.GroupDescBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeatures;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatistics;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.statistics.GroupStatisticsBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.desc.stats.reply.GroupDescStats;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.statistics.reply.GroupStats;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
48 import org.opendaylight.yangtools.yang.binding.DataObject;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import com.google.common.base.Optional;
54
55 /**
56  * statistics-manager
57  * org.opendaylight.controller.md.statistics.manager.impl
58  *
59  * StatListenCommitGroup
60  * Class is a NotifyListener for GroupStatistics and DataChangeListener for Config/DataStore for Group node.
61  * All expected (registered) GroupStatistics will be builded and commit to Operational/DataStore.
62  * DataChangeEven should call create/delete Group in Operational/DS
63  *
64  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
65  *
66  */
67 public class StatListenCommitGroup extends StatAbstractListenCommit<Group, OpendaylightGroupStatisticsListener>
68                                                     implements OpendaylightGroupStatisticsListener {
69
70     private static final Logger LOG = LoggerFactory.getLogger(StatListenCommitMeter.class);
71
72     public StatListenCommitGroup(final StatisticsManager manager,  final DataBroker db,
73             final NotificationProviderService nps) {
74         super(manager, db, nps, Group.class);
75     }
76
77     @Override
78     protected OpendaylightGroupStatisticsListener getStatNotificationListener() {
79         return this;
80     }
81
82     @Override
83     protected InstanceIdentifier<Group> getWildCardedRegistrationPath() {
84         return InstanceIdentifier.create(Nodes.class).child(Node.class)
85                 .augmentation(FlowCapableNode.class).child(Group.class);
86     }
87
88     @Override
89     public void onGroupDescStatsUpdated(final GroupDescStatsUpdated notification) {
90         final TransactionId transId = notification.getTransactionId();
91         final NodeId nodeId = notification.getId();
92         if ( ! isExpectedStatistics(transId, nodeId)) {
93             LOG.debug("STAT-MANAGER - GroupDescStatsUpdated: unregistred notification detect TransactionId {}", transId);
94             return;
95         }
96         if (notification.isMoreReplies()) {
97             manager.getRpcMsgManager().addNotification(notification, nodeId);
98             return;
99         }
100         final List<GroupDescStats> groupStats = notification.getGroupDescStats() != null
101                 ? new ArrayList<>(notification.getGroupDescStats()) : new ArrayList<GroupDescStats>(10);
102         final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
103         if (txContainer.isPresent()) {
104             final List<? extends TransactionAware> cacheNotifs =
105                     txContainer.get().getNotifications();
106             for (final TransactionAware notif : cacheNotifs) {
107                 if (notif instanceof GroupDescStatsUpdated) {
108                     groupStats.addAll(((GroupDescStatsUpdated) notif).getGroupDescStats());
109                 }
110             }
111         }
112         final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
113                 .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
114         manager.enqueue(new StatDataStoreOperation() {
115             @Override
116             public void applyOperation(final ReadWriteTransaction tx) {
117                 statGroupDescCommit(groupStats, nodeIdent, tx);
118                 /* Notification for continue collecting statistics */
119                 notifyToCollectNextStatistics(nodeIdent);
120             }
121         });
122     }
123
124     @Override
125     public void onGroupFeaturesUpdated(final GroupFeaturesUpdated notification) {
126         final TransactionId transId = notification.getTransactionId();
127         final NodeId nodeId = notification.getId();
128         if ( ! isExpectedStatistics(transId, nodeId)) {
129             LOG.debug("STAT-MANAGER - MeterFeaturesUpdated: unregistred notification detect TransactionId {}", transId);
130             return;
131         }
132         if (notification.isMoreReplies()) {
133             manager.getRpcMsgManager().addNotification(notification, nodeId);
134             return;
135         }
136         final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
137         if ( ! txContainer.isPresent()) {
138             return;
139         }
140         final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
141                 .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
142
143         manager.enqueue(new StatDataStoreOperation() {
144             @Override
145             public void applyOperation(final ReadWriteTransaction tx) {
146                 notifyToCollectNextStatistics(nodeIdent);
147                 final GroupFeatures stats = new GroupFeaturesBuilder(notification).build();
148                 final InstanceIdentifier<GroupFeatures> groupFeatureIdent = nodeIdent
149                         .augmentation(NodeGroupFeatures.class).child(GroupFeatures.class);
150                 Optional<Node> node = Optional.absent();
151                 try {
152                     node = tx.read(LogicalDatastoreType.OPERATIONAL, nodeIdent).checkedGet();
153                 }
154                 catch (final ReadFailedException e) {
155                     LOG.debug("Read Operational/DS for Node fail! {}", nodeIdent, e);
156                 }
157                 if (node.isPresent()) {
158                     tx.put(LogicalDatastoreType.OPERATIONAL, groupFeatureIdent, stats, true);
159                 }
160             }
161         });
162     }
163
164     @Override
165     public void onGroupStatisticsUpdated(final GroupStatisticsUpdated notification) {
166         final TransactionId transId = notification.getTransactionId();
167         final NodeId nodeId = notification.getId();
168         if ( ! isExpectedStatistics(transId, nodeId)) {
169             LOG.debug("STAT-MANAGER - GroupStatisticsUpdated: unregistred notification detect TransactionId {}", transId);
170             return;
171         }
172         if (notification.isMoreReplies()) {
173             manager.getRpcMsgManager().addNotification(notification, nodeId);
174             return;
175         }
176         final List<GroupStats> groupStats = notification.getGroupStats() != null
177                 ? new ArrayList<>(notification.getGroupStats()) : new ArrayList<GroupStats>(10);
178         Optional<Group> notifGroup = Optional.absent();
179         final Optional<TransactionCacheContainer<?>> txContainer = getTransactionCacheContainer(transId, nodeId);
180         if (txContainer.isPresent()) {
181             final Optional<? extends DataObject> inputObj = txContainer.get().getConfInput();
182             if (inputObj.isPresent() && inputObj.get() instanceof Group) {
183                 notifGroup = Optional.<Group> of((Group)inputObj.get());
184             }
185             final List<? extends TransactionAware> cacheNotifs =
186                     txContainer.get().getNotifications();
187             for (final TransactionAware notif : cacheNotifs) {
188                 if (notif instanceof GroupStatisticsUpdated) {
189                     groupStats.addAll(((GroupStatisticsUpdated) notif).getGroupStats());
190                 }
191             }
192         }
193         final Optional<Group> group = notifGroup;
194         final InstanceIdentifier<Node> nodeIdent = InstanceIdentifier
195                 .create(Nodes.class).child(Node.class, new NodeKey(nodeId));
196         manager.enqueue(new StatDataStoreOperation() {
197             @Override
198             public void applyOperation(final ReadWriteTransaction tx) {
199                 /* Notification for continue collecting statistics */
200                 if ( ! group.isPresent()) {
201                     notifyToCollectNextStatistics(nodeIdent);
202                 }
203                 statGroupCommit(groupStats, nodeIdent, group, tx);
204             }
205         });
206     }
207
208     private void statGroupCommit(final List<GroupStats> groupStats, final InstanceIdentifier<Node> nodeIdent,
209             final Optional<Group> group, final ReadWriteTransaction trans) {
210         final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
211
212         for (final GroupStats groupStat : groupStats) {
213             final GroupStatistics stats = new GroupStatisticsBuilder(groupStat).build();
214
215             final GroupKey groupKey = new GroupKey(groupStat.getGroupId());
216             final InstanceIdentifier<GroupStatistics> gsIdent = fNodeIdent
217                     .child(Group.class,groupKey).augmentation(NodeGroupStatistics.class)
218                     .child(GroupStatistics.class);
219             /* Statistics Writing */
220             Optional<FlowCapableNode> fNode = Optional.absent();
221             try {
222                 fNode = trans.read(LogicalDatastoreType.OPERATIONAL, fNodeIdent).checkedGet();
223             }
224             catch (final ReadFailedException e) {
225                 LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
226             }
227             if (fNode.isPresent()) {
228                 trans.put(LogicalDatastoreType.OPERATIONAL, gsIdent, stats, true);
229             }
230         }
231     }
232
233     private void statGroupDescCommit(final List<GroupDescStats> groupStats, final InstanceIdentifier<Node> nodeIdent,
234             final ReadWriteTransaction trans) {
235         final InstanceIdentifier<FlowCapableNode> fNodeIdent = nodeIdent.augmentation(FlowCapableNode.class);
236
237         final List<GroupKey> deviceGroupKeys = new ArrayList<>();
238
239         for (final GroupDescStats group : groupStats) {
240             if (group.getGroupId() != null) {
241                 final GroupBuilder groupBuilder = new GroupBuilder(group);
242                 final GroupKey groupKey = new GroupKey(group.getGroupId());
243                 final InstanceIdentifier<Group> groupRef = fNodeIdent.child(Group.class,groupKey);
244
245                 final NodeGroupDescStatsBuilder groupDesc= new NodeGroupDescStatsBuilder();
246                 groupDesc.setGroupDesc(new GroupDescBuilder(group).build());
247                 //Update augmented data
248                 groupBuilder.addAugmentation(NodeGroupDescStats.class, groupDesc.build());
249                 deviceGroupKeys.add(groupKey);
250                 Optional<FlowCapableNode> hashIdUpd = Optional.absent();
251                 try {
252                     hashIdUpd = trans.read(LogicalDatastoreType.OPERATIONAL,fNodeIdent).checkedGet();
253                 }
254                 catch (final ReadFailedException e) {
255                     LOG.debug("Read Operational/DS for FlowCapableNode fail! {}", fNodeIdent, e);
256                 }
257                 if (hashIdUpd.isPresent()) {
258                     trans.put(LogicalDatastoreType.OPERATIONAL, groupRef, groupBuilder.build());
259                 }
260             }
261         }
262         /* Delete all not presented Group Nodes */
263         deleteAllNotPresentNode(fNodeIdent, trans, deviceGroupKeys);
264     }
265
266     private void deleteAllNotPresentNode(final InstanceIdentifier<FlowCapableNode> fNodeIdent,
267             final ReadWriteTransaction trans, final List<GroupKey> deviceGroupKeys) {
268
269         final Optional<FlowCapableNode> fNode = readLatestConfiguration(fNodeIdent);
270         if ( ! fNode.isPresent()) {
271             LOG.trace("Read Operational/DS for FlowCapableNode fail! Node {} doesn't exist.", fNodeIdent);
272             return;
273         }
274         final List<Group> existGroups = fNode.get().getGroup().isEmpty()
275                 ? Collections.<Group> emptyList() : fNode.get().getGroup();
276         /* Add all existed groups paths - no updated paths has to be removed */
277         for (final Group group : existGroups) {
278             if (deviceGroupKeys.remove(group.getKey())) {
279                 break; // group still exist on device
280             }
281             LOG.trace("Group {} has to removed.", group);
282             final InstanceIdentifier<Group> delGroupIdent = fNodeIdent.child(Group.class, group.getKey());
283             Optional<Group> delGroup = Optional.absent();
284             try {
285                 delGroup = trans.read(LogicalDatastoreType.OPERATIONAL, delGroupIdent).checkedGet();
286             }
287             catch (final ReadFailedException e) {
288                 // NOOP - probably another transaction delete that node
289             }
290             if (delGroup.isPresent()) {
291                 trans.delete(LogicalDatastoreType.OPERATIONAL, delGroupIdent);
292             }
293         }
294     }
295 }
296