BUG-5574: bulk meters proposal
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / MeterUtil.java
1 /*
2  * Copyright (c) 2016 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.util;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Function;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.Iterables;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Iterator;
19 import java.util.List;
20 import javax.annotation.Nullable;
21 import org.apache.commons.lang3.tuple.Pair;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchOutput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchOutputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.BatchMeterOutputListGrouping;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchOutputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchOutputBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.output.list.grouping.BatchFailedMetersOutput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.output.list.grouping.BatchFailedMetersOutputBuilder;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
39 import org.opendaylight.yangtools.yang.common.RpcError;
40 import org.opendaylight.yangtools.yang.common.RpcResult;
41 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
42
43 /**
44  * provides meter util methods
45  */
46 public final class MeterUtil {
47
48     private static final RpcResultBuilder<List<BatchFailedMetersOutput>> SUCCESSFUL_METER_OUTPUT_RPC_RESULT =
49             RpcResultBuilder.success(Collections.<BatchFailedMetersOutput>emptyList());
50
51     public static final Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<AddMetersBatchOutput>> METER_ADD_TRANSFORM =
52             new Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<AddMetersBatchOutput>>() {
53                 @Nullable
54                 @Override
55                 public RpcResult<AddMetersBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulatedResult) {
56                     final AddMetersBatchOutput batchOutput = new AddMetersBatchOutputBuilder()
57                             .setBatchFailedMetersOutput(batchMetersCumulatedResult.getResult()).build();
58
59                     final RpcResultBuilder<AddMetersBatchOutput> resultBld =
60                             createCumulativeRpcResult(batchMetersCumulatedResult, batchOutput);
61                     return resultBld.build();
62                 }
63             };
64     public static final Function<Pair<RpcResult<AddMetersBatchOutput>, RpcResult<Void>>, RpcResult<AddMetersBatchOutput>>
65             METER_ADD_COMPOSING_TRANSFORM = createComposingFunction();
66
67     public static final Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<RemoveMetersBatchOutput>> METER_REMOVE_TRANSFORM =
68             new Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<RemoveMetersBatchOutput>>() {
69                 @Nullable
70                 @Override
71                 public RpcResult<RemoveMetersBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulatedResult) {
72                     final RemoveMetersBatchOutput batchOutput = new RemoveMetersBatchOutputBuilder()
73                             .setBatchFailedMetersOutput(batchMetersCumulatedResult.getResult()).build();
74
75                     final RpcResultBuilder<RemoveMetersBatchOutput> resultBld =
76                             createCumulativeRpcResult(batchMetersCumulatedResult, batchOutput);
77                     return resultBld.build();
78                 }
79             };
80     public static final Function<Pair<RpcResult<RemoveMetersBatchOutput>, RpcResult<Void>>, RpcResult<RemoveMetersBatchOutput>>
81             METER_REMOVE_COMPOSING_TRANSFORM = createComposingFunction();
82
83     public static final Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<UpdateMetersBatchOutput>> METER_UPDATE_TRANSFORM =
84             new Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<UpdateMetersBatchOutput>>() {
85                 @Nullable
86                 @Override
87                 public RpcResult<UpdateMetersBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulatedResult) {
88                     final UpdateMetersBatchOutput batchOutput = new UpdateMetersBatchOutputBuilder()
89                             .setBatchFailedMetersOutput(batchMetersCumulatedResult.getResult()).build();
90
91                     final RpcResultBuilder<UpdateMetersBatchOutput> resultBld =
92                             createCumulativeRpcResult(batchMetersCumulatedResult, batchOutput);
93                     return resultBld.build();
94                 }
95             };
96     public static final Function<Pair<RpcResult<UpdateMetersBatchOutput>, RpcResult<Void>>, RpcResult<UpdateMetersBatchOutput>>
97             METER_UPDATE_COMPOSING_TRANSFORM = createComposingFunction();
98
99     private MeterUtil() {
100         throw new IllegalStateException("This class should not be instantiated.");
101     }
102
103     /**
104      * @param nodePath
105      * @param meterId
106      * @return instance identifier assembled for given node and meter
107      */
108     public static MeterRef buildMeterPath(final InstanceIdentifier<Node> nodePath, final MeterId meterId) {
109         final KeyedInstanceIdentifier<Meter, MeterKey> meterPath = nodePath
110                 .augmentation(FlowCapableNode.class)
111                 .child(Meter.class, new MeterKey(meterId));
112
113         return new MeterRef(meterPath);
114     }
115
116     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedMetersOutput>>> createCumulativeFunction(
117             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter> inputBatchMeters) {
118         return createCumulativeFunction(inputBatchMeters, Iterables.size(inputBatchMeters));
119     }
120
121     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedMetersOutput>>> createCumulativeFunction(
122             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter> inputBatchMeters,
123             final int sizeOfInputBatch) {
124         return new Function<List<RpcResult<O>>, RpcResult<List<BatchFailedMetersOutput>>>() {
125             @Nullable
126             @Override
127             public RpcResult<List<BatchFailedMetersOutput>> apply(@Nullable final List<RpcResult<O>> innerInput) {
128                 final int sizeOfFutures = innerInput.size();
129                 Preconditions.checkArgument(sizeOfFutures == sizeOfInputBatch,
130                         "wrong amount of returned futures: {} <> {}", sizeOfFutures, sizeOfInputBatch);
131
132                 final List<BatchFailedMetersOutput> batchMeters = new ArrayList<>();
133                 final Iterator<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter>
134                         batchMeterIterator = inputBatchMeters.iterator();
135
136                 Collection<RpcError> meterErrors = new ArrayList<>(sizeOfFutures);
137
138                 int batchOrder = 0;
139                 for (RpcResult<O> meterModOutput : innerInput) {
140                     final MeterId meterId = batchMeterIterator.next().getMeterId();
141
142                     if (!meterModOutput.isSuccessful()) {
143                         batchMeters.add(new BatchFailedMetersOutputBuilder()
144                                 .setBatchOrder(batchOrder)
145                                 .setMeterId(meterId)
146                                 .build());
147                         meterErrors.addAll(meterModOutput.getErrors());
148                     }
149                     batchOrder++;
150                 }
151
152                 final RpcResultBuilder<List<BatchFailedMetersOutput>> resultBuilder;
153                 if (!meterErrors.isEmpty()) {
154                     resultBuilder = RpcResultBuilder.<List<BatchFailedMetersOutput>>failed()
155                             .withRpcErrors(meterErrors).withResult(batchMeters);
156                 } else {
157                     resultBuilder = SUCCESSFUL_METER_OUTPUT_RPC_RESULT;
158                 }
159                 return resultBuilder.build();
160             }
161         };
162     }
163
164     /**
165      * Factory method: create {@link Function} which attaches barrier response to given {@link RpcResult}&lt;T&gt;
166      * and changes success flag if needed.
167      * <br>
168      * Original rpcResult is the {@link Pair#getLeft()} and barrier result is the {@link Pair#getRight()}.
169      *
170      * @param <T> type of rpcResult value
171      * @return reusable static function
172      */
173     @VisibleForTesting
174     static <T extends BatchMeterOutputListGrouping>
175     Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>> createComposingFunction() {
176         return new Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>>() {
177             @Nullable
178             @Override
179             public RpcResult<T> apply(@Nullable final Pair<RpcResult<T>, RpcResult<Void>> input) {
180                 final RpcResultBuilder<T> resultBld;
181                 if (input.getLeft().isSuccessful() && input.getRight().isSuccessful()) {
182                     resultBld = RpcResultBuilder.success();
183                 } else {
184                     resultBld = RpcResultBuilder.failed();
185                 }
186
187                 final ArrayList<RpcError> rpcErrors = new ArrayList<>(input.getLeft().getErrors());
188                 rpcErrors.addAll(input.getRight().getErrors());
189                 resultBld.withRpcErrors(rpcErrors);
190
191                 resultBld.withResult(input.getLeft().getResult());
192
193                 return resultBld.build();
194             }
195         };
196     }
197
198     /**
199      * Wrap given list of problematic group-ids into {@link RpcResult} of given type.
200      *
201      * @param batchMetersCumulativeResult list of ids failed groups
202      * @param batchOutput
203      * @param <T>                         group operation type
204      * @return batch group operation output of given type containing list of group-ids and corresponding success flag
205      */
206     private static <T extends BatchMeterOutputListGrouping>
207     RpcResultBuilder<T> createCumulativeRpcResult(final @Nullable RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulativeResult,
208                                                   final T batchOutput) {
209         final RpcResultBuilder<T> resultBld;
210         if (batchMetersCumulativeResult.isSuccessful()) {
211             resultBld = RpcResultBuilder.success(batchOutput);
212         } else {
213             resultBld = RpcResultBuilder.failed();
214             resultBld.withResult(batchOutput)
215                     .withRpcErrors(batchMetersCumulativeResult.getErrors());
216         }
217         return resultBld;
218     }
219 }