/**
* 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.applications.frsync.impl.strategy;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;
import com.google.common.collect.Range;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
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.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
import org.opendaylight.openflowplugin.applications.frsync.SyncPlanPushStrategy;
import org.opendaylight.openflowplugin.applications.frsync.util.ItemSyncBox;
import org.opendaylight.openflowplugin.applications.frsync.util.PathUtil;
import org.opendaylight.openflowplugin.applications.frsync.util.ReconcileUtil;
import org.opendaylight.openflowplugin.applications.frsync.util.SyncCrudCounters;
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.ProcessFlatBatchInputBuilder;
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.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.BatchBuilder;
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.FlatBatchAddFlowCaseBuilder;
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.FlatBatchAddGroupCaseBuilder;
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.FlatBatchAddMeterCaseBuilder;
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.FlatBatchRemoveFlowCaseBuilder;
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.FlatBatchRemoveGroupCaseBuilder;
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.FlatBatchRemoveMeterCaseBuilder;
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.FlatBatchUpdateFlowCaseBuilder;
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.FlatBatchUpdateGroupCaseBuilder;
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.input.batch.batch.choice.FlatBatchUpdateMeterCaseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.add.flow._case.FlatBatchAddFlow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.add.flow._case.FlatBatchAddFlowBuilder;
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.add.group._case.FlatBatchAddGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.add.meter._case.FlatBatchAddMeter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.add.meter._case.FlatBatchAddMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.flow._case.FlatBatchRemoveFlow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.flow._case.FlatBatchRemoveFlowBuilder;
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.remove.group._case.FlatBatchRemoveGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.meter._case.FlatBatchRemoveMeter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.remove.meter._case.FlatBatchRemoveMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.flow._case.FlatBatchUpdateFlow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.flow._case.FlatBatchUpdateFlowBuilder;
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.input.batch.batch.choice.flat.batch.update.group._case.FlatBatchUpdateGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.meter._case.FlatBatchUpdateMeter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.batch.choice.flat.batch.update.meter._case.FlatBatchUpdateMeterBuilder;
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.flow.inventory.rev130819.meters.Meter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.batch.flow.input.update.grouping.OriginalBatchedFlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.batch.flow.input.update.grouping.UpdatedBatchedFlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.input.update.grouping.OriginalBatchedGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.input.update.grouping.UpdatedBatchedGroupBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.input.update.grouping.OriginalBatchedMeterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.input.update.grouping.UpdatedBatchedMeterBuilder;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Execute CRUD API for flow + group + meter involving flat-batch strategy.
*/
public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
private static final Logger LOG = LoggerFactory.getLogger(SyncPlanPushStrategyFlatBatchImpl.class);
private SalFlatBatchService flatBatchService;
private TableForwarder tableForwarder;
@Override
public ListenableFuture<RpcResult<Void>> executeSyncStrategy(ListenableFuture<RpcResult<Void>> resultVehicle,
final SynchronizationDiffInput diffInput,
final SyncCrudCounters counters) {
// prepare default (full) counts
counters.getGroupCrudCounts().setAdded(ReconcileUtil.countTotalPushed(diffInput.getGroupsToAddOrUpdate()));
counters.getGroupCrudCounts().setUpdated(ReconcileUtil.countTotalUpdated(diffInput.getGroupsToAddOrUpdate()));
counters.getGroupCrudCounts().setRemoved(ReconcileUtil.countTotalPushed(diffInput.getGroupsToRemove()));
counters.getFlowCrudCounts().setAdded(ReconcileUtil.countTotalPushed(diffInput.getFlowsToAddOrUpdate().values()));
counters.getFlowCrudCounts().setUpdated(ReconcileUtil.countTotalUpdated(diffInput.getFlowsToAddOrUpdate().values()));
counters.getFlowCrudCounts().setRemoved(ReconcileUtil.countTotalPushed(diffInput.getFlowsToRemove().values()));
counters.getMeterCrudCounts().setAdded(diffInput.getMetersToAddOrUpdate().getItemsToPush().size());
counters.getMeterCrudCounts().setUpdated(diffInput.getMetersToAddOrUpdate().getItemsToUpdate().size());
counters.getMeterCrudCounts().setRemoved(diffInput.getMetersToRemove().getItemsToPush().size());
/* Tables - have to be pushed before groups */
// TODO enable table-update when ready
//resultVehicle = updateTableFeatures(nodeIdent, configTree);
resultVehicle = Futures.transform(resultVehicle, new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
@Override
public ListenableFuture<RpcResult<Void>> apply(final RpcResult<Void> input) throws Exception {
final List<Batch> batchBag = new ArrayList<>();
int batchOrder = 0;
batchOrder = assembleAddOrUpdateGroups(batchBag, batchOrder, diffInput.getGroupsToAddOrUpdate());
batchOrder = assembleAddOrUpdateMeters(batchBag, batchOrder, diffInput.getMetersToAddOrUpdate());
batchOrder = assembleAddOrUpdateFlows(batchBag, batchOrder, diffInput.getFlowsToAddOrUpdate());
batchOrder = assembleRemoveFlows(batchBag, batchOrder, diffInput.getFlowsToRemove());
batchOrder = assembleRemoveMeters(batchBag, batchOrder, diffInput.getMetersToRemove());
batchOrder = assembleRemoveGroups(batchBag, batchOrder, diffInput.getGroupsToRemove());
LOG.trace("Index of last batch step: {}", batchOrder);
final ProcessFlatBatchInput flatBatchInput = new ProcessFlatBatchInputBuilder()
.setNode(new NodeRef(PathUtil.digNodePath(diffInput.getNodeIdent())))
// TODO: propagate from input
.setExitOnFirstError(false)
.setBatch(batchBag)
.build();
final Future<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture = flatBatchService.processFlatBatch(flatBatchInput);
if (LOG.isDebugEnabled()) {
Futures.addCallback(JdkFutureAdapters.listenInPoolThread(rpcResultFuture),
createCounterCallback(batchBag, batchOrder, counters));
}
return Futures.transform(JdkFutureAdapters.listenInPoolThread(rpcResultFuture),
ReconcileUtil.<ProcessFlatBatchOutput>createRpcResultToVoidFunction("flat-batch"));
}
});
return resultVehicle;
}
private FutureCallback<RpcResult<ProcessFlatBatchOutput>> createCounterCallback(final List<Batch> inputBatchBag,
final int failureIndexLimit,
final SyncCrudCounters counters) {
return new FutureCallback<RpcResult<ProcessFlatBatchOutput>>() {
@Override
public void onSuccess(@Nullable final RpcResult<ProcessFlatBatchOutput> result) {
if (!result.isSuccessful() && result.getResult() != null && !result.getResult().getBatchFailure().isEmpty()) {
Map<Range<Integer>, Batch> batchMap = mapBatchesToRanges(inputBatchBag, failureIndexLimit);
decrementBatchFailuresCounters(result.getResult().getBatchFailure(), batchMap, counters);
}
}
@Override
public void onFailure(final Throwable t) {
counters.resetAll();
}
};
}
private static void decrementBatchFailuresCounters(final List<BatchFailure> batchFailures,
final Map<Range<Integer>, Batch> batchMap,
final SyncCrudCounters counters) {
for (BatchFailure batchFailure : batchFailures) {
for (Map.Entry<Range<Integer>, Batch> rangeBatchEntry : batchMap.entrySet()) {
if (rangeBatchEntry.getKey().contains(batchFailure.getBatchOrder())) {
// get type and decrease
final BatchChoice batchChoice = rangeBatchEntry.getValue().getBatchChoice();
decrementCounters(batchChoice, counters);
break;
}
}
}
}
static void decrementCounters(final BatchChoice batchChoice, final SyncCrudCounters counters) {
if (batchChoice instanceof FlatBatchAddFlowCase) {
counters.getFlowCrudCounts().decAdded();
} else if (batchChoice instanceof FlatBatchUpdateFlowCase) {
counters.getFlowCrudCounts().decUpdated();
} else if (batchChoice instanceof FlatBatchRemoveFlowCase) {
counters.getFlowCrudCounts().decRemoved();
} else if (batchChoice instanceof FlatBatchAddGroupCase) {
counters.getGroupCrudCounts().decAdded();
} else if (batchChoice instanceof FlatBatchUpdateGroupCase) {
counters.getGroupCrudCounts().decUpdated();
} else if (batchChoice instanceof FlatBatchRemoveGroupCase) {
counters.getGroupCrudCounts().decRemoved();
} else if (batchChoice instanceof FlatBatchAddMeterCase) {
counters.getMeterCrudCounts().decAdded();
} else if (batchChoice instanceof FlatBatchUpdateMeterCase) {
counters.getMeterCrudCounts().decUpdated();
} else if (batchChoice instanceof FlatBatchRemoveMeterCase) {
counters.getMeterCrudCounts().decRemoved();
}
}
static Map<Range<Integer>, Batch> mapBatchesToRanges(final List<Batch> inputBatchBag, final int failureIndexLimit) {
final Map<Range<Integer>, Batch> batchMap = new LinkedHashMap<>();
final PeekingIterator<Batch> batchPeekingIterator = Iterators.peekingIterator(inputBatchBag.iterator());
while (batchPeekingIterator.hasNext()) {
final Batch batch = batchPeekingIterator.next();
final int nextBatchOrder = batchPeekingIterator.hasNext()
? batchPeekingIterator.peek().getBatchOrder()
: failureIndexLimit;
batchMap.put(Range.closed(batch.getBatchOrder(), nextBatchOrder - 1), batch);
}
return batchMap;
}
@VisibleForTesting
static int assembleRemoveFlows(final List<Batch> batchBag, int batchOrder, final Map<TableKey, ItemSyncBox<Flow>> flowItemSyncTableMap) {
// process flow remove
int order = batchOrder;
if (flowItemSyncTableMap != null) {
for (Map.Entry<TableKey, ItemSyncBox<Flow>> syncBoxEntry : flowItemSyncTableMap.entrySet()) {
final ItemSyncBox<Flow> flowItemSyncBox = syncBoxEntry.getValue();
if (!flowItemSyncBox.getItemsToPush().isEmpty()) {
final List<FlatBatchRemoveFlow> flatBatchRemoveFlowBag =
new ArrayList<>(flowItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (Flow flow : flowItemSyncBox.getItemsToPush()) {
flatBatchRemoveFlowBag.add(new FlatBatchRemoveFlowBuilder(flow)
.setBatchOrder(itemOrder++)
.setFlowId(flow.getId())
.build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchRemoveFlowCaseBuilder()
.setFlatBatchRemoveFlow(flatBatchRemoveFlowBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
}
}
return order;
}
@VisibleForTesting
static int assembleAddOrUpdateGroups(final List<Batch> batchBag, int batchOrder, final List<ItemSyncBox<Group>> groupsToAddOrUpdate) {
// process group add+update
int order = batchOrder;
if (groupsToAddOrUpdate != null) {
for (ItemSyncBox<Group> groupItemSyncBox : groupsToAddOrUpdate) {
if (!groupItemSyncBox.getItemsToPush().isEmpty()) {
final List<FlatBatchAddGroup> flatBatchAddGroupBag =
new ArrayList<>(groupItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (Group group : groupItemSyncBox.getItemsToPush()) {
flatBatchAddGroupBag.add(new FlatBatchAddGroupBuilder(group).setBatchOrder(itemOrder++).build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchAddGroupCaseBuilder()
.setFlatBatchAddGroup(flatBatchAddGroupBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
if (!groupItemSyncBox.getItemsToUpdate().isEmpty()) {
final List<FlatBatchUpdateGroup> flatBatchUpdateGroupBag =
new ArrayList<>(groupItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (ItemSyncBox.ItemUpdateTuple<Group> groupUpdate : groupItemSyncBox.getItemsToUpdate()) {
flatBatchUpdateGroupBag.add(new FlatBatchUpdateGroupBuilder()
.setBatchOrder(itemOrder++)
.setOriginalBatchedGroup(new OriginalBatchedGroupBuilder(groupUpdate.getOriginal()).build())
.setUpdatedBatchedGroup(new UpdatedBatchedGroupBuilder(groupUpdate.getUpdated()).build())
.build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchUpdateGroupCaseBuilder()
.setFlatBatchUpdateGroup(flatBatchUpdateGroupBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
}
}
return order;
}
@VisibleForTesting
static int assembleRemoveGroups(final List<Batch> batchBag, int batchOrder, final List<ItemSyncBox<Group>> groupsToRemoveOrUpdate) {
// process group add+update
int order = batchOrder;
if (groupsToRemoveOrUpdate != null) {
for (ItemSyncBox<Group> groupItemSyncBox : groupsToRemoveOrUpdate) {
if (!groupItemSyncBox.getItemsToPush().isEmpty()) {
final List<FlatBatchRemoveGroup> flatBatchRemoveGroupBag =
new ArrayList<>(groupItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (Group group : groupItemSyncBox.getItemsToPush()) {
flatBatchRemoveGroupBag.add(new FlatBatchRemoveGroupBuilder(group).setBatchOrder(itemOrder++).build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchRemoveGroupCaseBuilder()
.setFlatBatchRemoveGroup(flatBatchRemoveGroupBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
}
}
return order;
}
@VisibleForTesting
static int assembleAddOrUpdateMeters(final List<Batch> batchBag, int batchOrder, final ItemSyncBox<Meter> meterItemSyncBox) {
// process meter add+update
int order = batchOrder;
if (meterItemSyncBox != null) {
if (!meterItemSyncBox.getItemsToPush().isEmpty()) {
final List<FlatBatchAddMeter> flatBatchAddMeterBag =
new ArrayList<>(meterItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (Meter meter : meterItemSyncBox.getItemsToPush()) {
flatBatchAddMeterBag.add(new FlatBatchAddMeterBuilder(meter).setBatchOrder(itemOrder++).build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchAddMeterCaseBuilder()
.setFlatBatchAddMeter(flatBatchAddMeterBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
if (!meterItemSyncBox.getItemsToUpdate().isEmpty()) {
final List<FlatBatchUpdateMeter> flatBatchUpdateMeterBag =
new ArrayList<>(meterItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (ItemSyncBox.ItemUpdateTuple<Meter> meterUpdate : meterItemSyncBox.getItemsToUpdate()) {
flatBatchUpdateMeterBag.add(new FlatBatchUpdateMeterBuilder()
.setBatchOrder(itemOrder++)
.setOriginalBatchedMeter(new OriginalBatchedMeterBuilder(meterUpdate.getOriginal()).build())
.setUpdatedBatchedMeter(new UpdatedBatchedMeterBuilder(meterUpdate.getUpdated()).build())
.build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchUpdateMeterCaseBuilder()
.setFlatBatchUpdateMeter(flatBatchUpdateMeterBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
}
return order;
}
@VisibleForTesting
static int assembleRemoveMeters(final List<Batch> batchBag, int batchOrder, final ItemSyncBox<Meter> meterItemSyncBox) {
// process meter remove
int order = batchOrder;
if (meterItemSyncBox != null && !meterItemSyncBox.getItemsToPush().isEmpty()) {
final List<FlatBatchRemoveMeter> flatBatchRemoveMeterBag =
new ArrayList<>(meterItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (Meter meter : meterItemSyncBox.getItemsToPush()) {
flatBatchRemoveMeterBag.add(new FlatBatchRemoveMeterBuilder(meter).setBatchOrder(itemOrder++).build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchRemoveMeterCaseBuilder()
.setFlatBatchRemoveMeter(flatBatchRemoveMeterBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
return order;
}
@VisibleForTesting
static int assembleAddOrUpdateFlows(final List<Batch> batchBag, int batchOrder, final Map<TableKey, ItemSyncBox<Flow>> flowItemSyncTableMap) {
// process flow add+update
int order = batchOrder;
if (flowItemSyncTableMap != null) {
for (Map.Entry<TableKey, ItemSyncBox<Flow>> syncBoxEntry : flowItemSyncTableMap.entrySet()) {
final ItemSyncBox<Flow> flowItemSyncBox = syncBoxEntry.getValue();
if (!flowItemSyncBox.getItemsToPush().isEmpty()) {
final List<FlatBatchAddFlow> flatBatchAddFlowBag =
new ArrayList<>(flowItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (Flow flow : flowItemSyncBox.getItemsToPush()) {
flatBatchAddFlowBag.add(new FlatBatchAddFlowBuilder(flow)
.setBatchOrder(itemOrder++)
.setFlowId(flow.getId())
.build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchAddFlowCaseBuilder()
.setFlatBatchAddFlow(flatBatchAddFlowBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
if (!flowItemSyncBox.getItemsToUpdate().isEmpty()) {
final List<FlatBatchUpdateFlow> flatBatchUpdateFlowBag =
new ArrayList<>(flowItemSyncBox.getItemsToUpdate().size());
int itemOrder = 0;
for (ItemSyncBox.ItemUpdateTuple<Flow> flowUpdate : flowItemSyncBox.getItemsToUpdate()) {
flatBatchUpdateFlowBag.add(new FlatBatchUpdateFlowBuilder()
.setBatchOrder(itemOrder++)
.setFlowId(flowUpdate.getUpdated().getId())
.setOriginalBatchedFlow(new OriginalBatchedFlowBuilder(flowUpdate.getOriginal()).build())
.setUpdatedBatchedFlow(new UpdatedBatchedFlowBuilder(flowUpdate.getUpdated()).build())
.build());
}
final Batch batch = new BatchBuilder()
.setBatchChoice(new FlatBatchUpdateFlowCaseBuilder()
.setFlatBatchUpdateFlow(flatBatchUpdateFlowBag)
.build())
.setBatchOrder(order)
.build();
order += itemOrder;
batchBag.add(batch);
}
}
}
return order;
}
public SyncPlanPushStrategyFlatBatchImpl setFlatBatchService(final SalFlatBatchService flatBatchService) {
this.flatBatchService = flatBatchService;
return this;
}
public SyncPlanPushStrategyFlatBatchImpl setTableForwarder(final TableForwarder tableForwarder) {
this.tableForwarder = tableForwarder;
return this;
}
}