Merge "Removed duplicate declaration in pom.xml."
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / GroupUtil.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.group.types.rev131018.GroupId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.BatchGroupOutputListGrouping;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutputBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.output.list.grouping.BatchFailedGroupsOutput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.output.list.grouping.BatchFailedGroupsOutputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
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 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType;
43
44 /**
45  * provides group util methods
46  */
47 public final class GroupUtil {
48
49     private static final RpcResultBuilder<List<BatchFailedGroupsOutput>> SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT =
50             RpcResultBuilder.success(Collections.<BatchFailedGroupsOutput>emptyList());
51
52     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>> GROUP_ADD_TRANSFORM =
53             new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>>() {
54                 @Nullable
55                 @Override
56                 public RpcResult<AddGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
57                     final AddGroupsBatchOutput batchOutput = new AddGroupsBatchOutputBuilder()
58                             .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
59
60                     final RpcResultBuilder<AddGroupsBatchOutput> resultBld =
61                             createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
62                     return resultBld.build();
63                 }
64             };
65     public static final Function<Pair<RpcResult<AddGroupsBatchOutput>, RpcResult<Void>>, RpcResult<AddGroupsBatchOutput>>
66             GROUP_ADD_COMPOSING_TRANSFORM = createComposingFunction();
67
68     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>> GROUP_REMOVE_TRANSFORM =
69             new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>>() {
70                 @Nullable
71                 @Override
72                 public RpcResult<RemoveGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
73                     final RemoveGroupsBatchOutput batchOutput = new RemoveGroupsBatchOutputBuilder()
74                             .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
75
76                     final RpcResultBuilder<RemoveGroupsBatchOutput> resultBld =
77                             createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
78                     return resultBld.build();
79                 }
80             };
81     public static final Function<Pair<RpcResult<RemoveGroupsBatchOutput>, RpcResult<Void>>, RpcResult<RemoveGroupsBatchOutput>>
82             GROUP_REMOVE_COMPOSING_TRANSFORM = createComposingFunction();
83
84     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>> GROUP_UPDATE_TRANSFORM =
85             new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>>() {
86                 @Nullable
87                 @Override
88                 public RpcResult<UpdateGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
89                     final UpdateGroupsBatchOutput batchOutput = new UpdateGroupsBatchOutputBuilder()
90                             .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
91
92                     final RpcResultBuilder<UpdateGroupsBatchOutput> resultBld =
93                             createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
94                     return resultBld.build();
95                 }
96             };
97     public static final Function<Pair<RpcResult<UpdateGroupsBatchOutput>, RpcResult<Void>>, RpcResult<UpdateGroupsBatchOutput>>
98             GROUP_UPDATE_COMPOSING_TRANSFORM = createComposingFunction();
99
100     private GroupUtil() {
101         throw new IllegalStateException("This class should not be instantiated.");
102     }
103
104     /**
105      * @param nodePath
106      * @param groupId
107      * @return instance identifier assembled for given node and group
108      */
109     public static GroupRef buildGroupPath(final InstanceIdentifier<Node> nodePath, final GroupId groupId) {
110         final KeyedInstanceIdentifier<Group, GroupKey> groupPath = nodePath
111                 .augmentation(FlowCapableNode.class)
112                 .child(Group.class, new GroupKey(groupId));
113
114         return new GroupRef(groupPath);
115     }
116
117     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction(
118             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups) {
119         return createCumulatingFunction(inputBatchGroups, Iterables.size(inputBatchGroups));
120     }
121
122     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction(
123             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups,
124             final int sizeOfInputBatch) {
125         return new CumulatingFunction<O>(inputBatchGroups, sizeOfInputBatch).invoke();
126     }
127
128     /*
129      * Method returns the bitmap of actions supported by each group.
130      *
131      * @param actionsSupported
132      * @return
133      */
134     public static List<Long> extractGroupActionsSupportBitmap(final List<ActionType> actionsSupported) {
135         List<Long> supportActionByGroups = new ArrayList<>();
136         for (org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType supportedActions : actionsSupported) {
137             long supportActionBitmap = 0;
138             supportActionBitmap |= supportedActions.isOFPATOUTPUT() ? (1) : 0;
139             supportActionBitmap |= supportedActions.isOFPATCOPYTTLOUT() ? (1 << 11) : 0;
140             supportActionBitmap |= supportedActions.isOFPATCOPYTTLIN() ? (1 << 12) : 0;
141             supportActionBitmap |= supportedActions.isOFPATSETMPLSTTL() ? (1 << 15) : 0;
142             supportActionBitmap |= supportedActions.isOFPATDECMPLSTTL() ? (1 << 16) : 0;
143             supportActionBitmap |= supportedActions.isOFPATPUSHVLAN() ? (1 << 17) : 0;
144             supportActionBitmap |= supportedActions.isOFPATPOPVLAN() ? (1 << 18) : 0;
145             supportActionBitmap |= supportedActions.isOFPATPUSHMPLS() ? (1 << 19) : 0;
146             supportActionBitmap |= supportedActions.isOFPATPOPMPLS() ? (1 << 20) : 0;
147             supportActionBitmap |= supportedActions.isOFPATSETQUEUE() ? (1 << 21) : 0;
148             supportActionBitmap |= supportedActions.isOFPATGROUP() ? (1 << 22) : 0;
149             supportActionBitmap |= supportedActions.isOFPATSETNWTTL() ? (1 << 23) : 0;
150             supportActionBitmap |= supportedActions.isOFPATDECNWTTL() ? (1 << 24) : 0;
151             supportActionBitmap |= supportedActions.isOFPATSETFIELD() ? (1 << 25) : 0;
152             supportActionBitmap |= supportedActions.isOFPATPUSHPBB() ? (1 << 26) : 0;
153             supportActionBitmap |= supportedActions.isOFPATPOPPBB() ? (1 << 27) : 0;
154             supportActionByGroups.add(supportActionBitmap);
155         }
156         return supportActionByGroups;
157     }
158
159     /**
160      * Factory method: create {@link Function} which attaches barrier response to given {@link RpcResult}&lt;T&gt;
161      * and changes success flag if needed.
162      * <br>
163      * Original rpcResult is the {@link Pair#getLeft()} and barrier result is the {@link Pair#getRight()}.
164      *
165      * @param <T> type of rpcResult value
166      * @return reusable static function
167      */
168     @VisibleForTesting
169     static <T extends BatchGroupOutputListGrouping>
170     Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>> createComposingFunction() {
171         return new Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>>() {
172             @Nullable
173             @Override
174             public RpcResult<T> apply(@Nullable final Pair<RpcResult<T>, RpcResult<Void>> input) {
175                 final RpcResultBuilder<T> resultBld;
176                 if (input.getLeft().isSuccessful() && input.getRight().isSuccessful()) {
177                     resultBld = RpcResultBuilder.success();
178                 } else {
179                     resultBld = RpcResultBuilder.failed();
180                 }
181
182                 final ArrayList<RpcError> rpcErrors = new ArrayList<>(input.getLeft().getErrors());
183                 rpcErrors.addAll(input.getRight().getErrors());
184                 resultBld.withRpcErrors(rpcErrors);
185
186                 resultBld.withResult(input.getLeft().getResult());
187
188                 return resultBld.build();
189             }
190         };
191     }
192
193     /**
194      * Wrap given list of problematic group-ids into {@link RpcResult} of given type.
195      *
196      * @param batchGroupsCumulativeResult list of ids failed groups
197      * @param batchOutput
198      * @param <T>                         group operation type
199      * @return batch group operation output of given type containing list of group-ids and corresponding success flag
200      */
201     private static <T extends BatchGroupOutputListGrouping>
202     RpcResultBuilder<T> createCumulativeRpcResult(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulativeResult,
203                                                   final T batchOutput) {
204         final RpcResultBuilder<T> resultBld;
205         if (batchGroupsCumulativeResult.isSuccessful()) {
206             resultBld = RpcResultBuilder.success(batchOutput);
207         } else {
208             resultBld = RpcResultBuilder.failed();
209             resultBld.withResult(batchOutput)
210                     .withRpcErrors(batchGroupsCumulativeResult.getErrors());
211         }
212         return resultBld;
213     }
214
215     private static class CumulatingFunction<O> {
216         private final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups;
217         private final int sizeOfInputBatch;
218
219         public CumulatingFunction(Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups, int sizeOfInputBatch) {
220             this.inputBatchGroups = inputBatchGroups;
221             this.sizeOfInputBatch = sizeOfInputBatch;
222         }
223
224         public Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> invoke() {
225             return new Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>>() {
226                 @Nullable
227                 @Override
228                 public RpcResult<List<BatchFailedGroupsOutput>> apply(@Nullable final List<RpcResult<O>> innerInput) {
229                     final int sizeOfFutures = innerInput.size();
230                     Preconditions.checkArgument(sizeOfFutures == sizeOfInputBatch,
231                             "wrong amount of returned futures: {} <> {}", sizeOfFutures, sizeOfInputBatch);
232
233                     final List<BatchFailedGroupsOutput> batchGroups = new ArrayList<>();
234                     final Iterator<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group>
235                             batchGroupIterator = inputBatchGroups.iterator();
236
237                     Collection<RpcError> groupErrors = new ArrayList<>(sizeOfFutures);
238
239                     int batchOrder = 0;
240                     for (RpcResult<O> groupModOutput : innerInput) {
241                         final GroupId groupId = batchGroupIterator.next().getGroupId();
242
243                         if (!groupModOutput.isSuccessful()) {
244                             batchGroups.add(new BatchFailedGroupsOutputBuilder()
245                                     .setGroupId(groupId)
246                                     .setBatchOrder(batchOrder)
247                                     .build());
248                             groupErrors.addAll(groupModOutput.getErrors());
249                         }
250                         batchOrder++;
251                     }
252
253                     final RpcResultBuilder<List<BatchFailedGroupsOutput>> resultBuilder;
254                     if (!groupErrors.isEmpty()) {
255                         resultBuilder = RpcResultBuilder.<List<BatchFailedGroupsOutput>>failed()
256                                 .withRpcErrors(groupErrors).withResult(batchGroups);
257                     } else {
258                         resultBuilder = SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT;
259                     }
260                     return resultBuilder.build();
261                 }
262             };
263         }
264     }
265 }