Use ByteBuf.readRetainedSlice()
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / FlatBatchUtil.java
index 8bd950cff20db5d2953346b11f69986ad0ab8ea0..25f1179612805e05f5b5a69e90e2eee6ea89db89 100644 (file)
@@ -12,42 +12,42 @@ 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 com.google.common.util.concurrent.MoreExecutors;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.EnumSet;
 import java.util.List;
+import java.util.Map;
 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.flat.batch.flow.crud._case.aug.FlatBatchAddFlowCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchRemoveFlowCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.flow.crud._case.aug.FlatBatchUpdateFlowCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchAddGroupCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchRemoveGroupCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.group.crud._case.aug.FlatBatchUpdateGroupCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchAddMeterCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchRemoveMeterCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flat.batch.service.rev160321.flat.batch.meter.crud._case.aug.FlatBatchUpdateMeterCase;
 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.flat.batch.service.rev160321.process.flat.batch.output.BatchFailureKey;
 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.binding.util.BindingMap;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
- * provides flat batch util methods
+ * Provides flat batch util methods.
  */
 public final class FlatBatchUtil {
-
-    private static final Logger LOG = LoggerFactory.getLogger(FlatBatchUtil.class);
-
     private FlatBatchUtil() {
-        throw new IllegalStateException("This class should not be instantiated.");
+        // Hidden on purpose
     }
 
     public static void markBarriersWhereNeeded(final List<BatchPlanStep> batchPlan) {
@@ -67,34 +67,36 @@ public final class FlatBatchUtil {
 
     @VisibleForTesting
     static boolean decideBarrier(final EnumSet<BatchStepType> previousTypes, final BatchStepType type) {
-        final boolean needBarrier;
-        switch (type) {
-            case FLOW_ADD:
-            case FLOW_UPDATE:
-                needBarrier = previousTypes.contains(BatchStepType.GROUP_ADD)
-                        || previousTypes.contains(BatchStepType.METER_ADD);
-                break;
-            case GROUP_ADD:
-                needBarrier = previousTypes.contains(BatchStepType.GROUP_ADD)
-                        || previousTypes.contains(BatchStepType.GROUP_UPDATE);
-                break;
-            case GROUP_REMOVE:
-                needBarrier = previousTypes.contains(BatchStepType.FLOW_REMOVE)
-                        || previousTypes.contains(BatchStepType.FLOW_UPDATE)
-                        || previousTypes.contains(BatchStepType.GROUP_REMOVE)
-                        || previousTypes.contains(BatchStepType.GROUP_UPDATE);
-                break;
-            case METER_REMOVE:
-                needBarrier = previousTypes.contains(BatchStepType.FLOW_REMOVE)
-                        || previousTypes.contains(BatchStepType.FLOW_UPDATE);
-                break;
-            default:
-                needBarrier = false;
-        }
-        return needBarrier;
+        return isFlowBarrierNeeded(previousTypes, type)
+                || isGroupBarrierNeeded(previousTypes, type)
+                || isMeterBarrierNeeded(previousTypes, type);
     }
 
-    public static List<BatchPlanStep> assembleBatchPlan(List<Batch> batches) {
+    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(final Collection<Batch> batches) {
         final List<BatchPlanStep> plan = new ArrayList<>();
 
         BatchPlanStep planStep;
@@ -111,36 +113,36 @@ public final class FlatBatchUtil {
         return plan;
     }
 
-    private static List<? extends BatchOrderGrouping> extractBatchData(final BatchStepType batchStepType,
+    private static Collection<? extends BatchOrderGrouping> extractBatchData(final BatchStepType batchStepType,
                                                                        final BatchChoice batchChoice) {
-        final List<? extends BatchOrderGrouping> batchData;
+        final Collection<? extends BatchOrderGrouping> batchData;
         switch (batchStepType) {
             case FLOW_ADD:
-                batchData = ((FlatBatchAddFlowCase) batchChoice).getFlatBatchAddFlow();
+                batchData = ((FlatBatchAddFlowCase) batchChoice).nonnullFlatBatchAddFlow().values();
                 break;
             case FLOW_REMOVE:
-                batchData = ((FlatBatchRemoveFlowCase) batchChoice).getFlatBatchRemoveFlow();
+                batchData = ((FlatBatchRemoveFlowCase) batchChoice).nonnullFlatBatchRemoveFlow().values();
                 break;
             case FLOW_UPDATE:
-                batchData = ((FlatBatchUpdateFlowCase) batchChoice).getFlatBatchUpdateFlow();
+                batchData = ((FlatBatchUpdateFlowCase) batchChoice).nonnullFlatBatchUpdateFlow().values();
                 break;
             case GROUP_ADD:
-                batchData = ((FlatBatchAddGroupCase) batchChoice).getFlatBatchAddGroup();
+                batchData = ((FlatBatchAddGroupCase) batchChoice).nonnullFlatBatchAddGroup().values();
                 break;
             case GROUP_REMOVE:
-                batchData = ((FlatBatchRemoveGroupCase) batchChoice).getFlatBatchRemoveGroup();
+                batchData = ((FlatBatchRemoveGroupCase) batchChoice).nonnullFlatBatchRemoveGroup().values();
                 break;
             case GROUP_UPDATE:
-                batchData = ((FlatBatchUpdateGroupCase) batchChoice).getFlatBatchUpdateGroup();
+                batchData = ((FlatBatchUpdateGroupCase) batchChoice).nonnullFlatBatchUpdateGroup().values();
                 break;
             case METER_ADD:
-                batchData = ((FlatBatchAddMeterCase) batchChoice).getFlatBatchAddMeter();
+                batchData = ((FlatBatchAddMeterCase) batchChoice).nonnullFlatBatchAddMeter().values();
                 break;
             case METER_REMOVE:
-                batchData = ((FlatBatchRemoveMeterCase) batchChoice).getFlatBatchRemoveMeter();
+                batchData = ((FlatBatchRemoveMeterCase) batchChoice).nonnullFlatBatchRemoveMeter().values();
                 break;
             case METER_UPDATE:
-                batchData = ((FlatBatchUpdateMeterCase) batchChoice).getFlatBatchUpdateMeter();
+                batchData = ((FlatBatchUpdateMeterCase) batchChoice).nonnullFlatBatchUpdateMeter().values();
                 break;
             default:
                 throw new IllegalArgumentException("Unsupported batch step type obtained: " + batchStepType);
@@ -151,8 +153,9 @@ public final class FlatBatchUtil {
     @VisibleForTesting
     static <T extends BatchChoice> BatchStepType detectBatchStepType(final T batchCase) {
         final BatchStepType type;
-        final Class<? extends DataContainer> implementedInterface = batchCase.getImplementedInterface();
+        final Class<? extends DataContainer> implementedInterface = batchCase.implementedInterface();
 
+        // FIXME: use a lookup table instead of this cascade
         if (FlatBatchAddFlowCase.class.equals(implementedInterface)) {
             type = BatchStepType.FLOW_ADD;
         } else if (FlatBatchRemoveFlowCase.class.equals(implementedInterface)) {
@@ -177,41 +180,50 @@ public final class FlatBatchUtil {
         return type;
     }
 
-    /**
-     * @return RPC result incorporating partial results (state, errors, batch failures)
-     */
     @VisibleForTesting
     static Function<List<RpcResult<ProcessFlatBatchOutput>>, RpcResult<ProcessFlatBatchOutput>> mergeRpcResults() {
         return jobsResults -> {
             boolean isSuccessful = true;
             List<RpcError> rpcErrors = new ArrayList<>();
-            List<BatchFailure> batchFailures = new ArrayList<>();
+            BindingMap.Builder<BatchFailureKey, BatchFailure> batchFailures = BindingMap.orderedBuilder();
 
             for (RpcResult<ProcessFlatBatchOutput> jobResult : jobsResults) {
                 if (jobResult != null) {
-                    isSuccessful = (isSuccessful && jobResult.isSuccessful());
+                    isSuccessful = isSuccessful && jobResult.isSuccessful();
                     rpcErrors.addAll(jobResult.getErrors());
-                    batchFailures.addAll(jobResult.getResult().getBatchFailure());
+                    batchFailures.addAll(jobResult.getResult().nonnullBatchFailure().values());
                 }
             }
 
             return RpcResultBuilder.<ProcessFlatBatchOutput>status(isSuccessful)
                     .withRpcErrors(rpcErrors)
-                    .withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(batchFailures).build())
+                    .withResult(new ProcessFlatBatchOutputBuilder().setBatchFailure(batchFailures.build()).build())
                     .build();
         };
     }
 
     /**
      * Merge list of Futures with partial results into one ListenableFuture with single result.
-     * shortcut for {@link #mergeRpcResults()}
      * @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());
+        return Futures.transform(Futures.successfulAsList(firedJobs),
+                mergeRpcResults(),
+                MoreExecutors.directExecutor());
     }
 
-
+    /**
+     * 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(Map.of()).build())
+                               .buildFuture();
+    }
 }