Bump MRI upstreams
[openflowplugin.git] / applications / forwardingrules-sync / src / main / java / org / opendaylight / openflowplugin / applications / frsync / impl / strategy / SyncPlanPushStrategyFlatBatchImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.openflowplugin.applications.frsync.impl.strategy;
9
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.collect.Iterators;
12 import com.google.common.collect.PeekingIterator;
13 import com.google.common.collect.Range;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 import org.opendaylight.openflowplugin.applications.frsync.SyncPlanPushStrategy;
24 import org.opendaylight.openflowplugin.applications.frsync.util.ItemSyncBox;
25 import org.opendaylight.openflowplugin.applications.frsync.util.PathUtil;
26 import org.opendaylight.openflowplugin.applications.frsync.util.ReconcileUtil;
27 import org.opendaylight.openflowplugin.applications.frsync.util.SyncCrudCounters;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.ProcessFlatBatchOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.SalFlatBatchService;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchAddFlowCase;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchAddFlowCaseBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchRemoveFlowCase;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchRemoveFlowCaseBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchUpdateFlowCase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchUpdateFlowCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.add.flow._case.FlatBatchAddFlow;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.add.flow._case.FlatBatchAddFlowBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.add.flow._case.FlatBatchAddFlowKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.remove.flow._case.FlatBatchRemoveFlow;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.remove.flow._case.FlatBatchRemoveFlowBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.remove.flow._case.FlatBatchRemoveFlowKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.update.flow._case.FlatBatchUpdateFlow;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.update.flow._case.FlatBatchUpdateFlowBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.flat.batch.update.flow._case.FlatBatchUpdateFlowKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchAddGroupCase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchAddGroupCaseBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchRemoveGroupCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchRemoveGroupCaseBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchUpdateGroupCase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchUpdateGroupCaseBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.add.group._case.FlatBatchAddGroup;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.add.group._case.FlatBatchAddGroupBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.add.group._case.FlatBatchAddGroupKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.remove.group._case.FlatBatchRemoveGroup;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.remove.group._case.FlatBatchRemoveGroupBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.remove.group._case.FlatBatchRemoveGroupKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.update.group._case.FlatBatchUpdateGroup;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.update.group._case.FlatBatchUpdateGroupBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.flat.batch.update.group._case.FlatBatchUpdateGroupKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchAddMeterCase;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchAddMeterCaseBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchRemoveMeterCase;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchRemoveMeterCaseBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchUpdateMeterCase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchUpdateMeterCaseBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.add.meter._case.FlatBatchAddMeter;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.add.meter._case.FlatBatchAddMeterBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.add.meter._case.FlatBatchAddMeterKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.remove.meter._case.FlatBatchRemoveMeter;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.remove.meter._case.FlatBatchRemoveMeterBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.remove.meter._case.FlatBatchRemoveMeterKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.update.meter._case.FlatBatchUpdateMeter;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.update.meter._case.FlatBatchUpdateMeterBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.flat.batch.update.meter._case.FlatBatchUpdateMeterKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.Batch;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.BatchBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.input.batch.BatchChoice;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.process.flat.batch.output.BatchFailure;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.batch.flow.input.update.grouping.OriginalBatchedFlowBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.flows.service.rev160314.batch.flow.input.update.grouping.UpdatedBatchedFlowBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.input.update.grouping.OriginalBatchedGroupBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.groups.service.rev160315.batch.group.input.update.grouping.UpdatedBatchedGroupBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.input.update.grouping.OriginalBatchedMeterBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.meters.service.rev160316.batch.meter.input.update.grouping.UpdatedBatchedMeterBuilder;
92 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
93 import org.opendaylight.yangtools.yang.binding.util.BindingMap.Builder;
94 import org.opendaylight.yangtools.yang.common.RpcResult;
95 import org.opendaylight.yangtools.yang.common.Uint16;
96 import org.slf4j.Logger;
97 import org.slf4j.LoggerFactory;
98
99 /**
100  * Execute CRUD API for flow + group + meter involving flat-batch strategy.
101  */
102 public class SyncPlanPushStrategyFlatBatchImpl implements SyncPlanPushStrategy {
103
104     private static final Logger LOG = LoggerFactory.getLogger(SyncPlanPushStrategyFlatBatchImpl.class);
105
106     private SalFlatBatchService flatBatchService;
107     private TableForwarder tableForwarder;
108
109     @Override
110     public ListenableFuture<RpcResult<Void>> executeSyncStrategy(ListenableFuture<RpcResult<Void>> resultVehicle,
111                                                                  final SynchronizationDiffInput diffInput,
112                                                                  final SyncCrudCounters counters) {
113         // prepare default (full) counts
114         counters.getGroupCrudCounts().setAdded(ReconcileUtil.countTotalPushed(diffInput.getGroupsToAddOrUpdate()));
115         counters.getGroupCrudCounts().setUpdated(ReconcileUtil.countTotalUpdated(diffInput.getGroupsToAddOrUpdate()));
116         counters.getGroupCrudCounts().setRemoved(ReconcileUtil.countTotalPushed(diffInput.getGroupsToRemove()));
117
118         counters.getFlowCrudCounts().setAdded(ReconcileUtil.countTotalPushed(
119                 diffInput.getFlowsToAddOrUpdate().values()));
120         counters.getFlowCrudCounts().setUpdated(ReconcileUtil.countTotalUpdated(
121                 diffInput.getFlowsToAddOrUpdate().values()));
122         counters.getFlowCrudCounts().setRemoved(ReconcileUtil.countTotalPushed(diffInput.getFlowsToRemove().values()));
123
124         counters.getMeterCrudCounts().setAdded(diffInput.getMetersToAddOrUpdate().getItemsToPush().size());
125         counters.getMeterCrudCounts().setUpdated(diffInput.getMetersToAddOrUpdate().getItemsToUpdate().size());
126         counters.getMeterCrudCounts().setRemoved(diffInput.getMetersToRemove().getItemsToPush().size());
127
128         /* Tables - have to be pushed before groups */
129         // TODO enable table-update when ready
130         //resultVehicle = updateTableFeatures(nodeIdent, configTree);
131
132         resultVehicle = Futures.transformAsync(resultVehicle, input -> {
133             final List<Batch> batchBag = new ArrayList<>();
134             int batchOrder = 0;
135
136             batchOrder = assembleAddOrUpdateGroups(batchBag, batchOrder, diffInput.getGroupsToAddOrUpdate());
137             batchOrder = assembleAddOrUpdateMeters(batchBag, batchOrder, diffInput.getMetersToAddOrUpdate());
138             batchOrder = assembleAddOrUpdateFlows(batchBag, batchOrder, diffInput.getFlowsToAddOrUpdate());
139
140             batchOrder = assembleRemoveFlows(batchBag, batchOrder, diffInput.getFlowsToRemove());
141             batchOrder = assembleRemoveMeters(batchBag, batchOrder, diffInput.getMetersToRemove());
142             batchOrder = assembleRemoveGroups(batchBag, batchOrder, diffInput.getGroupsToRemove());
143
144             LOG.trace("Index of last batch step: {}", batchOrder);
145
146             final ProcessFlatBatchInput flatBatchInput = new ProcessFlatBatchInputBuilder()
147                     .setNode(new NodeRef(PathUtil.digNodePath(diffInput.getNodeIdent())))
148                     // TODO: propagate from input
149                     .setExitOnFirstError(false)
150                     .setBatch(BindingMap.ordered(batchBag))
151                     .build();
152
153             final ListenableFuture<RpcResult<ProcessFlatBatchOutput>> rpcResultFuture =
154                     flatBatchService.processFlatBatch(flatBatchInput);
155
156             if (LOG.isDebugEnabled()) {
157                 Futures.addCallback(rpcResultFuture, createCounterCallback(batchBag, batchOrder, counters),
158                     MoreExecutors.directExecutor());
159             }
160
161             return Futures.transform(rpcResultFuture,
162                     ReconcileUtil.createRpcResultToVoidFunction("flat-batch"),
163                     MoreExecutors.directExecutor());
164         }, MoreExecutors.directExecutor());
165         return resultVehicle;
166     }
167
168     private static FutureCallback<RpcResult<ProcessFlatBatchOutput>> createCounterCallback(
169             final List<Batch> inputBatchBag, final int failureIndexLimit, final SyncCrudCounters counters) {
170         return new FutureCallback<>() {
171             @Override
172             public void onSuccess(final RpcResult<ProcessFlatBatchOutput> result) {
173                 if (!result.isSuccessful() && result.getResult() != null
174                         && !result.getResult().nonnullBatchFailure().isEmpty()) {
175                     Map<Range<Uint16>, Batch> batchMap = mapBatchesToRanges(inputBatchBag, failureIndexLimit);
176                     decrementBatchFailuresCounters(result.getResult().nonnullBatchFailure().values(), batchMap,
177                             counters);
178                 }
179             }
180
181             @Override
182             public void onFailure(final Throwable failure) {
183                 counters.resetAll();
184             }
185         };
186     }
187
188     private static void decrementBatchFailuresCounters(final Collection<BatchFailure> batchFailures,
189                                                 final Map<Range<Uint16>, Batch> batchMap,
190                                                 final SyncCrudCounters counters) {
191         for (BatchFailure batchFailure : batchFailures) {
192             for (Map.Entry<Range<Uint16>, Batch> rangeBatchEntry : batchMap.entrySet()) {
193                 if (rangeBatchEntry.getKey().contains(batchFailure.getBatchOrder())) {
194                     // get type and decrease
195                     final BatchChoice batchChoice = rangeBatchEntry.getValue().getBatchChoice();
196                     decrementCounters(batchChoice, counters);
197                     break;
198                 }
199             }
200         }
201     }
202
203     static void decrementCounters(final BatchChoice batchChoice, final SyncCrudCounters counters) {
204         if (batchChoice instanceof FlatBatchAddFlowCase) {
205             counters.getFlowCrudCounts().decAdded();
206         } else if (batchChoice instanceof FlatBatchUpdateFlowCase) {
207             counters.getFlowCrudCounts().decUpdated();
208         } else if (batchChoice instanceof FlatBatchRemoveFlowCase) {
209             counters.getFlowCrudCounts().decRemoved();
210         } else if (batchChoice instanceof FlatBatchAddGroupCase) {
211             counters.getGroupCrudCounts().decAdded();
212         } else if (batchChoice instanceof FlatBatchUpdateGroupCase) {
213             counters.getGroupCrudCounts().decUpdated();
214         } else if (batchChoice instanceof FlatBatchRemoveGroupCase) {
215             counters.getGroupCrudCounts().decRemoved();
216         } else if (batchChoice instanceof FlatBatchAddMeterCase) {
217             counters.getMeterCrudCounts().decAdded();
218         } else if (batchChoice instanceof FlatBatchUpdateMeterCase) {
219             counters.getMeterCrudCounts().decUpdated();
220         } else if (batchChoice instanceof FlatBatchRemoveMeterCase) {
221             counters.getMeterCrudCounts().decRemoved();
222         }
223     }
224
225     static Map<Range<Uint16>, Batch> mapBatchesToRanges(final List<Batch> inputBatchBag, final int failureIndexLimit) {
226         final Map<Range<Uint16>, Batch> batchMap = new LinkedHashMap<>();
227         final PeekingIterator<Batch> batchPeekingIterator = Iterators.peekingIterator(inputBatchBag.iterator());
228         while (batchPeekingIterator.hasNext()) {
229             final Batch batch = batchPeekingIterator.next();
230             final int nextBatchOrder = batchPeekingIterator.hasNext()
231                     ? batchPeekingIterator.peek().getBatchOrder().toJava()
232                     : failureIndexLimit;
233             batchMap.put(Range.closed(batch.getBatchOrder(), Uint16.valueOf(nextBatchOrder - 1)), batch);
234         }
235         return batchMap;
236     }
237
238     @VisibleForTesting
239     static int assembleRemoveFlows(final List<Batch> batchBag, final int batchOrder,
240             final Map<TableKey, ItemSyncBox<Flow>> flowItemSyncTableMap) {
241         // process flow remove
242         int order = batchOrder;
243         if (flowItemSyncTableMap != null) {
244             for (Map.Entry<TableKey, ItemSyncBox<Flow>> syncBoxEntry : flowItemSyncTableMap.entrySet()) {
245                 final ItemSyncBox<Flow> flowItemSyncBox = syncBoxEntry.getValue();
246
247                 if (!flowItemSyncBox.getItemsToPush().isEmpty()) {
248                     final Builder<FlatBatchRemoveFlowKey, FlatBatchRemoveFlow> flatBatchRemoveFlowBag =
249                             BindingMap.orderedBuilder(flowItemSyncBox.getItemsToUpdate().size());
250                     int itemOrder = 0;
251                     for (Flow flow : flowItemSyncBox.getItemsToPush()) {
252                         flatBatchRemoveFlowBag.add(new FlatBatchRemoveFlowBuilder(flow)
253                                 .setBatchOrder(Uint16.valueOf(itemOrder++))
254                                 .setFlowId(flow.getId())
255                                 .build());
256                     }
257                     final Batch batch = new BatchBuilder()
258                             .setBatchChoice(new FlatBatchRemoveFlowCaseBuilder()
259                                     .setFlatBatchRemoveFlow(flatBatchRemoveFlowBag.build())
260                                     .build())
261                             .setBatchOrder(Uint16.valueOf(order))
262                             .build();
263                     order += itemOrder;
264                     batchBag.add(batch);
265                 }
266             }
267         }
268         return order;
269     }
270
271     @VisibleForTesting
272     static int assembleAddOrUpdateGroups(final List<Batch> batchBag, final int batchOrder,
273             final List<ItemSyncBox<Group>> groupsToAddOrUpdate) {
274         // process group add+update
275         int order = batchOrder;
276         if (groupsToAddOrUpdate != null) {
277             for (ItemSyncBox<Group> groupItemSyncBox : groupsToAddOrUpdate) {
278                 if (!groupItemSyncBox.getItemsToPush().isEmpty()) {
279                     final Builder<FlatBatchAddGroupKey, FlatBatchAddGroup> flatBatchAddGroupBag =
280                         BindingMap.orderedBuilder(groupItemSyncBox.getItemsToPush().size());
281                     int itemOrder = 0;
282                     for (Group group : groupItemSyncBox.getItemsToPush()) {
283                         flatBatchAddGroupBag.add(new FlatBatchAddGroupBuilder(group)
284                                 .setBatchOrder(Uint16.valueOf(itemOrder++)).build());
285                     }
286                     final Batch batch = new BatchBuilder()
287                             .setBatchChoice(new FlatBatchAddGroupCaseBuilder()
288                                     .setFlatBatchAddGroup(flatBatchAddGroupBag.build())
289                                     .build())
290                             .setBatchOrder(Uint16.valueOf(order))
291                             .build();
292                     order += itemOrder;
293                     batchBag.add(batch);
294                 }
295
296                 if (!groupItemSyncBox.getItemsToUpdate().isEmpty()) {
297                     final Builder<FlatBatchUpdateGroupKey, FlatBatchUpdateGroup> flatBatchUpdateGroupBag =
298                         BindingMap.orderedBuilder(groupItemSyncBox.getItemsToUpdate().size());
299                     int itemOrder = 0;
300                     for (ItemSyncBox.ItemUpdateTuple<Group> groupUpdate : groupItemSyncBox.getItemsToUpdate()) {
301                         flatBatchUpdateGroupBag.add(new FlatBatchUpdateGroupBuilder()
302                             .setBatchOrder(Uint16.valueOf(itemOrder++))
303                             .setOriginalBatchedGroup(new OriginalBatchedGroupBuilder(groupUpdate.getOriginal()).build())
304                             .setUpdatedBatchedGroup(new UpdatedBatchedGroupBuilder(groupUpdate.getUpdated()).build())
305                             .build());
306                     }
307                     final Batch batch = new BatchBuilder()
308                             .setBatchChoice(new FlatBatchUpdateGroupCaseBuilder()
309                                     .setFlatBatchUpdateGroup(flatBatchUpdateGroupBag.build())
310                                     .build())
311                             .setBatchOrder(Uint16.valueOf(order))
312                             .build();
313                     order += itemOrder;
314                     batchBag.add(batch);
315                 }
316             }
317         }
318         return order;
319     }
320
321     @VisibleForTesting
322     static int assembleRemoveGroups(final List<Batch> batchBag, final int batchOrder,
323             final List<ItemSyncBox<Group>> groupsToRemoveOrUpdate) {
324         // process group add+update
325         int order = batchOrder;
326         if (groupsToRemoveOrUpdate != null) {
327             for (ItemSyncBox<Group> groupItemSyncBox : groupsToRemoveOrUpdate) {
328                 if (!groupItemSyncBox.getItemsToPush().isEmpty()) {
329                     final Builder<FlatBatchRemoveGroupKey, FlatBatchRemoveGroup> flatBatchRemoveGroupBag =
330                         BindingMap.orderedBuilder(groupItemSyncBox.getItemsToUpdate().size());
331                     int itemOrder = 0;
332                     for (Group group : groupItemSyncBox.getItemsToPush()) {
333                         flatBatchRemoveGroupBag.add(new FlatBatchRemoveGroupBuilder(group)
334                                 .setBatchOrder(Uint16.valueOf(itemOrder++)).build());
335                     }
336                     final Batch batch = new BatchBuilder()
337                             .setBatchChoice(new FlatBatchRemoveGroupCaseBuilder()
338                                     .setFlatBatchRemoveGroup(flatBatchRemoveGroupBag.build())
339                                     .build())
340                             .setBatchOrder(Uint16.valueOf(order))
341                             .build();
342                     order += itemOrder;
343                     batchBag.add(batch);
344                 }
345             }
346         }
347         return order;
348     }
349
350     @VisibleForTesting
351     static int assembleAddOrUpdateMeters(final List<Batch> batchBag, final int batchOrder,
352             final ItemSyncBox<Meter> meterItemSyncBox) {
353         // process meter add+update
354         int order = batchOrder;
355         if (meterItemSyncBox != null) {
356             if (!meterItemSyncBox.getItemsToPush().isEmpty()) {
357                 final Builder<FlatBatchAddMeterKey, FlatBatchAddMeter> flatBatchAddMeterBag =
358                     BindingMap.orderedBuilder(meterItemSyncBox.getItemsToPush().size());
359                 int itemOrder = 0;
360                 for (Meter meter : meterItemSyncBox.getItemsToPush()) {
361                     flatBatchAddMeterBag.add(new FlatBatchAddMeterBuilder(meter)
362                         .setBatchOrder(Uint16.valueOf(itemOrder++))
363                         .build());
364                 }
365                 final Batch batch = new BatchBuilder()
366                         .setBatchChoice(new FlatBatchAddMeterCaseBuilder()
367                                 .setFlatBatchAddMeter(flatBatchAddMeterBag.build())
368                                 .build())
369                         .setBatchOrder(Uint16.valueOf(order))
370                         .build();
371                 order += itemOrder;
372                 batchBag.add(batch);
373             }
374
375             if (!meterItemSyncBox.getItemsToUpdate().isEmpty()) {
376                 final Builder<FlatBatchUpdateMeterKey, FlatBatchUpdateMeter> flatBatchUpdateMeterBag =
377                         BindingMap.orderedBuilder(meterItemSyncBox.getItemsToUpdate().size());
378                 int itemOrder = 0;
379                 for (ItemSyncBox.ItemUpdateTuple<Meter> meterUpdate : meterItemSyncBox.getItemsToUpdate()) {
380                     flatBatchUpdateMeterBag.add(new FlatBatchUpdateMeterBuilder()
381                             .setBatchOrder(Uint16.valueOf(itemOrder++))
382                             .setOriginalBatchedMeter(new OriginalBatchedMeterBuilder(meterUpdate.getOriginal()).build())
383                             .setUpdatedBatchedMeter(new UpdatedBatchedMeterBuilder(meterUpdate.getUpdated()).build())
384                             .build());
385                 }
386                 final Batch batch = new BatchBuilder()
387                         .setBatchChoice(new FlatBatchUpdateMeterCaseBuilder()
388                                 .setFlatBatchUpdateMeter(flatBatchUpdateMeterBag.build())
389                                 .build())
390                         .setBatchOrder(Uint16.valueOf(order))
391                         .build();
392                 order += itemOrder;
393                 batchBag.add(batch);
394             }
395         }
396         return order;
397     }
398
399     @VisibleForTesting
400     static int assembleRemoveMeters(final List<Batch> batchBag, final int batchOrder,
401             final ItemSyncBox<Meter> meterItemSyncBox) {
402         // process meter remove
403         int order = batchOrder;
404         if (meterItemSyncBox != null && !meterItemSyncBox.getItemsToPush().isEmpty()) {
405             final Builder<FlatBatchRemoveMeterKey, FlatBatchRemoveMeter> flatBatchRemoveMeterBag =
406                 BindingMap.orderedBuilder(meterItemSyncBox.getItemsToPush().size());
407             int itemOrder = 0;
408             for (Meter meter : meterItemSyncBox.getItemsToPush()) {
409                 flatBatchRemoveMeterBag.add(new FlatBatchRemoveMeterBuilder(meter)
410                     .setBatchOrder(Uint16.valueOf(itemOrder++))
411                     .build());
412             }
413             final Batch batch = new BatchBuilder()
414                     .setBatchChoice(new FlatBatchRemoveMeterCaseBuilder()
415                             .setFlatBatchRemoveMeter(flatBatchRemoveMeterBag.build())
416                             .build())
417                     .setBatchOrder(Uint16.valueOf(order))
418                     .build();
419             order += itemOrder;
420             batchBag.add(batch);
421         }
422         return order;
423     }
424
425     @VisibleForTesting
426     static int assembleAddOrUpdateFlows(final List<Batch> batchBag, final int batchOrder,
427             final Map<TableKey, ItemSyncBox<Flow>> flowItemSyncTableMap) {
428         // process flow add+update
429         int order = batchOrder;
430         if (flowItemSyncTableMap != null) {
431             for (Map.Entry<TableKey, ItemSyncBox<Flow>> syncBoxEntry : flowItemSyncTableMap.entrySet()) {
432                 final ItemSyncBox<Flow> flowItemSyncBox = syncBoxEntry.getValue();
433
434                 if (!flowItemSyncBox.getItemsToPush().isEmpty()) {
435                     final Builder<FlatBatchAddFlowKey, FlatBatchAddFlow> flatBatchAddFlowBag =
436                         BindingMap.orderedBuilder(flowItemSyncBox.getItemsToPush().size());
437                     int itemOrder = 0;
438                     for (Flow flow : flowItemSyncBox.getItemsToPush()) {
439                         flatBatchAddFlowBag.add(new FlatBatchAddFlowBuilder(flow)
440                                 .setBatchOrder(Uint16.valueOf(itemOrder++))
441                                 .setFlowId(flow.getId())
442                                 .build());
443                     }
444                     final Batch batch = new BatchBuilder()
445                             .setBatchChoice(new FlatBatchAddFlowCaseBuilder()
446                                     .setFlatBatchAddFlow(flatBatchAddFlowBag.build())
447                                     .build())
448                             .setBatchOrder(Uint16.valueOf(order))
449                             .build();
450                     order += itemOrder;
451                     batchBag.add(batch);
452                 }
453
454                 if (!flowItemSyncBox.getItemsToUpdate().isEmpty()) {
455                     final Builder<FlatBatchUpdateFlowKey, FlatBatchUpdateFlow> flatBatchUpdateFlowBag =
456                         BindingMap.orderedBuilder(flowItemSyncBox.getItemsToUpdate().size());
457                     int itemOrder = 0;
458                     for (ItemSyncBox.ItemUpdateTuple<Flow> flowUpdate : flowItemSyncBox.getItemsToUpdate()) {
459                         flatBatchUpdateFlowBag.add(new FlatBatchUpdateFlowBuilder()
460                             .setBatchOrder(Uint16.valueOf(itemOrder++))
461                             .setFlowId(flowUpdate.getUpdated().getId())
462                             .setOriginalBatchedFlow(new OriginalBatchedFlowBuilder(flowUpdate.getOriginal()).build())
463                             .setUpdatedBatchedFlow(new UpdatedBatchedFlowBuilder(flowUpdate.getUpdated()).build())
464                             .build());
465                     }
466                     final Batch batch = new BatchBuilder()
467                             .setBatchChoice(new FlatBatchUpdateFlowCaseBuilder()
468                                     .setFlatBatchUpdateFlow(flatBatchUpdateFlowBag.build())
469                                     .build())
470                             .setBatchOrder(Uint16.valueOf(order))
471                             .build();
472                     order += itemOrder;
473                     batchBag.add(batch);
474                 }
475             }
476         }
477         return order;
478     }
479
480     public SyncPlanPushStrategyFlatBatchImpl setFlatBatchService(final SalFlatBatchService flatBatchService) {
481         this.flatBatchService = flatBatchService;
482         return this;
483     }
484
485     public SyncPlanPushStrategyFlatBatchImpl setTableForwarder(final TableForwarder tableForwarder) {
486         this.tableForwarder = tableForwarder;
487         return this;
488     }
489 }