package org.opendaylight.openflowplugin.impl.util;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import org.opendaylight.openflowplugin.impl.services.batch.BatchPlanStep;
import org.opendaylight.openflowplugin.impl.services.batch.BatchStepType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.Batch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.BatchChoice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddFlowCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateFlowCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateGroupCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchUpdateMeterCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.output.BatchFailure;
import org.opendaylight.yang.gen.v1.urn.opendaylight.service.batch.common.rev160322.BatchOrderGrouping;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
- * provides flat batch util methods
+ * Provides flat batch util methods.
*/
public final class FlatBatchUtil {
- private static final Logger LOG = LoggerFactory.getLogger(FlatBatchUtil.class);
-
private FlatBatchUtil() {
throw new IllegalStateException("This class should not be instantiated.");
}
@VisibleForTesting
static boolean decideBarrier(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
- final boolean needBarrier;
- switch (type) {
- case FLOW_ADD:
- case FLOW_UPDATE:
- needBarrier = previousTypes.contains(BatchStepType.GROUP_ADD)
- || previousTypes.contains(BatchStepType.METER_ADD);
- break;
- case GROUP_ADD:
- needBarrier = previousTypes.contains(BatchStepType.GROUP_ADD)
- || previousTypes.contains(BatchStepType.GROUP_UPDATE);
- break;
- case GROUP_REMOVE:
- needBarrier = previousTypes.contains(BatchStepType.FLOW_REMOVE)
- || previousTypes.contains(BatchStepType.FLOW_UPDATE)
- || previousTypes.contains(BatchStepType.GROUP_REMOVE)
- || previousTypes.contains(BatchStepType.GROUP_UPDATE);
- break;
- case METER_REMOVE:
- needBarrier = previousTypes.contains(BatchStepType.FLOW_REMOVE)
- || previousTypes.contains(BatchStepType.FLOW_UPDATE);
- break;
- default:
- needBarrier = false;
- }
- return needBarrier;
+ return isFlowBarrierNeeded(previousTypes, type)
+ || isGroupBarrierNeeded(previousTypes, type)
+ || isMeterBarrierNeeded(previousTypes, type);
}
- public static List<BatchPlanStep> assembleBatchPlan(List<Batch> batches) {
+ private static boolean isFlowBarrierNeeded(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
+ return (type == BatchStepType.FLOW_ADD
+ || type == BatchStepType.FLOW_UPDATE)
+ && (previousTypes.contains(BatchStepType.GROUP_ADD)
+ || previousTypes.contains(BatchStepType.METER_ADD));
+ }
+
+ private static boolean isGroupBarrierNeeded(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
+ return type == BatchStepType.GROUP_ADD
+ && (previousTypes.contains(BatchStepType.GROUP_ADD)
+ || previousTypes.contains(BatchStepType.GROUP_UPDATE))
+ || type == BatchStepType.GROUP_REMOVE
+ && (previousTypes.contains(BatchStepType.FLOW_REMOVE)
+ || previousTypes.contains(BatchStepType.FLOW_UPDATE)
+ || previousTypes.contains(BatchStepType.GROUP_REMOVE)
+ || previousTypes.contains(BatchStepType.GROUP_UPDATE));
+ }
+
+ private static boolean isMeterBarrierNeeded(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
+ return type == BatchStepType.METER_REMOVE
+ && (previousTypes.contains(BatchStepType.FLOW_REMOVE)
+ || previousTypes.contains(BatchStepType.FLOW_UPDATE));
+ }
+
+ public static List<BatchPlanStep> assembleBatchPlan(final Collection<Batch> batches) {
final List<BatchPlanStep> plan = new ArrayList<>();
BatchPlanStep planStep;
return plan;
}
- private static List<? extends BatchOrderGrouping> extractBatchData(final BatchStepType batchStepType,
+ private static Collection<? extends BatchOrderGrouping> extractBatchData(final BatchStepType batchStepType,
final BatchChoice batchChoice) {
- final List<? extends BatchOrderGrouping> batchData;
+ final Collection<? extends BatchOrderGrouping> batchData;
switch (batchStepType) {
case FLOW_ADD:
- batchData = ((FlatBatchAddFlowCase) batchChoice).getFlatBatchAddFlow();
+ batchData = ((FlatBatchAddFlowCase) batchChoice).nonnullFlatBatchAddFlow().values();
break;
case FLOW_REMOVE:
- batchData = ((FlatBatchRemoveFlowCase) batchChoice).getFlatBatchRemoveFlow();
+ batchData = ((FlatBatchRemoveFlowCase) batchChoice).nonnullFlatBatchRemoveFlow().values();
break;
case FLOW_UPDATE:
- batchData = ((FlatBatchUpdateFlowCase) batchChoice).getFlatBatchUpdateFlow();
+ batchData = ((FlatBatchUpdateFlowCase) batchChoice).nonnullFlatBatchUpdateFlow().values();
break;
case GROUP_ADD:
- batchData = ((FlatBatchAddGroupCase) batchChoice).getFlatBatchAddGroup();
+ batchData = ((FlatBatchAddGroupCase) batchChoice).nonnullFlatBatchAddGroup().values();
break;
case GROUP_REMOVE:
- batchData = ((FlatBatchRemoveGroupCase) batchChoice).getFlatBatchRemoveGroup();
+ batchData = ((FlatBatchRemoveGroupCase) batchChoice).nonnullFlatBatchRemoveGroup().values();
break;
case GROUP_UPDATE:
- batchData = ((FlatBatchUpdateGroupCase) batchChoice).getFlatBatchUpdateGroup();
+ batchData = ((FlatBatchUpdateGroupCase) batchChoice).nonnullFlatBatchUpdateGroup().values();
break;
case METER_ADD:
- batchData = ((FlatBatchAddMeterCase) batchChoice).getFlatBatchAddMeter();
+ batchData = ((FlatBatchAddMeterCase) batchChoice).nonnullFlatBatchAddMeter().values();
break;
case METER_REMOVE:
- batchData = ((FlatBatchRemoveMeterCase) batchChoice).getFlatBatchRemoveMeter();
+ batchData = ((FlatBatchRemoveMeterCase) batchChoice).nonnullFlatBatchRemoveMeter().values();
break;
case METER_UPDATE:
- batchData = ((FlatBatchUpdateMeterCase) batchChoice).getFlatBatchUpdateMeter();
+ batchData = ((FlatBatchUpdateMeterCase) batchChoice).nonnullFlatBatchUpdateMeter().values();
break;
default:
throw new IllegalArgumentException("Unsupported batch step type obtained: " + batchStepType);
@VisibleForTesting
static <T extends BatchChoice> BatchStepType detectBatchStepType(final T batchCase) {
final BatchStepType type;
- final Class<? extends DataContainer> implementedInterface = batchCase.getImplementedInterface();
+ final Class<? extends DataContainer> implementedInterface = batchCase.implementedInterface();
+ // FIXME: use a lookup table instead of this cascade
if (FlatBatchAddFlowCase.class.equals(implementedInterface)) {
type = BatchStepType.FLOW_ADD;
} else if (FlatBatchRemoveFlowCase.class.equals(implementedInterface)) {
return type;
}
- /**
- * join errors of left and right rpc result into output
- *
- * @param output target result
- * @param chainInput left part (chained rpc result)
- * @param input right part (result of current operation)
- * @param <L> chain type
- * @param <R> current operation type
- */
- private static <L, R> void joinErrors(final RpcResultBuilder<L> output, final RpcResult<L> chainInput, final RpcResult<R> input) {
- final Collection<RpcError> rpcErrors = new ArrayList<>(chainInput.getErrors());
- rpcErrors.addAll(input.getErrors());
- if (!rpcErrors.isEmpty()) {
- output.withRpcErrors(rpcErrors);
- }
+ @VisibleForTesting
+ static Function<List<RpcResult<ProcessFlatBatchOutput>>, RpcResult<ProcessFlatBatchOutput>> mergeRpcResults() {
+ return jobsResults -> {
+ boolean isSuccessful = true;
+ List<RpcError> rpcErrors = new ArrayList<>();
+ List<BatchFailure> batchFailures = new ArrayList<>();
+
+ for (RpcResult<ProcessFlatBatchOutput> jobResult : jobsResults) {
+ if (jobResult != null) {
+ isSuccessful = isSuccessful && jobResult.isSuccessful();
+ rpcErrors.addAll(jobResult.getErrors());
+ batchFailures.addAll(jobResult.getResult().nonnullBatchFailure().values());
+ }
+ }
+
+ return RpcResultBuilder.<ProcessFlatBatchOutput>status(isSuccessful)
+ .withRpcErrors(rpcErrors)
+ .withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(batchFailures).build())
+ .build();
+ };
}
/**
- * create rpc result honoring success/fail outcomes of arguments
- *
- * @param chainInput left part (chained rpc result)
- * @param input right part (results of current operation)
- * @param <L> chain type
- * @param <R> current operation type
- * @return rpc result with combined status
+ * Merge list of Futures with partial results into one ListenableFuture with single result.
+ * @param firedJobs list of ListenableFutures with RPC results {@link ProcessFlatBatchOutput}
+ * @return ListenableFuture of RPC result with combined status and all errors + batch failures
*/
- private static <L, R> RpcResultBuilder<L> createNextRpcResultBuilder(final RpcResult<L> chainInput, final RpcResult<R> input) {
- return RpcResultBuilder.<L>status(input.isSuccessful() && chainInput.isSuccessful());
+ public static ListenableFuture<RpcResult<ProcessFlatBatchOutput>> mergeJobsResultsFutures(
+ final List<ListenableFuture<RpcResult<ProcessFlatBatchOutput>>> firedJobs) {
+ return Futures.transform(Futures.successfulAsList(firedJobs),
+ mergeRpcResults(),
+ MoreExecutors.directExecutor());
}
/**
- * Create rpc result builder with combined status and sum of all errors.
- * <br>
- * Shortcut for {@link #createNextRpcResultBuilder(RpcResult, RpcResult)} and
- * {@link #joinErrors(RpcResultBuilder, RpcResult, RpcResult)}.
- *
- * @param chainInput left part (chained rpc result)
- * @param input right part (results of current operation)
- * @param <L> chain type
- * @param <R> current operation type
- * @return rpc result with combined status and all errors
+ * Creates empty result future for flat batch service.
+ * @param status RPC result status
+ * @return ListenableFuture of RPC result with empty list of errors and batch failures
*/
- public static <L, R> RpcResultBuilder<L> mergeRpcResults(final RpcResult<L> chainInput, final RpcResult<R> input) {
- // create rpcResult builder honoring both success/failure of current input and chained input
- final RpcResultBuilder<L> output = FlatBatchUtil.createNextRpcResultBuilder(chainInput, input);
- // join errors
- FlatBatchUtil.joinErrors(output, chainInput, input);
- return output;
+ public static ListenableFuture<RpcResult<ProcessFlatBatchOutput>> createEmptyRpcBatchResultFuture(
+ final boolean status) {
+ return RpcResultBuilder.<ProcessFlatBatchOutput>status(status)
+ .withRpcErrors(new ArrayList<>())
+ .withResult(new ProcessFlatBatchOutputBuilder()
+ .setBatchFailure(new ArrayList<>())
+ .build())
+ .buildFuture();
}
}