/*
* 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.flow.inventory.rev130819.meters.Meter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.BatchMeterOutputListGrouping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchOutputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.output.list.grouping.BatchFailedMetersOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.output.list.grouping.BatchFailedMetersOutputBuilder;
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 meter util methods
*/
public final class MeterUtil {
private static final RpcResultBuilder<List<BatchFailedMetersOutput>> SUCCESSFUL_METER_OUTPUT_RPC_RESULT =
RpcResultBuilder.success(Collections.<BatchFailedMetersOutput>emptyList());
public static final Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<AddMetersBatchOutput>> METER_ADD_TRANSFORM =
new Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<AddMetersBatchOutput>>() {
@Nullable
@Override
public RpcResult<AddMetersBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulatedResult) {
final AddMetersBatchOutput batchOutput = new AddMetersBatchOutputBuilder()
.setBatchFailedMetersOutput(batchMetersCumulatedResult.getResult()).build();
final RpcResultBuilder<AddMetersBatchOutput> resultBld =
createCumulativeRpcResult(batchMetersCumulatedResult, batchOutput);
return resultBld.build();
}
};
public static final Function<Pair<RpcResult<AddMetersBatchOutput>, RpcResult<Void>>, RpcResult<AddMetersBatchOutput>>
METER_ADD_COMPOSING_TRANSFORM = createComposingFunction();
public static final Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<RemoveMetersBatchOutput>> METER_REMOVE_TRANSFORM =
new Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<RemoveMetersBatchOutput>>() {
@Nullable
@Override
public RpcResult<RemoveMetersBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulatedResult) {
final RemoveMetersBatchOutput batchOutput = new RemoveMetersBatchOutputBuilder()
.setBatchFailedMetersOutput(batchMetersCumulatedResult.getResult()).build();
final RpcResultBuilder<RemoveMetersBatchOutput> resultBld =
createCumulativeRpcResult(batchMetersCumulatedResult, batchOutput);
return resultBld.build();
}
};
public static final Function<Pair<RpcResult<RemoveMetersBatchOutput>, RpcResult<Void>>, RpcResult<RemoveMetersBatchOutput>>
METER_REMOVE_COMPOSING_TRANSFORM = createComposingFunction();
public static final Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<UpdateMetersBatchOutput>> METER_UPDATE_TRANSFORM =
new Function<RpcResult<List<BatchFailedMetersOutput>>, RpcResult<UpdateMetersBatchOutput>>() {
@Nullable
@Override
public RpcResult<UpdateMetersBatchOutput> apply(@Nullable final RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulatedResult) {
final UpdateMetersBatchOutput batchOutput = new UpdateMetersBatchOutputBuilder()
.setBatchFailedMetersOutput(batchMetersCumulatedResult.getResult()).build();
final RpcResultBuilder<UpdateMetersBatchOutput> resultBld =
createCumulativeRpcResult(batchMetersCumulatedResult, batchOutput);
return resultBld.build();
}
};
public static final Function<Pair<RpcResult<UpdateMetersBatchOutput>, RpcResult<Void>>, RpcResult<UpdateMetersBatchOutput>>
METER_UPDATE_COMPOSING_TRANSFORM = createComposingFunction();
private MeterUtil() {
throw new IllegalStateException("This class should not be instantiated.");
}
/**
* @param nodePath
* @param meterId
* @return instance identifier assembled for given node and meter
*/
public static MeterRef buildMeterPath(final InstanceIdentifier<Node> nodePath, final MeterId meterId) {
final KeyedInstanceIdentifier<Meter, MeterKey> meterPath = nodePath
.augmentation(FlowCapableNode.class)
.child(Meter.class, new MeterKey(meterId));
return new MeterRef(meterPath);
}
public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedMetersOutput>>> createCumulativeFunction(
final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter> inputBatchMeters) {
return createCumulativeFunction(inputBatchMeters, Iterables.size(inputBatchMeters));
}
public static <O> Function<List<RpcResult<O>>, RpcResult<List<BatchFailedMetersOutput>>> createCumulativeFunction(
final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter> inputBatchMeters,
final int sizeOfInputBatch) {
return new CumulativeFunction<O>(inputBatchMeters, sizeOfInputBatch).invoke();
}
/**
* Factory method: create {@link Function} which attaches barrier response to given {@link RpcResult}<T>
* and changes success flag if needed.
* <br>
* Original rpcResult is the {@link Pair#getLeft()} and barrier result is the {@link Pair#getRight()}.
*
* @param <T> type of rpcResult value
* @return reusable static function
*/
@VisibleForTesting
static <T extends BatchMeterOutputListGrouping>
Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>> createComposingFunction() {
return new Function<Pair<RpcResult<T>, RpcResult<Void>>, RpcResult<T>>() {
@Nullable
@Override
public RpcResult<T> apply(@Nullable final Pair<RpcResult<T>, RpcResult<Void>> input) {
final RpcResultBuilder<T> resultBld;
if (input.getLeft().isSuccessful() && input.getRight().isSuccessful()) {
resultBld = RpcResultBuilder.success();
} else {
resultBld = RpcResultBuilder.failed();
}
final ArrayList<RpcError> 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 batchMetersCumulativeResult list of ids failed groups
* @param batchOutput
* @param <T> group operation type
* @return batch group operation output of given type containing list of group-ids and corresponding success flag
*/
private static <T extends BatchMeterOutputListGrouping>
RpcResultBuilder<T> createCumulativeRpcResult(final @Nullable RpcResult<List<BatchFailedMetersOutput>> batchMetersCumulativeResult,
final T batchOutput) {
final RpcResultBuilder<T> resultBld;
if (batchMetersCumulativeResult.isSuccessful()) {
resultBld = RpcResultBuilder.success(batchOutput);
} else {
resultBld = RpcResultBuilder.failed();
resultBld.withResult(batchOutput)
.withRpcErrors(batchMetersCumulativeResult.getErrors());
}
return resultBld;
}
private static class CumulativeFunction<O> {
private final Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter> inputBatchMeters;
private final int sizeOfInputBatch;
public CumulativeFunction(Iterable<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter> inputBatchMeters, int sizeOfInputBatch) {
this.inputBatchMeters = inputBatchMeters;
this.sizeOfInputBatch = sizeOfInputBatch;
}
public Function<List<RpcResult<O>>, RpcResult<List<BatchFailedMetersOutput>>> invoke() {
return new Function<List<RpcResult<O>>, RpcResult<List<BatchFailedMetersOutput>>>() {
@Nullable
@Override
public RpcResult<List<BatchFailedMetersOutput>> apply(@Nullable final List<RpcResult<O>> innerInput) {
final int sizeOfFutures = innerInput.size();
Preconditions.checkArgument(sizeOfFutures == sizeOfInputBatch,
"wrong amount of returned futures: {} <> {}", sizeOfFutures, sizeOfInputBatch);
final List<BatchFailedMetersOutput> batchMeters = new ArrayList<>();
final Iterator<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter>
batchMeterIterator = inputBatchMeters.iterator();
Collection<RpcError> meterErrors = new ArrayList<>(sizeOfFutures);
int batchOrder = 0;
for (RpcResult<O> meterModOutput : innerInput) {
final MeterId meterId = batchMeterIterator.next().getMeterId();
if (!meterModOutput.isSuccessful()) {
batchMeters.add(new BatchFailedMetersOutputBuilder()
.setBatchOrder(batchOrder)
.setMeterId(meterId)
.build());
meterErrors.addAll(meterModOutput.getErrors());
}
batchOrder++;
}
final RpcResultBuilder<List<BatchFailedMetersOutput>> resultBuilder;
if (!meterErrors.isEmpty()) {
resultBuilder = RpcResultBuilder.<List<BatchFailedMetersOutput>>failed()
.withRpcErrors(meterErrors).withResult(batchMeters);
} else {
resultBuilder = SUCCESSFUL_METER_OUTPUT_RPC_RESULT;
}
return resultBuilder.build();
}
};
}
}
}