/* * 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.util; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.annotation.Nullable; import org.apache.commons.lang3.tuple.Pair; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.BatchGroupOutputListGrouping; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutputBuilder; 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.batch.group.output.list.grouping.BatchFailedGroupsOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; /** * provides group util methods */ public final class GroupUtil { private static final RpcResultBuilder> SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT = RpcResultBuilder.success(Collections.emptyList()); public static final Function>, RpcResult> GROUP_ADD_TRANSFORM = new Function>, RpcResult>() { @Nullable @Override public RpcResult apply(@Nullable final RpcResult> batchGroupsCumulatedResult) { final AddGroupsBatchOutput batchOutput = new AddGroupsBatchOutputBuilder() .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build(); final RpcResultBuilder resultBld = createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput); return resultBld.build(); } }; public static final Function, RpcResult>, RpcResult> GROUP_ADD_COMPOSING_TRANSFORM = createComposingFunction(); public static final Function>, RpcResult> GROUP_REMOVE_TRANSFORM = new Function>, RpcResult>() { @Nullable @Override public RpcResult apply(@Nullable final RpcResult> batchGroupsCumulatedResult) { final RemoveGroupsBatchOutput batchOutput = new RemoveGroupsBatchOutputBuilder() .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build(); final RpcResultBuilder resultBld = createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput); return resultBld.build(); } }; public static final Function, RpcResult>, RpcResult> GROUP_REMOVE_COMPOSING_TRANSFORM = createComposingFunction(); public static final Function>, RpcResult> GROUP_UPDATE_TRANSFORM = new Function>, RpcResult>() { @Nullable @Override public RpcResult apply(@Nullable final RpcResult> batchGroupsCumulatedResult) { final UpdateGroupsBatchOutput batchOutput = new UpdateGroupsBatchOutputBuilder() .setBatchFailedGroupsOutput(batchGroupsCumulatedResult.getResult()).build(); final RpcResultBuilder resultBld = createCumulativeRpcResult(batchGroupsCumulatedResult, batchOutput); return resultBld.build(); } }; public static final Function, RpcResult>, RpcResult> GROUP_UPDATE_COMPOSING_TRANSFORM = createComposingFunction(); private GroupUtil() { throw new IllegalStateException("This class should not be instantiated."); } /** * @param nodePath * @param groupId * @return instance identifier assembled for given node and group */ public static GroupRef buildGroupPath(final InstanceIdentifier nodePath, final GroupId groupId) { final KeyedInstanceIdentifier groupPath = nodePath .augmentation(FlowCapableNode.class) .child(Group.class, new GroupKey(groupId)); return new GroupRef(groupPath); } public static Function>, RpcResult>> createCumulatingFunction( final Iterable inputBatchGroups) { return createCumulatingFunction(inputBatchGroups, Iterables.size(inputBatchGroups)); } public static Function>, RpcResult>> createCumulatingFunction( final Iterable inputBatchGroups, final int sizeOfInputBatch) { return new Function>, RpcResult>>() { @Nullable @Override public RpcResult> apply(@Nullable final List> innerInput) { final int sizeOfFutures = innerInput.size(); Preconditions.checkArgument(sizeOfFutures == sizeOfInputBatch, "wrong amount of returned futures: {} <> {}", sizeOfFutures, sizeOfInputBatch); final List batchGroups = new ArrayList<>(); final Iterator batchGroupIterator = inputBatchGroups.iterator(); Collection groupErrors = new ArrayList<>(sizeOfFutures); int batchOrder = 0; for (RpcResult groupModOutput : innerInput) { final GroupId groupId = batchGroupIterator.next().getGroupId(); if (!groupModOutput.isSuccessful()) { batchGroups.add(new BatchFailedGroupsOutputBuilder() .setGroupId(groupId) .setBatchOrder(batchOrder) .build()); groupErrors.addAll(groupModOutput.getErrors()); } batchOrder++; } final RpcResultBuilder> resultBuilder; if (!groupErrors.isEmpty()) { resultBuilder = RpcResultBuilder.>failed() .withRpcErrors(groupErrors).withResult(batchGroups); } else { resultBuilder = SUCCESSFUL_GROUP_OUTPUT_RPC_RESULT; } return resultBuilder.build(); } }; } /** * Factory method: create {@link Function} which attaches barrier response to given {@link RpcResult}<T> * and changes success flag if needed. *
* Original rpcResult is the {@link Pair#getLeft()} and barrier result is the {@link Pair#getRight()}. * * @param type of rpcResult value * @return reusable static function */ @VisibleForTesting static Function, RpcResult>, RpcResult> createComposingFunction() { return new Function, RpcResult>, RpcResult>() { @Nullable @Override public RpcResult apply(@Nullable final Pair, RpcResult> input) { final RpcResultBuilder resultBld; if (input.getLeft().isSuccessful() && input.getRight().isSuccessful()) { resultBld = RpcResultBuilder.success(); } else { resultBld = RpcResultBuilder.failed(); } final ArrayList rpcErrors = new ArrayList<>(input.getLeft().getErrors()); rpcErrors.addAll(input.getRight().getErrors()); resultBld.withRpcErrors(rpcErrors); resultBld.withResult(input.getLeft().getResult()); return resultBld.build(); } }; } /** * Wrap given list of problematic group-ids into {@link RpcResult} of given type. * * @param batchGroupsCumulativeResult list of ids failed groups * @param batchOutput * @param group operation type * @return batch group operation output of given type containing list of group-ids and corresponding success flag */ private static RpcResultBuilder createCumulativeRpcResult(final @Nullable RpcResult> batchGroupsCumulativeResult, final T batchOutput) { final RpcResultBuilder resultBld; if (batchGroupsCumulativeResult.isSuccessful()) { resultBld = RpcResultBuilder.success(batchOutput); } else { resultBld = RpcResultBuilder.failed(); resultBld.withResult(batchOutput) .withRpcErrors(batchGroupsCumulativeResult.getErrors()); } return resultBld; } }