org.opendaylight.openflowplugin.impl.services.SalFlatBatchServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.openflowplugin.impl.services.SalFlatBatchServiceImpl.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.services;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import org.opendaylight.openflowplugin.impl.services.batch.BatchPlanStep;
import org.opendaylight.openflowplugin.impl.services.batch.BatchStepJob;
import org.opendaylight.openflowplugin.impl.services.batch.FlatBatchFlowAdapters;
import org.opendaylight.openflowplugin.impl.services.batch.FlatBatchGroupAdapters;
import org.opendaylight.openflowplugin.impl.services.batch.FlatBatchMeterAdapters;
import org.opendaylight.openflowplugin.impl.util.FlatBatchUtil;
import org.opendaylight.openflowplugin.impl.util.PathUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchInput;
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.SalFlatBatchService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.AddFlowsBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.AddFlowsBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.RemoveFlowsBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.RemoveFlowsBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.SalFlowsBatchService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.UpdateFlowsBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.UpdateFlowsBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.AddGroupsBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.RemoveGroupsBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.SalGroupsBatchService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.UpdateGroupsBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.AddMetersBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.RemoveMetersBatchOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.SalMetersBatchService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.UpdateMetersBatchOutput;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * default implementation of {@link SalFlowsBatchService} - delegates work to {@link SalFlowService}
 */
public class SalFlatBatchServiceImpl implements SalFlatBatchService {
    private static final Logger LOG = LoggerFactory.getLogger(SalFlatBatchServiceImpl.class);

    private final SalFlowsBatchService salFlowService;
    private final SalGroupsBatchService salGroupService;
    private final SalMetersBatchService salMeterService;

    public SalFlatBatchServiceImpl(final SalFlowsBatchService salFlowBatchService,
            final SalGroupsBatchService salGroupsBatchService, final SalMetersBatchService salMetersBatchService) {
        this.salFlowService = Preconditions.checkNotNull(salFlowBatchService,
                "delegate flow service must not be null");
        this.salGroupService = Preconditions.checkNotNull(salGroupsBatchService,
                "delegate group service must not be null");
        this.salMeterService = Preconditions.checkNotNull(salMetersBatchService,
                "delegate meter service must not be null");
    }

    @Override
    public Future<RpcResult<ProcessFlatBatchOutput>> processFlatBatch(final ProcessFlatBatchInput input) {
        LOG.trace("processing flat batch @ {} : {}", PathUtil.extractNodeId(input.getNode()).getValue(),
                input.getBatch().size());
        // create plan
        final List<BatchPlanStep> batchPlan = FlatBatchUtil.assembleBatchPlan(input.getBatch());
        // add barriers where needed
        FlatBatchUtil.markBarriersWhereNeeded(batchPlan);
        // prepare chain elements
        final List<BatchStepJob> batchChainElements = prepareBatchChain(batchPlan, input.getNode(),
                input.isExitOnFirstError());
        // execute plan with barriers and collect outputs chain correspondingly, collect results
        return executeBatchPlan(batchChainElements);
    }

    @VisibleForTesting
    Future<RpcResult<ProcessFlatBatchOutput>> executeBatchPlan(final List<BatchStepJob> batchJobsChain) {
        BatchStepJob batchJob;
        final List<ListenableFuture<RpcResult<ProcessFlatBatchOutput>>> firedJobs = new ArrayList<>();
        ListenableFuture<RpcResult<ProcessFlatBatchOutput>> chainSummaryResult = FlatBatchUtil
                .createEmptyRpcBatchResultFuture(true);

        for (int i = 0; i < batchJobsChain.size(); i++) {
            batchJob = batchJobsChain.get(i);
            // wire actual job with chain
            firedJobs.add(Futures.transform(chainSummaryResult, batchJob.getStepFunction()));
            // if barrier after actual job is needed or it is the last job -> merge fired job results with chain result
            if ((batchJob.getPlanStep().isBarrierAfter()) || (i == batchJobsChain.size() - 1)) {
                firedJobs.add(0, chainSummaryResult);
                chainSummaryResult = FlatBatchUtil.mergeJobsResultsFutures(firedJobs);
                firedJobs.clear();
            }
        }
        return chainSummaryResult;
    }

    @VisibleForTesting
    List<BatchStepJob> prepareBatchChain(final List<BatchPlanStep> batchPlan, final NodeRef node,
            final boolean exitOnFirstError) {
        // create batch API calls based on plan steps
        final List<BatchStepJob> chainJobs = new ArrayList<>();
        int stepOffset = 0;
        for (final BatchPlanStep planStep : batchPlan) {
            final int currentOffset = stepOffset;
            chainJobs.add(new BatchStepJob(planStep, chainInput -> {
                if (exitOnFirstError && !chainInput.isSuccessful()) {
                    LOG.debug("error on flat batch chain occurred -> skipping step {}", planStep.getStepType());
                    return FlatBatchUtil.createEmptyRpcBatchResultFuture(false);
                }
                LOG.trace("batch progressing on step type {}, previous steps result: {}", planStep.getStepType(),
                        chainInput.isSuccessful());
                return getChainOutput(node, planStep, currentOffset);
            }));
            stepOffset += planStep.getTaskBag().size();
        }

        return chainJobs;
    }

    private ListenableFuture<RpcResult<ProcessFlatBatchOutput>> getChainOutput(final NodeRef node,
            final BatchPlanStep planStep, final int currentOffset) {
        final ListenableFuture<RpcResult<ProcessFlatBatchOutput>> chainOutput;

        switch (planStep.getStepType()) {
        case FLOW_ADD:
            final AddFlowsBatchInput addFlowsBatchInput = FlatBatchFlowAdapters.adaptFlatBatchAddFlow(planStep,
                    node);
            final Future<RpcResult<AddFlowsBatchOutput>> resultAddFlowFuture = salFlowService
                    .addFlowsBatch(addFlowsBatchInput);
            chainOutput = FlatBatchFlowAdapters.convertFlowBatchFutureForChain(resultAddFlowFuture, currentOffset);
            break;
        case FLOW_REMOVE:
            final RemoveFlowsBatchInput removeFlowsBatchInput = FlatBatchFlowAdapters
                    .adaptFlatBatchRemoveFlow(planStep, node);
            final Future<RpcResult<RemoveFlowsBatchOutput>> resultRemoveFlowFuture = salFlowService
                    .removeFlowsBatch(removeFlowsBatchInput);
            chainOutput = FlatBatchFlowAdapters.convertFlowBatchFutureForChain(resultRemoveFlowFuture,
                    currentOffset);
            break;
        case FLOW_UPDATE:
            final UpdateFlowsBatchInput updateFlowsBatchInput = FlatBatchFlowAdapters
                    .adaptFlatBatchUpdateFlow(planStep, node);
            final Future<RpcResult<UpdateFlowsBatchOutput>> resultUpdateFlowFuture = salFlowService
                    .updateFlowsBatch(updateFlowsBatchInput);
            chainOutput = FlatBatchFlowAdapters.convertFlowBatchFutureForChain(resultUpdateFlowFuture,
                    currentOffset);
            break;
        case GROUP_ADD:
            final AddGroupsBatchInput addGroupsBatchInput = FlatBatchGroupAdapters.adaptFlatBatchAddGroup(planStep,
                    node);
            final Future<RpcResult<AddGroupsBatchOutput>> resultAddGroupFuture = salGroupService
                    .addGroupsBatch(addGroupsBatchInput);
            chainOutput = FlatBatchGroupAdapters.convertGroupBatchFutureForChain(resultAddGroupFuture,
                    currentOffset);
            break;
        case GROUP_REMOVE:
            final RemoveGroupsBatchInput removeGroupsBatchInput = FlatBatchGroupAdapters
                    .adaptFlatBatchRemoveGroup(planStep, node);
            final Future<RpcResult<RemoveGroupsBatchOutput>> resultRemoveGroupFuture = salGroupService
                    .removeGroupsBatch(removeGroupsBatchInput);
            chainOutput = FlatBatchGroupAdapters.convertGroupBatchFutureForChain(resultRemoveGroupFuture,
                    currentOffset);
            break;
        case GROUP_UPDATE:
            final UpdateGroupsBatchInput updateGroupsBatchInput = FlatBatchGroupAdapters
                    .adaptFlatBatchUpdateGroup(planStep, node);
            final Future<RpcResult<UpdateGroupsBatchOutput>> resultUpdateGroupFuture = salGroupService
                    .updateGroupsBatch(updateGroupsBatchInput);
            chainOutput = FlatBatchGroupAdapters.convertGroupBatchFutureForChain(resultUpdateGroupFuture,
                    currentOffset);
            break;
        case METER_ADD:
            final AddMetersBatchInput addMetersBatchInput = FlatBatchMeterAdapters.adaptFlatBatchAddMeter(planStep,
                    node);
            final Future<RpcResult<AddMetersBatchOutput>> resultAddMeterFuture = salMeterService
                    .addMetersBatch(addMetersBatchInput);
            chainOutput = FlatBatchMeterAdapters.convertMeterBatchFutureForChain(resultAddMeterFuture,
                    currentOffset);
            break;
        case METER_REMOVE:
            final RemoveMetersBatchInput removeMetersBatchInput = FlatBatchMeterAdapters
                    .adaptFlatBatchRemoveMeter(planStep, node);
            final Future<RpcResult<RemoveMetersBatchOutput>> resultRemoveMeterFuture = salMeterService
                    .removeMetersBatch(removeMetersBatchInput);
            chainOutput = FlatBatchMeterAdapters.convertMeterBatchFutureForChain(resultRemoveMeterFuture,
                    currentOffset);
            break;
        case METER_UPDATE:
            final UpdateMetersBatchInput updateMetersBatchInput = FlatBatchMeterAdapters
                    .adaptFlatBatchUpdateMeter(planStep, node);
            final Future<RpcResult<UpdateMetersBatchOutput>> resultUpdateMeterFuture = salMeterService
                    .updateMetersBatch(updateMetersBatchInput);
            chainOutput = FlatBatchMeterAdapters.convertMeterBatchFutureForChain(resultUpdateMeterFuture,
                    currentOffset);
            break;
        default:
            LOG.warn("Unsupported plan-step type occurred: {} -> OMITTING", planStep.getStepType());
            chainOutput = FlatBatchUtil.createEmptyRpcBatchResultFuture(true);
        }

        return chainOutput;
    }
}