Merge "Optimized imports"
[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
43 /**
44  * provides group util methods
45  */
46 public final class GroupUtil {
47
48     private static final RpcResultBuilder<List<BatchFailedGroupsOutput>> SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT =
49             RpcResultBuilder.success(Collections.<BatchFailedGroupsOutput>emptyList());
50
51     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>> GROUP_ADD_TRANSFORM =
52             new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<AddGroupsBatchOutput>>() {
53                 @Nullable
54                 @Override
55                 public RpcResult<AddGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
56                     final AddGroupsBatchOutput batchOutput = new AddGroupsBatchOutputBuilder()
57                             .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
58
59                     final RpcResultBuilder<AddGroupsBatchOutput> resultBld =
60                             createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
61                     return resultBld.build();
62                 }
63             };
64     public static final Function<Pair<RpcResult<AddGroupsBatchOutput>, RpcResult<Void>>, RpcResult<AddGroupsBatchOutput>>
65             GROUP_ADD_COMPOSING_TRANSFORM = createComposingFunction();
66
67     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>> GROUP_REMOVE_TRANSFORM =
68             new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<RemoveGroupsBatchOutput>>() {
69                 @Nullable
70                 @Override
71                 public RpcResult<RemoveGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
72                     final RemoveGroupsBatchOutput batchOutput = new RemoveGroupsBatchOutputBuilder()
73                             .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
74
75                     final RpcResultBuilder<RemoveGroupsBatchOutput> resultBld =
76                             createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
77                     return resultBld.build();
78                 }
79             };
80     public static final Function<Pair<RpcResult<RemoveGroupsBatchOutput>, RpcResult<Void>>, RpcResult<RemoveGroupsBatchOutput>>
81             GROUP_REMOVE_COMPOSING_TRANSFORM = createComposingFunction();
82
83     public static final Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>> GROUP_UPDATE_TRANSFORM =
84             new Function<RpcResult<List<BatchFailedGroupsOutput>>, RpcResult<UpdateGroupsBatchOutput>>() {
85                 @Nullable
86                 @Override
87                 public RpcResult<UpdateGroupsBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulatedResult) {
88                     final UpdateGroupsBatchOutput batchOutput = new UpdateGroupsBatchOutputBuilder()
89                             .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build();
90
91                     final RpcResultBuilder<UpdateGroupsBatchOutput> resultBld =
92                             createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput);
93                     return resultBld.build();
94                 }
95             };
96     public static final Function<Pair<RpcResult<UpdateGroupsBatchOutput>, RpcResult<Void>>, RpcResult<UpdateGroupsBatchOutput>>
97             GROUP_UPDATE_COMPOSING_TRANSFORM = createComposingFunction();
98
99     private GroupUtil() {
100         throw new IllegalStateException("This class should not be instantiated.");
101     }
102
103     /**
104      * @param nodePath
105      * @param groupId
106      * @return instance identifier assembled for given node and group
107      */
108     public static GroupRef buildGroupPath(final InstanceIdentifier<Node> nodePath, final GroupId groupId) {
109         final KeyedInstanceIdentifier<Group, GroupKey> groupPath = nodePath
110                 .augmentation(FlowCapableNode.class)
111                 .child(Group.class, new GroupKey(groupId));
112
113         return new GroupRef(groupPath);
114     }
115
116     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction(
117             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups) {
118         return createCumulatingFunction(inputBatchGroups, Iterables.size(inputBatchGroups));
119     }
120
121     public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>> createCumulatingFunction(
122             final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group> inputBatchGroups,
123             final int sizeOfInputBatch) {
124         return new Function<List<RpcResult<O>>, RpcResult<List<BatchFailedGroupsOutput>>>() {
125             @Nullable
126             @Override
127             public RpcResult<List<BatchFailedGroupsOutput>> 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<BatchFailedGroupsOutput> batchGroups = new ArrayList<>();
133                 final Iterator<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Group>
134                         batchGroupIterator = inputBatchGroups.iterator();
135
136                 Collection<RpcError> groupErrors = new ArrayList<>(sizeOfFutures);
137
138                 int batchOrder = 0;
139                 for (RpcResult<O> groupModOutput : innerInput) {
140                     final GroupId groupId = batchGroupIterator.next().getGroupId();
141
142                     if (!groupModOutput.isSuccessful()) {
143                         batchGroups.add(new BatchFailedGroupsOutputBuilder()
144                                 .setGroupId(groupId)
145                                 .setBatchOrder(batchOrder)
146                                 .build());
147                         groupErrors.addAll(groupModOutput.getErrors());
148                     }
149                     batchOrder++;
150                 }
151
152                 final RpcResultBuilder<List<BatchFailedGroupsOutput>> resultBuilder;
153                 if (!groupErrors.isEmpty()) {
154                     resultBuilder = RpcResultBuilder.<List<BatchFailedGroupsOutput>>failed()
155                             .withRpcErrors(groupErrors).withResult(batchGroups);
156                 } else {
157                     resultBuilder = SUCCESSFUL_GROUP_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 BatchGroupOutputListGrouping>
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 batchGroupsCumulativeResult 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 BatchGroupOutputListGrouping>
207     RpcResultBuilder<T> createCumulativeRpcResult(final @Nullable RpcResult<List<BatchFailedGroupsOutput>> batchGroupsCumulativeResult,
208                                                   final T batchOutput) {
209         final RpcResultBuilder<T> resultBld;
210         if (batchGroupsCumulativeResult.isSuccessful()) {
211             resultBld = RpcResultBuilder.success(batchOutput);
212         } else {
213             resultBld = RpcResultBuilder.failed();
214             resultBld.withResult(batchOutput)
215                     .withRpcErrors(batchGroupsCumulativeResult.getErrors());
216         }
217         return resultBld;
218     }
219 }