/* * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.openflowplugin.impl.services.batch; 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.JdkFutureAdapters; import com.google.common.util.concurrent.ListenableFuture; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Future; import javax.annotation.Nullable; import org.opendaylight.openflowplugin.impl.util.FlatBatchUtil; 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.batch.choice.flat.batch.add.group._case.FlatBatchAddGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.group._case.FlatBatchRemoveGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.group._case.FlatBatchUpdateGroup; 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.flat.batch.service.rev160321.process.flat.batch.output.BatchFailureBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.output.batch.failure.batch.item.id.choice.FlatBatchFailureGroupIdCaseBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.BatchGroupOutputListGrouping; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.add.groups.batch.input.BatchAddGroups; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.add.groups.batch.input.BatchAddGroupsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.output.list.grouping.BatchFailedGroupsOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.remove.groups.batch.input.BatchRemoveGroups; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.remove.groups.batch.input.BatchRemoveGroupsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.update.groups.batch.input.BatchUpdateGroups; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.update.groups.batch.input.BatchUpdateGroupsBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; /** * transform between FlatBatch API and group batch API */ public class FlatBatchGroupAdapters { private FlatBatchGroupAdapters() { throw new IllegalStateException("This class should not be instantiated."); } /** * @param planStep batch step containing changes of the same type * @param node pointer for RPC routing * @return input suitable for {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.SalGroupsBatchService#addGroupsBatch(AddGroupsBatchInput)} */ public static AddGroupsBatchInput adaptFlatBatchAddGroup(final BatchPlanStep planStep, final NodeRef node) { final List batchGroups = new ArrayList<>(); for (FlatBatchAddGroup batchAddGroup : planStep.getTaskBag()) { final BatchAddGroups addGroups = new BatchAddGroupsBuilder(batchAddGroup) .setGroupId(batchAddGroup.getGroupId()) .build(); batchGroups.add(addGroups); } return new AddGroupsBatchInputBuilder() .setBarrierAfter(planStep.isBarrierAfter()) .setNode(node) .setBatchAddGroups(batchGroups) .build(); } /** * @param planStep batch step containing changes of the same type * @param node pointer for RPC routing * @return input suitable for {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.SalGroupsBatchService#removeGroupsBatch(RemoveGroupsBatchInput)} */ public static RemoveGroupsBatchInput adaptFlatBatchRemoveGroup(final BatchPlanStep planStep, final NodeRef node) { final List batchGroups = new ArrayList<>(); for (FlatBatchRemoveGroup batchRemoveGroup : planStep.getTaskBag()) { final BatchRemoveGroups removeGroups = new BatchRemoveGroupsBuilder(batchRemoveGroup) .setGroupId(batchRemoveGroup.getGroupId()) .build(); batchGroups.add(removeGroups); } return new RemoveGroupsBatchInputBuilder() .setBarrierAfter(planStep.isBarrierAfter()) .setNode(node) .setBatchRemoveGroups(batchGroups) .build(); } /** * @param planStep batch step containing changes of the same type * @param node pointer for RPC routing * @return input suitable for {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.SalGroupsBatchService#updateGroupsBatch(UpdateGroupsBatchInput)} */ public static UpdateGroupsBatchInput adaptFlatBatchUpdateGroup(final BatchPlanStep planStep, final NodeRef node) { final List batchGroups = new ArrayList<>(); for (FlatBatchUpdateGroup batchUpdateGroup : planStep.getTaskBag()) { final BatchUpdateGroups updateGroups = new BatchUpdateGroupsBuilder(batchUpdateGroup) .build(); batchGroups.add(updateGroups); } return new UpdateGroupsBatchInputBuilder() .setBarrierAfter(planStep.isBarrierAfter()) .setNode(node) .setBatchUpdateGroups(batchGroups) .build(); } /** * @param chainInput here all partial results are collected (values + errors) * @param stepOffset offset of current batch plan step * @return next chained result incorporating results of this step's batch */ @VisibleForTesting static Function, RpcResult> createBatchGroupChainingFunction(final RpcResult chainInput, final int stepOffset) { return new Function, RpcResult>() { @Nullable @Override public RpcResult apply(@Nullable final RpcResult input) { // create rpcResult builder honoring both success/failure of current input and chained input + join errors final RpcResultBuilder output = FlatBatchUtil.mergeRpcResults(chainInput, input); // convert values and add to chain values final ProcessFlatBatchOutputBuilder outputBuilder = new ProcessFlatBatchOutputBuilder(chainInput.getResult()); final List batchFailures = wrapBatchGroupFailuresForFlat(input, stepOffset); // join values if (outputBuilder.getBatchFailure() == null) { outputBuilder.setBatchFailure(new ArrayList(batchFailures.size())); } outputBuilder.getBatchFailure().addAll(batchFailures); return output.withResult(outputBuilder.build()).build(); } }; } private static List wrapBatchGroupFailuresForFlat( final RpcResult input, final int stepOffset) { final List batchFailures = new ArrayList<>(); if (input.getResult().getBatchFailedGroupsOutput() != null) { for (BatchFailedGroupsOutput stepOutput : input.getResult().getBatchFailedGroupsOutput()) { final BatchFailure batchFailure = new BatchFailureBuilder() .setBatchOrder(stepOffset + stepOutput.getBatchOrder()) .setBatchItemIdChoice(new FlatBatchFailureGroupIdCaseBuilder() .setGroupId(stepOutput.getGroupId()) .build()) .build(); batchFailures.add(batchFailure); } } return batchFailures; } /** * shortcut for {@link #createBatchGroupChainingFunction(RpcResult, int)} with conversion {@link ListenableFuture} * * @param exact type of batch flow output * @param chainInput here all partial results are collected (values + errors) * @param resultUpdateGroupFuture batch group rpc-result (add/remove/update) * @param currentOffset offset of current batch plan step with respect to entire chain of steps * @return next chained result incorporating results of this step's batch */ public static ListenableFuture> adaptGroupBatchFutureForChain(final RpcResult chainInput, final Future> resultUpdateGroupFuture, final int currentOffset) { return Futures.transform(JdkFutureAdapters.listenInPoolThread(resultUpdateGroupFuture), FlatBatchGroupAdapters.createBatchGroupChainingFunction(chainInput, currentOffset)); } }