Merge "Remove nexusproxy property"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / statistics / StatisticsContextImpl.java
1 /*
2  * Copyright (c) 2015 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.openflowplugin.impl.statistics;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.Iterators;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.SettableFuture;
20 import io.netty.util.Timeout;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import javax.annotation.CheckForNull;
27 import javax.annotation.Nullable;
28 import javax.annotation.concurrent.GuardedBy;
29 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
30 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
31 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
32 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
33 import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener;
34 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
35 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
36 import org.opendaylight.openflowplugin.impl.rpc.listener.ItemLifecycleListenerImpl;
37 import org.opendaylight.openflowplugin.impl.services.RequestContextUtil;
38 import org.opendaylight.openflowplugin.impl.statistics.services.dedicated.StatisticsGatheringOnTheFlyService;
39 import org.opendaylight.openflowplugin.impl.statistics.services.dedicated.StatisticsGatheringService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * Created by Martin Bobak <mbobak@cisco.com> on 1.4.2015.
46  */
47 public class StatisticsContextImpl implements StatisticsContext {
48
49     private static final Logger LOG = LoggerFactory.getLogger(StatisticsContextImpl.class);
50     private static final String CONNECTION_CLOSED = "Connection closed.";
51
52     private final ItemLifecycleListener itemLifeCycleListener;
53     private final Collection<RequestContext<?>> requestContexts = new HashSet<>();
54     private final DeviceContext deviceContext;
55     private final DeviceState devState;
56     private final ListenableFuture<Boolean> emptyFuture;
57     private final boolean shuttingDownStatisticsPolling;
58     private final Object COLLECTION_STAT_TYPE_LOCK = new Object();
59     @GuardedBy("COLLECTION_STAT_TYPE_LOCK")
60     private List<MultipartType> collectingStatType;
61
62     private StatisticsGatheringService statisticsGatheringService;
63     private StatisticsGatheringOnTheFlyService statisticsGatheringOnTheFlyService;
64     private Timeout pollTimeout;
65
66     public StatisticsContextImpl(@CheckForNull final DeviceContext deviceContext,
67             final boolean shuttingDownStatisticsPolling) {
68         this.deviceContext = Preconditions.checkNotNull(deviceContext);
69         this.devState = Preconditions.checkNotNull(deviceContext.getDeviceState());
70         this.shuttingDownStatisticsPolling = shuttingDownStatisticsPolling;
71         emptyFuture = Futures.immediateFuture(new Boolean(false));
72         statisticsGatheringService = new StatisticsGatheringService(this, deviceContext);
73         statisticsGatheringOnTheFlyService = new StatisticsGatheringOnTheFlyService(this, deviceContext);
74         itemLifeCycleListener = new ItemLifecycleListenerImpl(deviceContext);
75         statListForCollectingInitialization();
76         this.deviceContext.setStatisticsContext(StatisticsContextImpl.this);
77     }
78
79     @Override
80     public void statListForCollectingInitialization() {
81         synchronized (COLLECTION_STAT_TYPE_LOCK) {
82             final List<MultipartType> statListForCollecting = new ArrayList<>();
83             if (devState.isTableStatisticsAvailable()) {
84                 statListForCollecting.add(MultipartType.OFPMPTABLE);
85             }
86             if (devState.isFlowStatisticsAvailable()) {
87                 statListForCollecting.add(MultipartType.OFPMPFLOW);
88             }
89             if (devState.isGroupAvailable()) {
90                 statListForCollecting.add(MultipartType.OFPMPGROUPDESC);
91                 statListForCollecting.add(MultipartType.OFPMPGROUP);
92             }
93             if (devState.isMetersAvailable()) {
94                 statListForCollecting.add(MultipartType.OFPMPMETERCONFIG);
95                 statListForCollecting.add(MultipartType.OFPMPMETER);
96             }
97             if (devState.isPortStatisticsAvailable()) {
98                 statListForCollecting.add(MultipartType.OFPMPPORTSTATS);
99             }
100             if (devState.isQueueStatisticsAvailable()) {
101                 statListForCollecting.add(MultipartType.OFPMPQUEUE);
102             }
103             collectingStatType = ImmutableList.<MultipartType>copyOf(statListForCollecting);
104         }
105     }
106
107     @Override
108     public ListenableFuture<Boolean> gatherDynamicData() {
109         if (shuttingDownStatisticsPolling) {
110             LOG.debug("Statistics for device {} is not enabled.", deviceContext.getDeviceState().getNodeId());
111             return Futures.immediateFuture(Boolean.TRUE);
112         }
113         final ListenableFuture<Boolean> errorResultFuture = deviceConnectionCheck();
114         if (errorResultFuture != null) {
115             return errorResultFuture;
116         }
117         synchronized (COLLECTION_STAT_TYPE_LOCK) {
118             final Iterator<MultipartType> statIterator = collectingStatType.iterator();
119             final SettableFuture<Boolean> settableStatResultFuture = SettableFuture.create();
120
121             // write start timestamp to state snapshot container
122             StatisticsGatheringUtils.markDeviceStateSnapshotStart(deviceContext);
123
124             statChainFuture(statIterator, settableStatResultFuture);
125
126             // write end timestamp to state snapshot container
127             Futures.addCallback(settableStatResultFuture, new FutureCallback<Boolean>() {
128                 @Override
129                 public void onSuccess(@Nullable final Boolean result) {
130                     StatisticsGatheringUtils.markDeviceStateSnapshotEnd(deviceContext, true);
131                 }
132                 @Override
133                 public void onFailure(final Throwable t) {
134                     StatisticsGatheringUtils.markDeviceStateSnapshotEnd(deviceContext, false);
135                 }
136             });
137             return settableStatResultFuture;
138         }
139     }
140
141     private ListenableFuture<Boolean> chooseStat(final MultipartType multipartType){
142         switch (multipartType) {
143             case OFPMPFLOW:
144                 return collectFlowStatistics(multipartType);
145             case OFPMPTABLE:
146                 return collectTableStatistics(multipartType);
147             case OFPMPPORTSTATS:
148                 return collectPortStatistics(multipartType);
149             case OFPMPQUEUE:
150                 return collectQueueStatistics(multipartType);
151             case OFPMPGROUPDESC:
152                 return collectGroupDescStatistics(multipartType);
153             case OFPMPGROUP:
154                 return collectGroupStatistics(multipartType);
155             case OFPMPMETERCONFIG:
156                 return collectMeterConfigStatistics(multipartType);
157             case OFPMPMETER:
158                 return collectMeterStatistics(multipartType);
159             default:
160                 LOG.warn("Unsuported Statistics type {}", multipartType);
161                 return Futures.immediateCheckedFuture(Boolean.TRUE);
162         }
163     }
164
165
166     @Override
167     public <T> RequestContext<T> createRequestContext() {
168         final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.reservedXidForDeviceMessage()) {
169             @Override
170             public void close() {
171                 requestContexts.remove(this);
172             }
173         };
174         requestContexts.add(ret);
175         return ret;
176     }
177
178     @Override
179     public void close() {
180         for (final Iterator<RequestContext<?>> iterator = Iterators.consumingIterator(requestContexts.iterator());
181                 iterator.hasNext();) {
182             RequestContextUtil.closeRequestContextWithRpcError(iterator.next(), CONNECTION_CLOSED);
183         }
184         if (null != pollTimeout && !pollTimeout.isExpired()) {
185             pollTimeout.cancel();
186             }
187         }
188
189         @Override
190         public void setPollTimeout (Timeout pollTimeout){
191             this.pollTimeout = pollTimeout;
192         }
193
194         @Override
195         public Optional<Timeout> getPollTimeout () {
196             return Optional.fromNullable(pollTimeout);
197         }
198
199         void statChainFuture ( final Iterator<MultipartType> iterator, final SettableFuture<Boolean> resultFuture){
200
201             if (ConnectionContext.CONNECTION_STATE.RIP.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
202                 final String errMsg = String.format("Device connection is closed for Node : %s.",
203                         deviceContext.getDeviceState().getNodeId());
204                 LOG.debug(errMsg);
205                 resultFuture.setException(new IllegalStateException(errMsg));
206                 return;
207             }
208
209             if (!iterator.hasNext()) {
210                 resultFuture.set(Boolean.TRUE);
211                 LOG.debug("Stats collection successfully finished for node {}", deviceContext.getDeviceState().getNodeId());
212                 return;
213             }
214
215             final MultipartType nextType = iterator.next();
216             LOG.debug("Stats iterating to next type for node {} of type {}", deviceContext.getDeviceState().getNodeId(), nextType);
217
218             final ListenableFuture<Boolean> deviceStatisticsCollectionFuture = chooseStat(nextType);
219             Futures.addCallback(deviceStatisticsCollectionFuture, new FutureCallback<Boolean>() {
220                 @Override
221                 public void onSuccess(final Boolean result) {
222                     statChainFuture(iterator, resultFuture);
223                 }
224
225                 @Override
226                 public void onFailure(final Throwable t) {
227                     resultFuture.setException(t);
228                 }
229             });
230         }
231
232         /**
233          * Method checks a device state. It returns null for be able continue. Otherwise it returns immediateFuture
234          * which has to be returned from caller too
235          *
236          * @return
237          */
238         @VisibleForTesting
239         ListenableFuture<Boolean> deviceConnectionCheck () {
240             if (!ConnectionContext.CONNECTION_STATE.WORKING.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
241                 ListenableFuture<Boolean> resultingFuture = SettableFuture.create();
242                 switch (deviceContext.getPrimaryConnectionContext().getConnectionState()) {
243                     case RIP:
244                         final String errMsg = String.format("Device connection doesn't exist anymore. Primary connection status : %s",
245                                 deviceContext.getPrimaryConnectionContext().getConnectionState());
246                         resultingFuture = Futures.immediateFailedFuture(new Throwable(errMsg));
247                         break;
248                     default:
249                         resultingFuture = Futures.immediateCheckedFuture(Boolean.TRUE);
250                         break;
251                 }
252                 return resultingFuture;
253             }
254             return null;
255         }
256
257         private ListenableFuture<Boolean> collectFlowStatistics ( final MultipartType multipartType){
258             return devState.isFlowStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
259                     statisticsGatheringOnTheFlyService, deviceContext, /*MultipartType.OFPMPFLOW*/ multipartType) : emptyFuture;
260         }
261
262         private ListenableFuture<Boolean> collectTableStatistics ( final MultipartType multipartType){
263             return devState.isTableStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
264                     statisticsGatheringService, deviceContext, /*MultipartType.OFPMPTABLE*/ multipartType) : emptyFuture;
265         }
266
267         private ListenableFuture<Boolean> collectPortStatistics ( final MultipartType multipartType){
268             return devState.isPortStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
269                     statisticsGatheringService, deviceContext, /*MultipartType.OFPMPPORTSTATS*/ multipartType) : emptyFuture;
270         }
271
272         private ListenableFuture<Boolean> collectQueueStatistics ( final MultipartType multipartType){
273             return devState.isQueueStatisticsAvailable() ? StatisticsGatheringUtils.gatherStatistics(
274                     statisticsGatheringService, deviceContext, /*MultipartType.OFPMPQUEUE*/ multipartType) : emptyFuture;
275         }
276
277         private ListenableFuture<Boolean> collectGroupDescStatistics ( final MultipartType multipartType){
278             return devState.isGroupAvailable() ? StatisticsGatheringUtils.gatherStatistics(
279                     statisticsGatheringService, deviceContext, /*MultipartType.OFPMPGROUPDESC*/ multipartType) : emptyFuture;
280         }
281
282         private ListenableFuture<Boolean> collectGroupStatistics ( final MultipartType multipartType){
283             return devState.isGroupAvailable() ? StatisticsGatheringUtils.gatherStatistics(
284                     statisticsGatheringService, deviceContext, /*MultipartType.OFPMPGROUP*/ multipartType) : emptyFuture;
285         }
286
287         private ListenableFuture<Boolean> collectMeterConfigStatistics ( final MultipartType multipartType){
288             return devState.isMetersAvailable() ? StatisticsGatheringUtils.gatherStatistics(
289                     statisticsGatheringService, deviceContext, /*MultipartType.OFPMPMETERCONFIG*/ multipartType) : emptyFuture;
290         }
291
292         private ListenableFuture<Boolean> collectMeterStatistics ( final MultipartType multipartType){
293             return devState.isMetersAvailable() ? StatisticsGatheringUtils.gatherStatistics(
294                     statisticsGatheringService, deviceContext, /*MultipartType.OFPMPMETER*/ multipartType) : emptyFuture;
295         }
296
297     @VisibleForTesting
298     protected void setStatisticsGatheringService(final StatisticsGatheringService statisticsGatheringService) {
299         this.statisticsGatheringService = statisticsGatheringService;
300     }
301
302     @VisibleForTesting
303     protected void setStatisticsGatheringOnTheFlyService(final StatisticsGatheringOnTheFlyService
304                                                              statisticsGatheringOnTheFlyService) {
305         this.statisticsGatheringOnTheFlyService = statisticsGatheringOnTheFlyService;
306     }
307
308     @Override
309     public ItemLifecycleListener getItemLifeCycleListener () {
310         return itemLifeCycleListener;
311     }
312
313
314     @Override
315     public DeviceContext getDeviceContext() {
316         return deviceContext;
317     }
318 }