2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.openflowplugin.impl.util;
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;
42 * Provides flat batch util methods.
44 public final class FlatBatchUtil {
46 private FlatBatchUtil() {
47 throw new IllegalStateException("This class should not be instantiated.");
50 public static void markBarriersWhereNeeded(final List<BatchPlanStep> batchPlan) {
51 final EnumSet<BatchStepType> previousTypes = EnumSet.noneOf(BatchStepType.class);
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();
60 previousTypes.add(type);
61 previousPlanStep = planStep;
66 static boolean decideBarrier(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
67 return isFlowBarrierNeeded(previousTypes, type)
68 || isGroupBarrierNeeded(previousTypes, type)
69 || isMeterBarrierNeeded(previousTypes, type);
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));
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)));
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));
96 public static List<BatchPlanStep> assembleBatchPlan(List<Batch> batches) {
97 final List<BatchPlanStep> plan = new ArrayList<>();
99 BatchPlanStep planStep;
100 for (Batch batch : batches) {
101 final BatchStepType nextStepType = detectBatchStepType(batch.getBatchChoice());
103 planStep = new BatchPlanStep(nextStepType);
104 planStep.getTaskBag().addAll(extractBatchData(planStep.getStepType(), batch.getBatchChoice()));
105 if (!planStep.isEmpty()) {
113 private static List<? extends BatchOrderGrouping> extractBatchData(final BatchStepType batchStepType,
114 final BatchChoice batchChoice) {
115 final List<? extends BatchOrderGrouping> batchData;
116 switch (batchStepType) {
118 batchData = ((FlatBatchAddFlowCase) batchChoice).getFlatBatchAddFlow();
121 batchData = ((FlatBatchRemoveFlowCase) batchChoice).getFlatBatchRemoveFlow();
124 batchData = ((FlatBatchUpdateFlowCase) batchChoice).getFlatBatchUpdateFlow();
127 batchData = ((FlatBatchAddGroupCase) batchChoice).getFlatBatchAddGroup();
130 batchData = ((FlatBatchRemoveGroupCase) batchChoice).getFlatBatchRemoveGroup();
133 batchData = ((FlatBatchUpdateGroupCase) batchChoice).getFlatBatchUpdateGroup();
136 batchData = ((FlatBatchAddMeterCase) batchChoice).getFlatBatchAddMeter();
139 batchData = ((FlatBatchRemoveMeterCase) batchChoice).getFlatBatchRemoveMeter();
142 batchData = ((FlatBatchUpdateMeterCase) batchChoice).getFlatBatchUpdateMeter();
145 throw new IllegalArgumentException("Unsupported batch step type obtained: " + batchStepType);
151 static <T extends BatchChoice> BatchStepType detectBatchStepType(final T batchCase) {
152 final BatchStepType type;
153 final Class<? extends DataContainer> implementedInterface = batchCase.implementedInterface();
155 // FIXME: use a lookup table instead of this cascade
156 if (FlatBatchAddFlowCase.class.equals(implementedInterface)) {
157 type = BatchStepType.FLOW_ADD;
158 } else if (FlatBatchRemoveFlowCase.class.equals(implementedInterface)) {
159 type = BatchStepType.FLOW_REMOVE;
160 } else if (FlatBatchUpdateFlowCase.class.equals(implementedInterface)) {
161 type = BatchStepType.FLOW_UPDATE;
162 } else if (FlatBatchAddGroupCase.class.equals(implementedInterface)) {
163 type = BatchStepType.GROUP_ADD;
164 } else if (FlatBatchRemoveGroupCase.class.equals(implementedInterface)) {
165 type = BatchStepType.GROUP_REMOVE;
166 } else if (FlatBatchUpdateGroupCase.class.equals(implementedInterface)) {
167 type = BatchStepType.GROUP_UPDATE;
168 } else if (FlatBatchAddMeterCase.class.equals(implementedInterface)) {
169 type = BatchStepType.METER_ADD;
170 } else if (FlatBatchRemoveMeterCase.class.equals(implementedInterface)) {
171 type = BatchStepType.METER_REMOVE;
172 } else if (FlatBatchUpdateMeterCase.class.equals(implementedInterface)) {
173 type = BatchStepType.METER_UPDATE;
175 throw new IllegalArgumentException("Unsupported batch obtained: " + implementedInterface);
181 static Function<List<RpcResult<ProcessFlatBatchOutput>>, RpcResult<ProcessFlatBatchOutput>> mergeRpcResults() {
182 return jobsResults -> {
183 boolean isSuccessful = true;
184 List<RpcError> rpcErrors = new ArrayList<>();
185 List<BatchFailure> batchFailures = new ArrayList<>();
187 for (RpcResult<ProcessFlatBatchOutput> jobResult : jobsResults) {
188 if (jobResult != null) {
189 isSuccessful = (isSuccessful && jobResult.isSuccessful());
190 rpcErrors.addAll(jobResult.getErrors());
191 batchFailures.addAll(jobResult.getResult().getBatchFailure());
195 return RpcResultBuilder.<ProcessFlatBatchOutput>status(isSuccessful)
196 .withRpcErrors(rpcErrors)
197 .withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(batchFailures).build())
203 * Merge list of Futures with partial results into one ListenableFuture with single result.
204 * @param firedJobs list of ListenableFutures with RPC results {@link ProcessFlatBatchOutput}
205 * @return ListenableFuture of RPC result with combined status and all errors + batch failures
207 public static ListenableFuture<RpcResult<ProcessFlatBatchOutput>> mergeJobsResultsFutures(
208 final List<ListenableFuture<RpcResult<ProcessFlatBatchOutput>>> firedJobs) {
209 return Futures.transform(Futures.successfulAsList(firedJobs),
211 MoreExecutors.directExecutor());
215 * Creates empty result future for flat batch service.
216 * @param status RPC result status
217 * @return ListenableFuture of RPC result with empty list of errors and batch failures
219 public static ListenableFuture<RpcResult<ProcessFlatBatchOutput>> createEmptyRpcBatchResultFuture(
220 final boolean status) {
221 return RpcResultBuilder.<ProcessFlatBatchOutput>status(status)
222 .withRpcErrors(new ArrayList<>())
223 .withResult(new ProcessFlatBatchOutputBuilder()
224 .setBatchFailure(new ArrayList<>())