Updated experimenter model
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / deserialization / factories / MultipartReplyMessageFactory.java
index eb0669166a2380a0101453d74eff30aa61fc6af6..4074339a535908eb0daa07eebbaa9a19a48669c1 100644 (file)
@@ -14,17 +14,18 @@ import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.opendaylight.openflowjava.protocol.impl.deserialization.OFDeserializer;
-import org.opendaylight.openflowjava.protocol.impl.util.ActionsDeserializer;
-import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils;
-import org.opendaylight.openflowjava.protocol.impl.util.EncodeConstants;
-import org.opendaylight.openflowjava.protocol.impl.util.InstructionsDeserializer;
-import org.opendaylight.openflowjava.protocol.impl.util.MatchDeserializer;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.MessageCodeKey;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.openflowjava.protocol.impl.util.CodeKeyMaker;
+import org.opendaylight.openflowjava.protocol.impl.util.CodeKeyMakerFactory;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.protocol.impl.util.ListDeserializer;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionRelatedTableFeatureProperty;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionRelatedTableFeaturePropertyBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterRelatedTableFeatureProperty;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterRelatedTableFeaturePropertyBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.InstructionRelatedTableFeatureProperty;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.InstructionRelatedTableFeaturePropertyBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.NextTableRelatedTableFeatureProperty;
@@ -33,7 +34,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OxmRelatedTableFeaturePropertyBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.table.features.properties.container.table.feature.properties.NextTableIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.table.features.properties.container.table.feature.properties.NextTableIdsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.ActionsList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.grouping.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.instructions.grouping.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.FlowModFlags;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.GroupCapabilities;
@@ -52,10 +54,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev13
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableConfig;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableFeaturesPropType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.match.grouping.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.grouping.MatchEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessageBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.BucketsList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.BucketsListBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.grouping.BucketsList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.buckets.grouping.BucketsListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.meter.band.header.meter.band.MeterBandDropCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.meter.band.header.meter.band.MeterBandDscpRemarkCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.meter.band.header.meter.band.MeterBandExperimenterCaseBuilder;
@@ -133,15 +137,16 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeaturesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.multipart.reply.table.features.TableFeatures;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.multipart.reply.table.features.TableFeaturesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.table.features.properties.TableFeatureProperties;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.table.features.properties.TableFeaturePropertiesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.table.features.properties.grouping.TableFeatureProperties;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.table.features.properties.grouping.TableFeaturePropertiesBuilder;
 
 /**
  * Translates MultipartReply messages
  * @author timotej.kubas
  * @author michal.polkorab
  */
-public class MultipartReplyMessageFactory implements OFDeserializer<MultipartReplyMessage> {
+public class MultipartReplyMessageFactory implements OFDeserializer<MultipartReplyMessage>,
+        DeserializerRegistryInjector {
 
     private static final byte PADDING_IN_MULTIPART_REPLY_HEADER = 4;
     private static final int DESC_STR_LEN = 256;
@@ -173,28 +178,12 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
     private static final byte PADDING_IN_BUCKETS_HEADER = 4;
     private static final byte GROUP_DESC_HEADER_LENGTH = 8;
     private static final byte BUCKETS_HEADER_LENGTH = 16;
-
-    
-    private static MultipartReplyMessageFactory instance;
-
-    private MultipartReplyMessageFactory() {
-        // singleton
-    }
-    
-    /**
-     * @return singleton factory
-     */
-    public static synchronized MultipartReplyMessageFactory getInstance() {
-        if (instance == null){
-            instance = new MultipartReplyMessageFactory();
-        }
-        return instance;
-    }
+    private DeserializerRegistry registry;
 
     @Override
-    public MultipartReplyMessage bufferToMessage(ByteBuf rawMessage, short version) {
+    public MultipartReplyMessage deserialize(ByteBuf rawMessage) {
         MultipartReplyMessageBuilder builder = new MultipartReplyMessageBuilder();
-        builder.setVersion(version);
+        builder.setVersion((short) EncodeConstants.OF13_VERSION_ID);
         builder.setXid(rawMessage.readUnsignedInt());
         int type = rawMessage.readUnsignedShort();
         builder.setType(MultipartType.forValue(type));
@@ -266,33 +255,40 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
         return caseBuilder.build();
     }
     
-    private static MultipartReplyFlowCase setFlow(ByteBuf input) {
+    private MultipartReplyFlowCase setFlow(ByteBuf input) {
         MultipartReplyFlowCaseBuilder caseBuilder = new MultipartReplyFlowCaseBuilder();
         MultipartReplyFlowBuilder flowBuilder = new MultipartReplyFlowBuilder();
         List<FlowStats> flowStatsList = new ArrayList<>();
         while (input.readableBytes() > 0) {
             FlowStatsBuilder flowStatsBuilder = new FlowStatsBuilder();
-            input.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
-            flowStatsBuilder.setTableId(input.readUnsignedByte());
-            input.skipBytes(PADDING_IN_FLOW_STATS_HEADER_01);
-            flowStatsBuilder.setDurationSec(input.readUnsignedInt());
-            flowStatsBuilder.setDurationNsec(input.readUnsignedInt());
-            flowStatsBuilder.setPriority(input.readUnsignedShort());
-            flowStatsBuilder.setIdleTimeout(input.readUnsignedShort());
-            flowStatsBuilder.setHardTimeout(input.readUnsignedShort());
-            flowStatsBuilder.setFlags(createFlowModFlagsFromBitmap(input.readShort()));
-            input.skipBytes(PADDING_IN_FLOW_STATS_HEADER_02);
+            int flowRecordLength = input.readUnsignedShort();
+            ByteBuf subInput = input.readSlice(flowRecordLength - EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+            flowStatsBuilder.setTableId(subInput.readUnsignedByte());
+            subInput.skipBytes(PADDING_IN_FLOW_STATS_HEADER_01);
+            flowStatsBuilder.setDurationSec(subInput.readUnsignedInt());
+            flowStatsBuilder.setDurationNsec(subInput.readUnsignedInt());
+            flowStatsBuilder.setPriority(subInput.readUnsignedShort());
+            flowStatsBuilder.setIdleTimeout(subInput.readUnsignedShort());
+            flowStatsBuilder.setHardTimeout(subInput.readUnsignedShort());
+            flowStatsBuilder.setFlags(createFlowModFlagsFromBitmap(subInput.readUnsignedShort()));
+            subInput.skipBytes(PADDING_IN_FLOW_STATS_HEADER_02);
             byte[] cookie = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
-            input.readBytes(cookie);
+            subInput.readBytes(cookie);
             flowStatsBuilder.setCookie(new BigInteger(1, cookie));
             byte[] packetCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
-            input.readBytes(packetCount);
+            subInput.readBytes(packetCount);
             flowStatsBuilder.setPacketCount(new BigInteger(1, packetCount));
             byte[] byteCount = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
-            input.readBytes(byteCount);
+            subInput.readBytes(byteCount);
             flowStatsBuilder.setByteCount(new BigInteger(1, byteCount));
-            flowStatsBuilder.setMatch(MatchDeserializer.createMatch(input));
-            flowStatsBuilder.setInstructions(InstructionsDeserializer.createInstructions(input, input.readableBytes()));
+            OFDeserializer<Match> matchDeserializer = registry.getDeserializer(new MessageCodeKey(
+                    EncodeConstants.OF13_VERSION_ID, EncodeConstants.EMPTY_VALUE, Match.class));
+            flowStatsBuilder.setMatch(matchDeserializer.deserialize(subInput));
+            CodeKeyMaker keyMaker = CodeKeyMakerFactory
+                    .createInstructionsKeyMaker(EncodeConstants.OF13_VERSION_ID);
+            List<Instruction> instructions = ListDeserializer.deserializeList(
+                    EncodeConstants.OF13_VERSION_ID, subInput.readableBytes(), subInput, keyMaker, registry);
+            flowStatsBuilder.setInstruction(instructions);
             flowStatsList.add(flowStatsBuilder.build());
         }
         flowBuilder.setFlowStats(flowStatsList);
@@ -300,7 +296,7 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
         return caseBuilder.build();
     }
     
-    private static FlowModFlags createFlowModFlagsFromBitmap(short input){
+    private static FlowModFlags createFlowModFlagsFromBitmap(int input){
         final Boolean _oFPFFSENDFLOWREM = (input & (1 << 0)) != 0;
         final Boolean _oFPFFCHECKOVERLAP = (input & (1 << 1)) != 0;
         final Boolean _oFPFFRESETCOUNTS = (input & (1 << 2)) != 0; 
@@ -346,7 +342,7 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
         return caseBuilder.build();
     }
     
-    private static MultipartReplyTableFeaturesCase setTableFeatures(ByteBuf input) {
+    private MultipartReplyTableFeaturesCase setTableFeatures(ByteBuf input) {
         MultipartReplyTableFeaturesCaseBuilder caseBuilder = new MultipartReplyTableFeaturesCaseBuilder();
         MultipartReplyTableFeaturesBuilder builder = new MultipartReplyTableFeaturesBuilder();
         List<TableFeatures> features = new ArrayList<>();
@@ -378,7 +374,7 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
         return new TableConfig(deprecated);
     }
     
-    private static List<TableFeatureProperties> createTableFeaturesProperties(ByteBuf input, int length) {
+    private List<TableFeatureProperties> createTableFeaturesProperties(ByteBuf input, int length) {
         List<TableFeatureProperties> properties = new ArrayList<>();
         int tableFeaturesLength = length;
         while (tableFeaturesLength > 0) {
@@ -391,7 +387,10 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
             if (type.equals(TableFeaturesPropType.OFPTFPTINSTRUCTIONS)
                     || type.equals(TableFeaturesPropType.OFPTFPTINSTRUCTIONSMISS)) {
                 InstructionRelatedTableFeaturePropertyBuilder insBuilder = new InstructionRelatedTableFeaturePropertyBuilder();
-                insBuilder.setInstructions(InstructionsDeserializer.createInstructionIds(input, propertyLength - COMMON_PROPERTY_LENGTH));
+                CodeKeyMaker keyMaker = CodeKeyMakerFactory.createInstructionsKeyMaker(EncodeConstants.OF13_VERSION_ID);
+                List<Instruction> instructions = ListDeserializer.deserializeHeaders(EncodeConstants.OF13_VERSION_ID,
+                        propertyLength - COMMON_PROPERTY_LENGTH, input, keyMaker, registry);
+                insBuilder.setInstruction(instructions);
                 builder.addAugmentation(InstructionRelatedTableFeatureProperty.class, insBuilder.build());
             } else if (type.equals(TableFeaturesPropType.OFPTFPTNEXTTABLES)
                     || type.equals(TableFeaturesPropType.OFPTFPTNEXTTABLESMISS)) {
@@ -411,7 +410,10 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
                     || type.equals(TableFeaturesPropType.OFPTFPTAPPLYACTIONS)
                     || type.equals(TableFeaturesPropType.OFPTFPTAPPLYACTIONSMISS)) {
                 ActionRelatedTableFeaturePropertyBuilder actionBuilder = new ActionRelatedTableFeaturePropertyBuilder();
-                actionBuilder.setActionsList(ActionsDeserializer.createActionIds(input, propertyLength - COMMON_PROPERTY_LENGTH));
+                CodeKeyMaker keyMaker = CodeKeyMakerFactory.createActionsKeyMaker(EncodeConstants.OF13_VERSION_ID);
+                List<Action> actions = ListDeserializer.deserializeHeaders(EncodeConstants.OF13_VERSION_ID,
+                        propertyLength - COMMON_PROPERTY_LENGTH, input, keyMaker, registry);
+                actionBuilder.setAction(actions);
                 builder.addAugmentation(ActionRelatedTableFeatureProperty.class, actionBuilder.build());
             } else if (type.equals(TableFeaturesPropType.OFPTFPTMATCH)
                     || type.equals(TableFeaturesPropType.OFPTFPTWILDCARDS)
@@ -420,20 +422,23 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
                     || type.equals(TableFeaturesPropType.OFPTFPTAPPLYSETFIELD)
                     || type.equals(TableFeaturesPropType.OFPTFPTAPPLYSETFIELDMISS)) {
                 OxmRelatedTableFeaturePropertyBuilder oxmBuilder = new OxmRelatedTableFeaturePropertyBuilder();
-                oxmBuilder.setMatchEntries(MatchDeserializer.createMatchIds(input, propertyLength - COMMON_PROPERTY_LENGTH));
+                CodeKeyMaker keyMaker = CodeKeyMakerFactory
+                        .createMatchEntriesKeyMaker(EncodeConstants.OF13_VERSION_ID);
+                List<MatchEntries> entries = ListDeserializer.deserializeHeaders(EncodeConstants.OF13_VERSION_ID,
+                        propertyLength - COMMON_PROPERTY_LENGTH, input, keyMaker, registry);
+                oxmBuilder.setMatchEntries(entries);
                 builder.addAugmentation(OxmRelatedTableFeatureProperty.class, oxmBuilder.build());
             } else if (type.equals(TableFeaturesPropType.OFPTFPTEXPERIMENTER)
                     || type.equals(TableFeaturesPropType.OFPTFPTEXPERIMENTERMISS)) {
-                ExperimenterRelatedTableFeaturePropertyBuilder expBuilder = new ExperimenterRelatedTableFeaturePropertyBuilder();
-                expBuilder.setExperimenter(input.readUnsignedInt());
-                expBuilder.setExpType(input.readUnsignedInt());
-                int dataLength = propertyLength - COMMON_PROPERTY_LENGTH - 2 * EncodeConstants.SIZE_OF_INT_IN_BYTES;
-                if (dataLength > 0) {
-                    byte[] data = new byte[dataLength];
-                    input.readBytes(data);
-                    expBuilder.setData(data);
-                }
-                builder.addAugmentation(ExperimenterRelatedTableFeatureProperty.class, expBuilder.build());
+                // return index to property start, so that the experimenter properties are deserialized
+                // correctly - as whole ofp_table_feature_prop_experimenter property
+                input.readerIndex(input.readerIndex() - 2 * EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+                OFDeserializer<TableFeatureProperties> propDeserializer = registry.getDeserializer(
+                        new MessageCodeKey(EncodeConstants.OF13_VERSION_ID,
+                                type.getIntValue(), TableFeatureProperties.class));
+                TableFeatureProperties expProp = propDeserializer.deserialize(input);
+                properties.add(expProp);
+                continue;
             }
             if (paddingRemainder != 0) {
                 input.skipBytes(EncodeConstants.PADDING - paddingRemainder);
@@ -668,14 +673,15 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
                         bandsBuilder.setMeterBand(bandDscpRemarkCaseBuilder.build());
                         break;
                     case 0xFFFF:
-                       MeterBandExperimenterCaseBuilder bandExperimenterCaseBuilder = new MeterBandExperimenterCaseBuilder();
+                        MeterBandExperimenterCaseBuilder bandExperimenterCaseBuilder = new MeterBandExperimenterCaseBuilder();
                         MeterBandExperimenterBuilder bandExperimenterBuilder = new MeterBandExperimenterBuilder();
-                        bandExperimenterBuilder.setType(MeterBandType.forValue(bandType));
-                        actualLength += input.readUnsignedShort();
-                        bandExperimenterBuilder.setRate(input.readUnsignedInt());
-                        bandExperimenterBuilder.setBurstSize(input.readUnsignedInt());
-                        bandExperimenterBuilder.setExperimenter(input.readUnsignedInt());
-                        bandExperimenterCaseBuilder.setMeterBandExperimenter(bandExperimenterBuilder.build());
+                        // TODO - implement lookup into registry
+//                        bandExperimenterBuilder.setType(MeterBandType.forValue(bandType));
+//                        actualLength += input.readUnsignedShort();
+//                        bandExperimenterBuilder.setRate(input.readUnsignedInt());
+//                        bandExperimenterBuilder.setBurstSize(input.readUnsignedInt());
+//                        bandExperimenterBuilder.setExperimenter(input.readUnsignedInt());
+//                        bandExperimenterCaseBuilder.setMeterBandExperimenter(bandExperimenterBuilder.build());
                         bandsBuilder.setMeterBand(bandExperimenterCaseBuilder.build());
                         break;
                     default:
@@ -692,13 +698,14 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
     }
     
     private static MultipartReplyExperimenterCase setExperimenter(ByteBuf input) {
+     // TODO - implement lookup into registry
        MultipartReplyExperimenterCaseBuilder caseBuilder = new MultipartReplyExperimenterCaseBuilder();
         MultipartReplyExperimenterBuilder builder = new MultipartReplyExperimenterBuilder();
-        builder.setExperimenter(input.readUnsignedInt());
-        builder.setExpType(input.readUnsignedInt());
-        byte[] data = new byte[input.readableBytes()];
-        input.readBytes(data);
-        builder.setData(data);
+//        builder.setExperimenter(input.readUnsignedInt());
+//        builder.setExpType(input.readUnsignedInt());
+//        byte[] data = new byte[input.readableBytes()];
+//        input.readBytes(data);
+//        builder.setData(data);
         caseBuilder.setMultipartReplyExperimenter(builder.build());
         return caseBuilder.build();
     }
@@ -826,7 +833,7 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
         return new GroupTypes(OFPGT_ALL, OFPGT_FF, OFPGT_INDIRECT, OFPGT_SELECT);
     }
     
-    private static MultipartReplyGroupDescCase setGroupDesc(ByteBuf input) {
+    private MultipartReplyGroupDescCase setGroupDesc(ByteBuf input) {
         MultipartReplyGroupDescCaseBuilder caseBuilder = new MultipartReplyGroupDescCaseBuilder();
         MultipartReplyGroupDescBuilder builder = new MultipartReplyGroupDescBuilder();
         List<GroupDesc> groupDescsList = new ArrayList<>();
@@ -845,9 +852,10 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
                 bucketsBuilder.setWatchPort(new PortNumber(input.readUnsignedInt()));
                 bucketsBuilder.setWatchGroup(input.readUnsignedInt());
                 input.skipBytes(PADDING_IN_BUCKETS_HEADER);
-                List<ActionsList> actionsList = ActionsDeserializer
-                        .createActionsList(input, bucketsLength - BUCKETS_HEADER_LENGTH);
-                bucketsBuilder.setActionsList(actionsList);
+                CodeKeyMaker keyMaker = CodeKeyMakerFactory.createActionsKeyMaker(EncodeConstants.OF13_VERSION_ID);
+                List<Action> actions = ListDeserializer.deserializeList(EncodeConstants.OF13_VERSION_ID,
+                        bucketsLength - BUCKETS_HEADER_LENGTH, input, keyMaker, registry);
+                bucketsBuilder.setAction(actions);
                 bucketsList.add(bucketsBuilder.build());
                 actualLength += bucketsLength;
             }
@@ -858,5 +866,10 @@ public class MultipartReplyMessageFactory implements OFDeserializer<MultipartRep
         caseBuilder.setMultipartReplyGroupDesc(builder.build());
         return caseBuilder.build();
     }
-    
+
+    @Override
+    public void injectDeserializerRegistry(
+            DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
 }