Update MRI upstreams for Phosphorus
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / flow / FlowConvertor.java
index 47a8a3f0111b9475169f999c0cdc1bd1f9aaeec5..0b14be3e17a103565bd1a4ee96c7c737b18dc917 100644 (file)
@@ -5,20 +5,23 @@
  * 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.openflow.md.core.sal.convertor.flow;
 
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
+import static java.util.Objects.requireNonNull;
+import static java.util.Objects.requireNonNullElse;
+
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Ordering;
-import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.action.data.ActionConvertorData;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ConvertorProcessor;
@@ -30,14 +33,13 @@ import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.MeterCase;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.WriteActionsCase;
 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.cases.WriteMetadataCase;
-import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.flowflag.FlowFlagReactor;
-import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchReactor;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchInjector;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.VlanCfi;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
@@ -52,6 +54,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.M
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
@@ -65,12 +68,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev13
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OxmMatchType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInputBuilder;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.util.BindingMap;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
+import org.opendaylight.yangtools.yang.common.Uint8;
 
 /**
  * Converts the SAL Flow to OF Flow. It checks if there is a set-vlan-id (1.0) action made on OF1.3.
  * If yes its handled separately.
  *
+ * <p>
  * Example usage:
  * <pre>
  * {@code
@@ -82,244 +90,193 @@ import org.opendaylight.yangtools.yang.binding.DataContainer;
  */
 public class FlowConvertor extends Convertor<Flow, List<FlowModInputBuilder>, VersionDatapathIdConvertorData> {
     /**
-     * Default idle timeout
+     * Default idle timeout.
      */
-    public static final Integer DEFAULT_IDLE_TIMEOUT = 0;
+    public static final Uint16 DEFAULT_IDLE_TIMEOUT = Uint16.ZERO;
+
     /**
-     * Default hard timeout
+     * Default hard timeout.
      */
-    public static final Integer DEFAULT_HARD_TIMEOUT = 0;
+    public static final Uint16 DEFAULT_HARD_TIMEOUT = Uint16.ZERO;
+
     /**
-     * Default priority
+     * Default priority.
      */
-    public static final Integer DEFAULT_PRIORITY = Integer.parseInt("8000", 16);
+    public static final Uint16 DEFAULT_PRIORITY = Uint16.valueOf(0x8000);
+
     /**
-     * flow flag: remove
+     * flow flag: remove.
      */
     public static final boolean DEFAULT_OFPFF_FLOW_REM = false;
+
     /**
-     * flow flag: check overlap
+     * flow flag: check overlap.
      */
     public static final boolean DEFAULT_OFPFF_CHECK_OVERLAP = false;
+
     /**
-     * flow flag: reset counts
+     * flow flag: reset counts.
      */
     public static final boolean DEFAULT_OFPFF_RESET_COUNTS = false;
+
     /**
-     * flow flag: don't keep track of packet counts
+     * flow flag: don't keep track of packet counts.
      */
     public static final boolean DEFAULT_OFPFF_NO_PKT_COUNTS = false;
+
     /**
-     * flow flag: don't keep track of byte counts
+     * flow flag: don't keep track of byte counts.
      */
     public static final boolean DEFAULT_OFPFF_NO_BYT_COUNTS = false;
+
     /**
-     * flow flag: emergency [OFP-1.0]
+     * flow flag: emergency [OFP-1.0].
      */
     public static final boolean DEFAULT_OFPFF_EMERGENCY = false;
+
     /**
-     * OxmMatch type
+     * OxmMatch type.
      */
     public static final Class<? extends MatchTypeBase> DEFAULT_MATCH_TYPE = OxmMatchType.class;
+
     /**
-     * default match entries - empty
+     * default match entries - empty.
      */
-    public static final List<MatchEntry> DEFAULT_MATCH_ENTRIES = new ArrayList<>();
+    public static final List<MatchEntry> DEFAULT_MATCH_ENTRIES = ImmutableList.of();
 
     // Default values for when things are null
-    private static final TableId DEFAULT_TABLE_ID = new TableId(0L);
-    private static final Long DEFAULT_BUFFER_ID = OFConstants.OFP_NO_BUFFER;
-    private static final Long OFPP_ANY = Long.parseLong("ffffffff", 16);
-    private static final Long DEFAULT_OUT_PORT = OFPP_ANY;
-    private static final Long OFPG_ANY = Long.parseLong("ffffffff", 16);
-    private static final Long DEFAULT_OUT_GROUP = OFPG_ANY;
-    private static final Integer PUSH_VLAN = 0x8100;
-    private static final Ordering<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> INSTRUCTION_ORDERING = Ordering.from(OrderComparator.build());
+    private static final TableId DEFAULT_TABLE_ID = new TableId(Uint32.ZERO);
+    private static final Uint32 DEFAULT_BUFFER_ID = OFConstants.OFP_NO_BUFFER;
+    private static final Uint32 OFPP_ANY = Uint32.MAX_VALUE;
+    private static final PortNumber DEFAULT_OUT_PORT = new PortNumber(OFPP_ANY);
+    private static final Uint32 OFPG_ANY = Uint32.MAX_VALUE;
+    private static final Uint32 DEFAULT_OUT_GROUP = OFPG_ANY;
+    private static final Uint16 PUSH_VLAN = Uint16.valueOf(0x8100);
+    private static final Integer PUSH_TAG = PUSH_VLAN.toJava();
+    private static final VlanCfi PUSH_CFI = new VlanCfi(1);
+    private static final Ordering<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction
+        .list.Instruction> INSTRUCTION_ORDERING = Ordering.from(OrderComparator.build());
     private static final VlanMatch VLAN_MATCH_FALSE;
     private static final VlanMatch VLAN_MATCH_TRUE;
-    private static final ConvertorProcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction, Instruction, ActionConvertorData> PROCESSOR = new ConvertorProcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction, Instruction, ActionConvertorData>()
+    private static final ConvertorProcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026
+        .instruction.Instruction, Instruction, ActionConvertorData> PROCESSOR =
+            new ConvertorProcessor<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026
+                .instruction.Instruction, Instruction, ActionConvertorData>()
             .addCase(new ApplyActionsCase())
             .addCase(new ClearActionsCase())
             .addCase(new GoToTableCase())
             .addCase(new MeterCase())
             .addCase(new WriteActionsCase())
             .addCase(new WriteMetadataCase());
-    private static final List<Class<? extends DataContainer>> TYPES = Arrays.asList(Flow.class, AddFlowInput.class, RemoveFlowInput.class, UpdatedFlow.class);
+
+    private static final List<Class<?>> TYPES = Arrays.asList(Flow.class, AddFlowInput.class,
+            RemoveFlowInput.class, UpdatedFlow.class);
 
     static {
-        final VlanId zeroVlan = new VlanId(0);
-        VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder();
-        VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
-        vlanIdBuilder.setVlanIdPresent(false);
-        vlanIdBuilder.setVlanId(zeroVlan);
-        vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
-
-        VLAN_MATCH_FALSE = vlanMatchBuilder.build();
-
-        VlanMatchBuilder vlanMatchBuilder2 = new VlanMatchBuilder();
-        VlanIdBuilder vlanIdBuilder2 = new VlanIdBuilder();
-        vlanIdBuilder2.setVlanIdPresent(true);
-        vlanIdBuilder2.setVlanId(zeroVlan);
-        vlanMatchBuilder2.setVlanId(vlanIdBuilder2.build());
-
-        VLAN_MATCH_TRUE = vlanMatchBuilder2.build();
+        final VlanId zeroVlan = new VlanId(Uint16.ZERO);
+        VLAN_MATCH_FALSE = new VlanMatchBuilder()
+            .setVlanId(new VlanIdBuilder().setVlanIdPresent(false).setVlanId(zeroVlan).build())
+            .build();
+        VLAN_MATCH_TRUE = new VlanMatchBuilder()
+            .setVlanId(new VlanIdBuilder().setVlanIdPresent(true).setVlanId(zeroVlan).build())
+            .build();
     }
 
-    private FlowModInputBuilder toFlowModInput(Flow flow, short version, BigInteger datapathid) {
+    private FlowModInputBuilder toFlowModInput(final Flow flow,
+            final VersionDatapathIdConvertorData versionConverterData) {
 
-        FlowModInputBuilder flowMod = new FlowModInputBuilder();
+        FlowModInputBuilder flowMod = new FlowModInputBuilder()
+            .setIdleTimeout(requireNonNullElse(flow.getIdleTimeout(), DEFAULT_IDLE_TIMEOUT))
+            .setHardTimeout(requireNonNullElse(flow.getHardTimeout(), DEFAULT_HARD_TIMEOUT))
+            .setPriority(requireNonNullElse(flow.getPriority(), DEFAULT_PRIORITY))
+            .setBufferId(requireNonNullElse(flow.getBufferId(), DEFAULT_BUFFER_ID))
+            .setOutGroup(requireNonNullElse(flow.getOutGroup(), DEFAULT_OUT_GROUP));
         salToOFFlowCookie(flow, flowMod);
         salToOFFlowCookieMask(flow, flowMod);
         salToOFFlowTableId(flow, flowMod);
         salToOFFlowCommand(flow, flowMod);
-        salToOFFlowIdleTimeout(flow, flowMod);
-        salToOFFlowHardTimeout(flow, flowMod);
-        salToOFFlowPriority(flow, flowMod);
-        salToOFFlowBufferId(flow, flowMod);
         salToOFFlowOutPort(flow, flowMod);
-        salToOFFlowOutGroup(flow, flowMod);
 
         // convert and inject flowFlags
-        FlowFlagReactor.getInstance().convert(flow.getFlags(), version, flowMod, getConvertorExecutor());
+        final Optional<Object> conversion = getConvertorExecutor().convert(flow.getFlags(), versionConverterData);
+        FlowFlagsInjector.inject(conversion, flowMod, versionConverterData.getVersion());
 
         // convert and inject match
-        MatchReactor.getInstance().convert(flow.getMatch(), version, flowMod, getConvertorExecutor());
+        final Optional<Object> conversionMatch = getConvertorExecutor().convert(flow.getMatch(), versionConverterData);
+        MatchInjector.inject(conversionMatch, flowMod, versionConverterData.getVersion());
 
         if (flow.getInstructions() != null) {
-            flowMod.setInstruction(toInstructions(flow, version, datapathid));
-            flowMod.setAction(getActions(version, datapathid, flow));
-        }
-
-        flowMod.setVersion(version);
-
-        return flowMod;
-    }
-
-    private static void salToOFFlowOutGroup(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getOutGroup() != null) {
-            flowMod.setOutGroup(flow.getOutGroup());
-        } else {
-            flowMod.setOutGroup(DEFAULT_OUT_GROUP);
-        }
-    }
-
-    private static void salToOFFlowOutPort(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getOutPort() != null) {
-            flowMod.setOutPort(new PortNumber(flow.getOutPort().longValue()));
-        } else {
-            flowMod.setOutPort(new PortNumber(DEFAULT_OUT_PORT));
-        }
-    }
-
-    private static void salToOFFlowBufferId(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getBufferId() != null) {
-            flowMod.setBufferId(flow.getBufferId());
-        } else {
-            flowMod.setBufferId(DEFAULT_BUFFER_ID);
-        }
-    }
-
-    private static void salToOFFlowPriority(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getPriority() != null) {
-            flowMod.setPriority(flow.getPriority());
-        } else {
-            flowMod.setPriority(DEFAULT_PRIORITY);
+            flowMod
+                .setInstruction(toInstructions(flow, versionConverterData.getVersion(),
+                    versionConverterData.getDatapathId()))
+                .setAction(getActions(versionConverterData.getVersion(), versionConverterData.getDatapathId(), flow));
         }
-    }
 
-    private static void salToOFFlowHardTimeout(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getHardTimeout() != null) {
-            flowMod.setHardTimeout(flow.getHardTimeout());
-        } else {
-            flowMod.setHardTimeout(DEFAULT_HARD_TIMEOUT);
-        }
+        return flowMod
+            .setVersion(versionConverterData.getVersion());
     }
 
-    private static void salToOFFlowIdleTimeout(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getIdleTimeout() != null) {
-            flowMod.setIdleTimeout(flow.getIdleTimeout());
-        } else {
-            flowMod.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
-        }
+    private static void salToOFFlowOutPort(final Flow flow, final FlowModInputBuilder flowMod) {
+        final var outPort = flow.getOutPort();
+        flowMod.setOutPort(outPort != null ? new PortNumber(outPort.toUint32()) : DEFAULT_OUT_PORT);
     }
 
-    private static void salToOFFlowCommand(Flow flow, FlowModInputBuilder flowMod) {
+    private static void salToOFFlowCommand(final Flow flow, final FlowModInputBuilder flowMod) {
         if (flow instanceof AddFlowInput || flow instanceof UpdatedFlow) {
             flowMod.setCommand(FlowModCommand.OFPFCADD);
         } else if (flow instanceof RemoveFlowInput) {
-            if (MoreObjects.firstNonNull(flow.isStrict(), Boolean.FALSE)) {
-                flowMod.setCommand(FlowModCommand.OFPFCDELETESTRICT);
-            } else {
-                flowMod.setCommand(FlowModCommand.OFPFCDELETE);
-            }
+            flowMod.setCommand(Boolean.TRUE.equals(flow.getStrict())
+                ? FlowModCommand.OFPFCDELETESTRICT : FlowModCommand.OFPFCDELETE);
         }
     }
 
-    private static void salToOFFlowTableId(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getTableId() != null) {
-            flowMod.setTableId(new TableId(flow.getTableId().longValue()));
-        } else {
-            flowMod.setTableId(DEFAULT_TABLE_ID);
-        }
+    private static void salToOFFlowTableId(final Flow flow, final FlowModInputBuilder flowMod) {
+        final var tableId = flow.getTableId();
+        flowMod.setTableId(tableId != null ? new TableId(flow.getTableId().toUint32()) : DEFAULT_TABLE_ID);
     }
 
-    private static void salToOFFlowCookieMask(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getCookieMask() != null) {
-            flowMod.setCookieMask(flow.getCookieMask().getValue());
-        } else {
-            flowMod.setCookieMask(OFConstants.DEFAULT_COOKIE_MASK);
-        }
+    private static void salToOFFlowCookieMask(final Flow flow, final FlowModInputBuilder flowMod) {
+        final var mask = flow.getCookieMask();
+        flowMod.setCookieMask(mask != null ? mask.getValue() : OFConstants.DEFAULT_COOKIE_MASK);
     }
 
-    private static void salToOFFlowCookie(Flow flow, FlowModInputBuilder flowMod) {
-        if (flow.getCookie() != null) {
-            flowMod.setCookie(flow.getCookie().getValue());
-        } else {
-            flowMod.setCookie(OFConstants.DEFAULT_COOKIE);
-        }
+    private static void salToOFFlowCookie(final Flow flow, final FlowModInputBuilder flowMod) {
+        final var omNomNom = flow.getCookie();
+        flowMod.setCookie(omNomNom != null ? omNomNom.getValue() : OFConstants.DEFAULT_COOKIE);
     }
 
-    private List<Instruction> toInstructions(Flow flow, short version, BigInteger datapathid) {
+    private List<Instruction> toInstructions(final Flow flow, final Uint8 version, final Uint64 datapathid) {
         final List<Instruction> instructionsList = new ArrayList<>();
         final ActionConvertorData data = new ActionConvertorData(version);
         data.setDatapathId(datapathid);
         data.setIpProtocol(FlowConvertorUtil.getIpProtocolFromFlow(flow));
 
-        Instructions instructions = flow.getInstructions();
-
-        for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction : instructions
-                .getInstruction()) {
-            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction = instruction
-                    .getInstruction();
-
-            Optional<Instruction> result = PROCESSOR.process(curInstruction, data, getConvertorExecutor());
-
-            if (result.isPresent()) {
-                instructionsList.add(result.get());
-            }
+        final ConvertorExecutor convertor = getConvertorExecutor();
+        for (var instruction : flow.getInstructions().nonnullInstruction().values()) {
+            Optional<Instruction> result = PROCESSOR.process(instruction.getInstruction(), data, convertor);
+            result.ifPresent(instructionsList::add);
         }
 
         return instructionsList;
     }
 
-    private List<Action> getActions(short version, BigInteger datapathid, Flow flow) {
+    private List<Action> getActions(final Uint8 version, final Uint64 datapathid, final Flow flow) {
         Instructions instructions = flow.getInstructions();
-        List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> sortedInstructions =
-                INSTRUCTION_ORDERING.sortedCopy(instructions.getInstruction());
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction>
+            sortedInstructions = INSTRUCTION_ORDERING.sortedCopy(instructions.nonnullInstruction().values());
 
-        for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction : sortedInstructions) {
-            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction = instruction
-                    .getInstruction();
-
-            if (curInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) {
-                org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase applyActionscase = (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) curInstruction;
-                ApplyActions applyActions = applyActionscase.getApplyActions();
+        for (var instruction : sortedInstructions) {
+            final var curInstruction = instruction.getInstruction();
+            if (curInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026
+                    .instruction.instruction.ApplyActionsCase) {
+                final var applyActions = ((org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026
+                    .instruction.instruction.ApplyActionsCase) curInstruction).getApplyActions();
 
                 final ActionConvertorData data = new ActionConvertorData(version);
                 data.setDatapathId(datapathid);
                 data.setIpProtocol(FlowConvertorUtil.getIpProtocolFromFlow(flow));
                 Optional<List<Action>> result = getConvertorExecutor().convert(applyActions.getAction(), data);
-                return result.orElse(Collections.emptyList());
+                return result.orElse(List.of());
             }
         }
 
@@ -327,20 +284,19 @@ public class FlowConvertor extends Convertor<Flow, List<FlowModInputBuilder>, Ve
     }
 
     // check if set vlanid action is present in the flow
-    private static boolean isSetVlanIdActionCasePresent(Flow flow) {
+    private static boolean isSetVlanIdActionCasePresent(final Flow flow) {
         // we are trying to find if there is a set-vlan-id action (OF1.0) action present in the flow.
         // If yes,then we would need to two flows
-        if (flow.getInstructions() != null && flow.getInstructions().getInstruction() != null) {
-            for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction instruction :
-                    flow.getInstructions().getInstruction()) {
-                org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curInstruction =
-                        instruction.getInstruction();
-
-                if (curInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) {
-                    org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase applyActionscase = (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) curInstruction;
-                    ApplyActions applyActions = applyActionscase.getApplyActions();
-                    for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action action :
-                            applyActions.getAction()) {
+        final var insns = flow.getInstructions();
+        if (insns != null) {
+            for (var instruction : insns.nonnullInstruction().values()) {
+                final var curInstruction = instruction.getInstruction();
+
+                if (curInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026
+                        .instruction.instruction.ApplyActionsCase) {
+                    ApplyActions applyActions = ((org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types
+                        .rev131026.instruction.instruction.ApplyActionsCase) curInstruction).getApplyActions();
+                    for (var action : applyActions.nonnullAction().values()) {
                         if (action.getAction() instanceof SetVlanIdActionCase) {
                             return true;
                         }
@@ -354,56 +310,56 @@ public class FlowConvertor extends Convertor<Flow, List<FlowModInputBuilder>, Ve
 
     /**
      * A) If user provided flow's match includes vlan match  and action has set_vlan_field
-     * Install following rules
+     * Install following rules.
      *    1) match on (OFPVID_PRESENT |value) without mask + action [set_field]
      * <p/>
      * B) if user provided flow's match doesn't include vlan match but action has set_vlan field
      *     1) Match on (OFPVID_NONE ) without mask + action [push vlan tag + set_field]
      *     2) Match on (OFPVID_PRESENT) with mask (OFPVID_PRESENT ) + action [ set_field]
      */
-    private List<FlowModInputBuilder> handleSetVlanIdForOF13(Flow srcFlow, short version, BigInteger datapathId) {
+    private List<FlowModInputBuilder> handleSetVlanIdForOF13(final Flow srcFlow,
+            final VersionDatapathIdConvertorData versionDatapathIdConverterData) {
         List<FlowModInputBuilder> list = new ArrayList<>(2);
 
-        final Match srcMatch = Preconditions.checkNotNull(srcFlow.getMatch());
+        final Match srcMatch = requireNonNull(srcFlow.getMatch());
         final VlanMatch srcVlanMatch = srcMatch.getVlanMatch();
         if (srcVlanMatch != null) {
             //create flow with setfield and match
             // match on vlan tag or vlanid with no mask
-            VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder(srcVlanMatch);
-            VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
-            vlanIdBuilder.setVlanIdPresent(srcVlanMatch.getVlanId().isVlanIdPresent());
-            vlanIdBuilder.setVlanId(srcVlanMatch.getVlanId().getVlanId());
-            vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
-            Match match = new MatchBuilder(srcMatch).setVlanMatch(vlanMatchBuilder.build()).build();
-
-            Optional<? extends Flow> optional = injectMatchToFlow(srcFlow, match);
+            Optional<? extends Flow> optional = injectMatchToFlow(srcFlow, new MatchBuilder(srcMatch)
+                .setVlanMatch(new VlanMatchBuilder(srcVlanMatch)
+                    .setVlanId(new VlanIdBuilder()
+                        .setVlanIdPresent(srcVlanMatch.getVlanId().getVlanIdPresent())
+                        .setVlanId(srcVlanMatch.getVlanId().getVlanId())
+                        .build())
+                    .build())
+                .build());
             if (optional.isPresent()) {
-                list.add(toFlowModInput(optional.get(), version, datapathId));
+                list.add(toFlowModInput(optional.get(), versionDatapathIdConverterData));
             }
         } else {
             // create 2 flows
             //flow 1
             // match on no vlan tag with no mask
-            Match match1 = new MatchBuilder(srcMatch).setVlanMatch(VLAN_MATCH_FALSE).build();
-
-            Optional<? extends Flow> optional1 = injectMatchAndAction(srcFlow, match1);
+            Optional<? extends Flow> optional1 = injectMatchAndAction(srcFlow,
+                new MatchBuilder(srcMatch).setVlanMatch(VLAN_MATCH_FALSE).build());
             if (optional1.isPresent()) {
-                list.add(toFlowModInput(optional1.get(), version, datapathId));
+                list.add(toFlowModInput(optional1.get(), versionDatapathIdConverterData));
             }
 
             //flow2
             // match on vlan tag with mask
-            Match match2 = new MatchBuilder(srcMatch).setVlanMatch(VLAN_MATCH_TRUE).build();
-            Optional<? extends Flow> optional2 = injectMatchToFlow(srcFlow, match2);
+            Optional<? extends Flow> optional2 = injectMatchToFlow(srcFlow,
+                new MatchBuilder(srcMatch).setVlanMatch(VLAN_MATCH_TRUE).build());
             if (optional2.isPresent()) {
-                list.add(toFlowModInput(optional2.get(), version, datapathId));
+                list.add(toFlowModInput(optional2.get(), versionDatapathIdConverterData));
             }
         }
         return list;
     }
 
 
-    private static Optional<? extends Flow> injectMatchToFlow(Flow sourceFlow, Match match) {
+    private static Optional<? extends Flow> injectMatchToFlow(final Flow sourceFlow, final Match match) {
         if (sourceFlow instanceof AddFlowInput) {
             return Optional.of(new AddFlowInputBuilder(sourceFlow).setMatch(match).build());
         } else if (sourceFlow instanceof RemoveFlowInput) {
@@ -415,9 +371,9 @@ public class FlowConvertor extends Convertor<Flow, List<FlowModInputBuilder>, Ve
         }
     }
 
-    private static Optional<? extends Flow> injectMatchAndAction(Flow sourceFlow, Match match) {
+    private static Optional<? extends Flow> injectMatchAndAction(final Flow sourceFlow, final Match match) {
 
-        Instructions instructions = (new InstructionsBuilder())
+        Instructions instructions = new InstructionsBuilder()
                 .setInstruction(injectPushActionToInstruction(sourceFlow))
                 .build();
 
@@ -435,95 +391,91 @@ public class FlowConvertor extends Convertor<Flow, List<FlowModInputBuilder>, Ve
         }
     }
 
-    private static List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction>
-    injectPushActionToInstruction(final Flow sourceFlow) {
-
-        List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> srcInstructionList =
-                sourceFlow.getInstructions().getInstruction();
-
-        List<org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction> targetInstructionList = new ArrayList<>(srcInstructionList.size());
-        List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> targetActionList = new ArrayList<>();
-
-        org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder instructionBuilder =
-                new org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder();
-
-        for (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction srcInstruction : srcInstructionList) {
-            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.Instruction curSrcInstruction =
-                    srcInstruction.getInstruction();
-
-            if (curSrcInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) {
-                org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase applyActionscase = (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase) curSrcInstruction;
-                ApplyActions applyActions = applyActionscase.getApplyActions();
-                List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> srcActionList = applyActions.getAction();
+    private static @NonNull Map<InstructionKey,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction>
+                injectPushActionToInstruction(final Flow sourceFlow) {
+        final var srcInstructionList = sourceFlow.getInstructions().nonnullInstruction();
+        final var targetInstructionList = BindingMap.<
+            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction>
+                orderedBuilder(srcInstructionList.size());
+        final var targetActionList = BindingMap.<
+            org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey,
+            org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action>orderedBuilder();
+        final var instructionBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026
+            .instruction.list.InstructionBuilder();
+
+        for (var srcInstruction : srcInstructionList.values()) {
+            final var curSrcInstruction = srcInstruction.getInstruction();
+
+            if (curSrcInstruction instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026
+                    .instruction.instruction.ApplyActionsCase) {
+                final var applyActionscase = (org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types
+                            .rev131026.instruction.instruction.ApplyActionsCase) curSrcInstruction;
+                final var srcActionList = applyActionscase.getApplyActions().nonnullAction();
 
                 int offset = 0;
-                for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action actionItem : srcActionList) {
+                for (var actionItem : srcActionList.values()) {
                     // check if its a set-vlan-action. If yes, then add the injected-action
 
                     if (actionItem.getAction() instanceof SetVlanIdActionCase) {
-                        SetVlanIdActionCase setVlanIdActionCase = (SetVlanIdActionCase) actionItem.getAction();
-
-                        PushVlanActionCaseBuilder pushVlanActionCaseBuilder = new PushVlanActionCaseBuilder();
-                        PushVlanActionBuilder pushVlanActionBuilder = new PushVlanActionBuilder();
-
-                        pushVlanActionBuilder.setCfi(new VlanCfi(1))
-                                .setVlanId(setVlanIdActionCase.getSetVlanIdAction().getVlanId())
-                                .setEthernetType(PUSH_VLAN)
-                                .setTag(PUSH_VLAN);
-                        pushVlanActionCaseBuilder.setPushVlanAction(pushVlanActionBuilder.build());
-                        PushVlanActionCase injectedAction = pushVlanActionCaseBuilder.build();
-
-                        ActionBuilder actionBuilder = new ActionBuilder();
-                        actionBuilder.setAction(injectedAction)
-                                .setKey(actionItem.getKey())
-                                .setOrder(actionItem.getOrder() + offset);
-
-                        targetActionList.add(actionBuilder.build());
+                        final var setVlanIdActionCase = (SetVlanIdActionCase) actionItem.getAction();
+
+                        targetActionList.add(new ActionBuilder()
+                            .setAction(new PushVlanActionCaseBuilder()
+                                .setPushVlanAction(new PushVlanActionBuilder()
+                                    .setCfi(PUSH_CFI)
+                                    .setVlanId(setVlanIdActionCase.getSetVlanIdAction().getVlanId())
+                                    .setEthernetType(PUSH_VLAN)
+                                    .setTag(PUSH_TAG)
+                                    .build())
+                                .build())
+                            // FIXME: this looks like a mismatch
+                            .withKey(actionItem.key())
+                            .setOrder(actionItem.getOrder() + offset)
+                            .build());
                         offset++;
                     }
 
                     if (offset > 0) {
                         // we need to increment the order for all the actions added after injection
-                        ActionBuilder actionBuilder =
-                                new ActionBuilder(actionItem);
-                        actionBuilder.setOrder(actionItem.getOrder() + offset);
-                        actionItem = actionBuilder.build();
+                        final Integer newOrder = actionItem.getOrder() + offset;
+                        actionItem = new ActionBuilder(actionItem)
+                            .setOrder(newOrder)
+                            .withKey(new ActionKey(newOrder))
+                            .build();
                     }
 
                     targetActionList.add(actionItem);
                 }
 
-                ApplyActionsCaseBuilder applyActionsCaseBuilder = new ApplyActionsCaseBuilder();
-                ApplyActionsBuilder applyActionsBuilder = new ApplyActionsBuilder();
-                applyActionsBuilder.setAction(targetActionList);
-                applyActionsCaseBuilder.setApplyActions(applyActionsBuilder.build());
-
-                instructionBuilder.setInstruction(applyActionsCaseBuilder.build());
+                instructionBuilder.setInstruction(new ApplyActionsCaseBuilder()
+                    .setApplyActions(new ApplyActionsBuilder().setAction(targetActionList.build()).build())
+                    .build());
             } else {
                 instructionBuilder.setInstruction(curSrcInstruction);
             }
 
-            instructionBuilder
-                    .setKey(srcInstruction.getKey())
-                    .setOrder(srcInstruction.getOrder());
-            targetInstructionList.add(instructionBuilder.build());
-
+            targetInstructionList.add(instructionBuilder
+                .withKey(srcInstruction.key())
+                .setOrder(srcInstruction.getOrder())
+                .build());
         }
 
-        return targetInstructionList;
+        return targetInstructionList.build();
     }
 
     @Override
-    public Collection<Class<? extends DataContainer>> getTypes() {
+    public Collection<Class<?>> getTypes() {
         return  TYPES;
     }
 
     @Override
-    public List<FlowModInputBuilder> convert(Flow source, VersionDatapathIdConvertorData data) {
-        if (data.getVersion() >= OFConstants.OFP_VERSION_1_3 && isSetVlanIdActionCasePresent(source)) {
-            return handleSetVlanIdForOF13(source, data.getVersion(), data.getDatapathId());
+    public List<FlowModInputBuilder> convert(final Flow source, final VersionDatapathIdConvertorData data) {
+        if (OFConstants.OFP_VERSION_1_3.compareTo(data.getVersion()) <= 0 && isSetVlanIdActionCasePresent(source)) {
+            return handleSetVlanIdForOF13(source, data);
         } else {
-            return Collections.singletonList(toFlowModInput(source, data.getVersion(), data.getDatapathId()));
+            return Collections.singletonList(toFlowModInput(source, data));
         }
     }
 }