Merge "OPNFLWPLUG-929 : Remove deprecated guava library"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / FlatBatchUtil.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.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import java.util.ArrayList;
17 import java.util.EnumSet;
18 import java.util.List;
19 import org.opendaylight.openflowplugin.impl.services.batch.BatchPlanStep;
20 import org.opendaylight.openflowplugin.impl.services.batch.BatchStepType;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchOutput;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchOutputBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.Batch;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.BatchChoice;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddFlowCase;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddGroupCase;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddMeterCase;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveFlowCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveGroupCase;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveMeterCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateFlowCase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateGroupCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateMeterCase;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.output.BatchFailure;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.service.batch.common.rev160322.BatchOrderGrouping;
36 import org.opendaylight.yangtools.yang.binding.DataContainer;
37 import org.opendaylight.yangtools.yang.common.RpcError;
38 import org.opendaylight.yangtools.yang.common.RpcResult;
39 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
40
41 /**
42  * Provides flat batch util methods.
43  */
44 public final class FlatBatchUtil {
45
46     private FlatBatchUtil() {
47         throw new IllegalStateException("This class should not be instantiated.");
48     }
49
50     public static void markBarriersWhereNeeded(final List<BatchPlanStep> batchPlan) {
51         final EnumSet<BatchStepType> previousTypes = EnumSet.noneOf(BatchStepType.class);
52
53         BatchPlanStep previousPlanStep = null;
54         for (BatchPlanStep planStep : batchPlan) {
55             final BatchStepType type = planStep.getStepType();
56             if (!previousTypes.isEmpty() && decideBarrier(previousTypes, type)) {
57                 previousPlanStep.setBarrierAfter(true);
58                 previousTypes.clear();
59             }
60             previousTypes.add(type);
61             previousPlanStep = planStep;
62         }
63     }
64
65     @VisibleForTesting
66     static boolean decideBarrier(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
67         return isFlowBarrierNeeded(previousTypes, type)
68                 || isGroupBarrierNeeded(previousTypes, type)
69                 || isMeterBarrierNeeded(previousTypes, type);
70     }
71
72     private static boolean isFlowBarrierNeeded(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
73         return (type == BatchStepType.FLOW_ADD
74                 || type == BatchStepType.FLOW_UPDATE)
75                 && (previousTypes.contains(BatchStepType.GROUP_ADD)
76                 || previousTypes.contains(BatchStepType.METER_ADD));
77     }
78
79     private static boolean isGroupBarrierNeeded(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
80         return (type == BatchStepType.GROUP_ADD
81                 && (previousTypes.contains(BatchStepType.GROUP_ADD)
82                 || previousTypes.contains(BatchStepType.GROUP_UPDATE)))
83                 || (type == BatchStepType.GROUP_REMOVE
84                 && (previousTypes.contains(BatchStepType.FLOW_REMOVE)
85                 || previousTypes.contains(BatchStepType.FLOW_UPDATE)
86                 || previousTypes.contains(BatchStepType.GROUP_REMOVE)
87                 || previousTypes.contains(BatchStepType.GROUP_UPDATE)));
88     }
89
90     private static boolean isMeterBarrierNeeded(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
91         return type == BatchStepType.METER_REMOVE
92                 && (previousTypes.contains(BatchStepType.FLOW_REMOVE)
93                 || previousTypes.contains(BatchStepType.FLOW_UPDATE));
94     }
95
96     public static List<BatchPlanStep> assembleBatchPlan(List<Batch> batches) {
97         final List<BatchPlanStep> plan = new ArrayList<>();
98
99         BatchPlanStep planStep;
100         for (Batch batch : batches) {
101             final BatchStepType nextStepType = detectBatchStepType(batch.getBatchChoice());
102
103             planStep = new BatchPlanStep(nextStepType);
104             planStep.getTaskBag().addAll(extractBatchData(planStep.getStepType(), batch.getBatchChoice()));
105             if (!planStep.isEmpty()) {
106                 plan.add(planStep);
107             }
108         }
109
110         return plan;
111     }
112
113     private static List<? extends BatchOrderGrouping> extractBatchData(final BatchStepType batchStepType,
114                                                                        final BatchChoice batchChoice) {
115         final List<? extends BatchOrderGrouping> batchData;
116         switch (batchStepType) {
117             case FLOW_ADD:
118                 batchData = ((FlatBatchAddFlowCase) batchChoice).getFlatBatchAddFlow();
119                 break;
120             case FLOW_REMOVE:
121                 batchData = ((FlatBatchRemoveFlowCase) batchChoice).getFlatBatchRemoveFlow();
122                 break;
123             case FLOW_UPDATE:
124                 batchData = ((FlatBatchUpdateFlowCase) batchChoice).getFlatBatchUpdateFlow();
125                 break;
126             case GROUP_ADD:
127                 batchData = ((FlatBatchAddGroupCase) batchChoice).getFlatBatchAddGroup();
128                 break;
129             case GROUP_REMOVE:
130                 batchData = ((FlatBatchRemoveGroupCase) batchChoice).getFlatBatchRemoveGroup();
131                 break;
132             case GROUP_UPDATE:
133                 batchData = ((FlatBatchUpdateGroupCase) batchChoice).getFlatBatchUpdateGroup();
134                 break;
135             case METER_ADD:
136                 batchData = ((FlatBatchAddMeterCase) batchChoice).getFlatBatchAddMeter();
137                 break;
138             case METER_REMOVE:
139                 batchData = ((FlatBatchRemoveMeterCase) batchChoice).getFlatBatchRemoveMeter();
140                 break;
141             case METER_UPDATE:
142                 batchData = ((FlatBatchUpdateMeterCase) batchChoice).getFlatBatchUpdateMeter();
143                 break;
144             default:
145                 throw new IllegalArgumentException("Unsupported batch step type obtained: " + batchStepType);
146         }
147         return batchData;
148     }
149
150     @VisibleForTesting
151     static <T extends BatchChoice> BatchStepType detectBatchStepType(final T batchCase) {
152         final BatchStepType type;
153         final Class<? extends DataContainer> implementedInterface = batchCase.getImplementedInterface();
154
155         if (FlatBatchAddFlowCase.class.equals(implementedInterface)) {
156             type = BatchStepType.FLOW_ADD;
157         } else if (FlatBatchRemoveFlowCase.class.equals(implementedInterface)) {
158             type = BatchStepType.FLOW_REMOVE;
159         } else if (FlatBatchUpdateFlowCase.class.equals(implementedInterface)) {
160             type = BatchStepType.FLOW_UPDATE;
161         } else if (FlatBatchAddGroupCase.class.equals(implementedInterface)) {
162             type = BatchStepType.GROUP_ADD;
163         } else if (FlatBatchRemoveGroupCase.class.equals(implementedInterface)) {
164             type = BatchStepType.GROUP_REMOVE;
165         } else if (FlatBatchUpdateGroupCase.class.equals(implementedInterface)) {
166             type = BatchStepType.GROUP_UPDATE;
167         } else if (FlatBatchAddMeterCase.class.equals(implementedInterface)) {
168             type = BatchStepType.METER_ADD;
169         } else if (FlatBatchRemoveMeterCase.class.equals(implementedInterface)) {
170             type = BatchStepType.METER_REMOVE;
171         } else if (FlatBatchUpdateMeterCase.class.equals(implementedInterface)) {
172             type = BatchStepType.METER_UPDATE;
173         } else {
174             throw new IllegalArgumentException("Unsupported batch obtained: " + implementedInterface);
175         }
176         return type;
177     }
178
179     @VisibleForTesting
180     static Function<List<RpcResult<ProcessFlatBatchOutput>>, RpcResult<ProcessFlatBatchOutput>> mergeRpcResults() {
181         return jobsResults -> {
182             boolean isSuccessful = true;
183             List<RpcError> rpcErrors = new ArrayList<>();
184             List<BatchFailure> batchFailures = new ArrayList<>();
185
186             for (RpcResult<ProcessFlatBatchOutput> jobResult : jobsResults) {
187                 if (jobResult != null) {
188                     isSuccessful = (isSuccessful && jobResult.isSuccessful());
189                     rpcErrors.addAll(jobResult.getErrors());
190                     batchFailures.addAll(jobResult.getResult().getBatchFailure());
191                 }
192             }
193
194             return RpcResultBuilder.<ProcessFlatBatchOutput>status(isSuccessful)
195                     .withRpcErrors(rpcErrors)
196                     .withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(batchFailures).build())
197                     .build();
198         };
199     }
200
201     /**
202      * Merge list of Futures with partial results into one ListenableFuture with single result.
203      * @param firedJobs list of ListenableFutures with RPC results {@link ProcessFlatBatchOutput}
204      * @return ListenableFuture of RPC result with combined status and all errors + batch failures
205      */
206     public static ListenableFuture<RpcResult<ProcessFlatBatchOutput>> mergeJobsResultsFutures(
207             final List<ListenableFuture<RpcResult<ProcessFlatBatchOutput>>> firedJobs) {
208         return Futures.transform(Futures.successfulAsList(firedJobs),
209                 mergeRpcResults(),
210                 MoreExecutors.directExecutor());
211     }
212
213     /**
214      * Creates empty result future for flat batch service.
215      * @param status RPC result status
216      * @return ListenableFuture of RPC result with empty list of errors and batch failures
217      */
218     public static ListenableFuture<RpcResult<ProcessFlatBatchOutput>> createEmptyRpcBatchResultFuture(
219             final boolean status) {
220         return RpcResultBuilder.<ProcessFlatBatchOutput>status(status)
221                                .withRpcErrors(new ArrayList<>())
222                                .withResult(new ProcessFlatBatchOutputBuilder()
223                                        .setBatchFailure(new ArrayList<>())
224                                        .build())
225                                .buildFuture();
226     }
227 }