org.opendaylight.openflowplugin.impl.util.FlatBatchUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.openflowplugin.impl.util.FlatBatchUtil.java

Source

/*
 * 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.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
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.FlatBatchAddGroupCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchAddMeterCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveFlowCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveGroupCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.FlatBatchRemoveMeterCase;
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;

/**
 * Provides flat batch util methods.
 */
public final class FlatBatchUtil {

    private FlatBatchUtil() {
        throw new IllegalStateException("This class should not be instantiated.");
    }

    public static void markBarriersWhereNeeded(final List<BatchPlanStep> batchPlan) {
        final EnumSet<BatchStepType> previousTypes = EnumSet.noneOf(BatchStepType.class);

        BatchPlanStep previousPlanStep = null;
        for (BatchPlanStep planStep : batchPlan) {
            final BatchStepType type = planStep.getStepType();
            if (!previousTypes.isEmpty() && decideBarrier(previousTypes, type)) {
                previousPlanStep.setBarrierAfter(true);
                previousTypes.clear();
            }
            previousTypes.add(type);
            previousPlanStep = planStep;
        }
    }

    @VisibleForTesting
    static boolean decideBarrier(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
        return isFlowBarrierNeeded(previousTypes, type) || isGroupBarrierNeeded(previousTypes, type)
                || isMeterBarrierNeeded(previousTypes, type);
    }

    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(List<Batch> batches) {
        final List<BatchPlanStep> plan = new ArrayList<>();

        BatchPlanStep planStep;
        for (Batch batch : batches) {
            final BatchStepType nextStepType = detectBatchStepType(batch.getBatchChoice());

            planStep = new BatchPlanStep(nextStepType);
            planStep.getTaskBag().addAll(extractBatchData(planStep.getStepType(), batch.getBatchChoice()));
            if (!planStep.isEmpty()) {
                plan.add(planStep);
            }
        }

        return plan;
    }

    private static List<? extends BatchOrderGrouping> extractBatchData(final BatchStepType batchStepType,
            final BatchChoice batchChoice) {
        final List<? extends BatchOrderGrouping> batchData;
        switch (batchStepType) {
        case FLOW_ADD:
            batchData = ((FlatBatchAddFlowCase) batchChoice).getFlatBatchAddFlow();
            break;
        case FLOW_REMOVE:
            batchData = ((FlatBatchRemoveFlowCase) batchChoice).getFlatBatchRemoveFlow();
            break;
        case FLOW_UPDATE:
            batchData = ((FlatBatchUpdateFlowCase) batchChoice).getFlatBatchUpdateFlow();
            break;
        case GROUP_ADD:
            batchData = ((FlatBatchAddGroupCase) batchChoice).getFlatBatchAddGroup();
            break;
        case GROUP_REMOVE:
            batchData = ((FlatBatchRemoveGroupCase) batchChoice).getFlatBatchRemoveGroup();
            break;
        case GROUP_UPDATE:
            batchData = ((FlatBatchUpdateGroupCase) batchChoice).getFlatBatchUpdateGroup();
            break;
        case METER_ADD:
            batchData = ((FlatBatchAddMeterCase) batchChoice).getFlatBatchAddMeter();
            break;
        case METER_REMOVE:
            batchData = ((FlatBatchRemoveMeterCase) batchChoice).getFlatBatchRemoveMeter();
            break;
        case METER_UPDATE:
            batchData = ((FlatBatchUpdateMeterCase) batchChoice).getFlatBatchUpdateMeter();
            break;
        default:
            throw new IllegalArgumentException("Unsupported batch step type obtained: " + batchStepType);
        }
        return batchData;
    }

    @VisibleForTesting
    static <T extends BatchChoice> BatchStepType detectBatchStepType(final T batchCase) {
        final BatchStepType type;
        final Class<? extends DataContainer> implementedInterface = batchCase.getImplementedInterface();

        if (FlatBatchAddFlowCase.class.equals(implementedInterface)) {
            type = BatchStepType.FLOW_ADD;
        } else if (FlatBatchRemoveFlowCase.class.equals(implementedInterface)) {
            type = BatchStepType.FLOW_REMOVE;
        } else if (FlatBatchUpdateFlowCase.class.equals(implementedInterface)) {
            type = BatchStepType.FLOW_UPDATE;
        } else if (FlatBatchAddGroupCase.class.equals(implementedInterface)) {
            type = BatchStepType.GROUP_ADD;
        } else if (FlatBatchRemoveGroupCase.class.equals(implementedInterface)) {
            type = BatchStepType.GROUP_REMOVE;
        } else if (FlatBatchUpdateGroupCase.class.equals(implementedInterface)) {
            type = BatchStepType.GROUP_UPDATE;
        } else if (FlatBatchAddMeterCase.class.equals(implementedInterface)) {
            type = BatchStepType.METER_ADD;
        } else if (FlatBatchRemoveMeterCase.class.equals(implementedInterface)) {
            type = BatchStepType.METER_REMOVE;
        } else if (FlatBatchUpdateMeterCase.class.equals(implementedInterface)) {
            type = BatchStepType.METER_UPDATE;
        } else {
            throw new IllegalArgumentException("Unsupported batch obtained: " + implementedInterface);
        }
        return type;
    }

    @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().getBatchFailure());
                }
            }

            return RpcResultBuilder.<ProcessFlatBatchOutput>status(isSuccessful).withRpcErrors(rpcErrors)
                    .withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(batchFailures).build()).build();
        };
    }

    /**
     * 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
     */
    public static ListenableFuture<RpcResult<ProcessFlatBatchOutput>> mergeJobsResultsFutures(
            final List<ListenableFuture<RpcResult<ProcessFlatBatchOutput>>> firedJobs) {
        return Futures.transform(Futures.successfulAsList(firedJobs), mergeRpcResults());
    }

    /**
     * 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 ListenableFuture<RpcResult<ProcessFlatBatchOutput>> createEmptyRpcBatchResultFuture(
            final boolean status) {
        return RpcResultBuilder.<ProcessFlatBatchOutput>status(status).withRpcErrors(new ArrayList<>())
                .withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(new ArrayList<>()).build())
                .buildFuture();
    }

}