Extensibility support (deserialization part)
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / util / InstructionsDeserializer.java
index f678d87f2568d5b26c2064440000e09b4e447655..820c7fa7094dec72060e8139326caf6006940627 100644 (file)
@@ -10,9 +10,13 @@ package org.opendaylight.openflowjava.protocol.impl.util;
 
 import io.netty.buffer.ByteBuf;
 
-import java.util.ArrayList;
 import java.util.List;
 
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderDeserializer;
+import org.opendaylight.openflowjava.protocol.api.extensibility.MessageCodeKey;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionsInstruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionsInstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterInstruction;
@@ -23,6 +27,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MeterIdInstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.TableIdInstruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.TableIdInstructionBuilder;
+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.ApplyActions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.ClearActions;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.Experimenter;
@@ -38,127 +43,97 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction
  * @author michal.polkorab
  * @author timotej.kubas
  */
-public abstract class InstructionsDeserializer {
+public class InstructionsDeserializer implements OFDeserializer<Instruction>,
+        HeaderDeserializer<Instruction>, DeserializerRegistryInjector {
     
     private static final byte WRITE_APPLY_CLEAR_ACTION_LENGTH = 8;
-    private static final byte EXPERIMENTER_HEADER_LENGTH = 8;
     private static final byte GOTO_TABLE_PADDING = 3;
     private static final byte WRITE_METADATA_PADDING = 4;
     private static final byte ACTIONS_RELATED_INSTRUCTION_PADDING = 4;
+    private DeserializerRegistry registry;
 
-    /**
-     * Creates list of instructions
-     * @param input
-     * @param length
-     * @return list of ofp_instruction
-     */
-    public static List<Instruction> createInstructions(ByteBuf input, int length) {
-        List<Instruction> instructions = new ArrayList<>();
-        if (input.readableBytes() != 0) {
-            int lengthOfInstructions = length;
-            while (lengthOfInstructions > 0) {
-                InstructionBuilder builder = new InstructionBuilder();
-                int type = input.readUnsignedShort();
-                int instructionLength = input.readUnsignedShort();
-                lengthOfInstructions -= instructionLength;
-                switch (type) {
-                case 1:
-                    createGotoTableInstruction(builder, input);
-                    break;
-                case 2:
-                    createMetadataInstruction(builder, input);
-                    break;
-                case 3:
-                    builder.setType(WriteActions.class);
-                    createActionRelatedInstruction(input, builder, instructionLength - WRITE_APPLY_CLEAR_ACTION_LENGTH);
-                    break;
-                case 4:
-                    builder.setType(ApplyActions.class);
-                    createActionRelatedInstruction(input, builder, instructionLength - WRITE_APPLY_CLEAR_ACTION_LENGTH);
-                    break;
-                case 5:
-                    builder.setType(ClearActions.class);
-                    createActionRelatedInstruction(input, builder, instructionLength - WRITE_APPLY_CLEAR_ACTION_LENGTH);
-                    break;
-                case 6:
-                    builder.setType(Meter.class);
-                    MeterIdInstructionBuilder meterBuilder = new MeterIdInstructionBuilder();
-                    meterBuilder.setMeterId(input.readUnsignedInt());
-                    builder.addAugmentation(MeterIdInstruction.class, meterBuilder.build());
-                    break;
-                case 65535:
-                    builder.setType(Experimenter.class);
-                    ExperimenterInstructionBuilder expBuilder = new ExperimenterInstructionBuilder();
-                    expBuilder.setExperimenter(input.readUnsignedInt());
-                    int dataLength = instructionLength - EXPERIMENTER_HEADER_LENGTH;
-                    if (dataLength > 0) {
-                        byte[] data = new byte[dataLength];
-                        input.readBytes(data);
-                        expBuilder.setData(data);
-                    }
-                    builder.addAugmentation(ExperimenterInstruction.class, expBuilder.build());
-                    break;
-                default:
-                    break;
-                }
-                instructions.add(builder.build());
-            }
+    @Override
+    public Instruction deserialize(ByteBuf input) {
+        InstructionBuilder builder = new InstructionBuilder();
+        int type = input.readUnsignedShort();
+        switch (type) {
+        case 1:
+            createGotoTableInstruction(builder, input);
+            break;
+        case 2:
+            createMetadataInstruction(builder, input);
+            break;
+        case 3:
+            builder.setType(WriteActions.class);
+            createActionRelatedInstruction(input, builder);
+            break;
+        case 4:
+            builder.setType(ApplyActions.class);
+            createActionRelatedInstruction(input, builder);
+            break;
+        case 5:
+            builder.setType(ClearActions.class);
+            createActionRelatedInstruction(input, builder);
+            break;
+        case 6:
+            builder.setType(Meter.class);
+            input.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+            MeterIdInstructionBuilder meterBuilder = new MeterIdInstructionBuilder();
+            meterBuilder.setMeterId(input.readUnsignedInt());
+            builder.addAugmentation(MeterIdInstruction.class, meterBuilder.build());
+            break;
+        case 65535:
+            builder.setType(Experimenter.class);
+            OFDeserializer<ExperimenterInstruction> deserializer = registry.getDeserializer(
+                    new MessageCodeKey(EncodeConstants.OF13_VERSION_ID, type, ExperimenterInstruction.class));
+            ExperimenterInstruction expInstruction = deserializer.deserialize(input);
+            builder.addAugmentation(ExperimenterInstruction.class, expInstruction);
+            break;
+        default:
+            break;
         }
-        return instructions;
+        return builder.build();
     }
 
-    /**
-     * Creates instruction ids (instructions without values)
-     * @param input
-     * @param length
-     * @return list of ofp_instruction without values
-     */
-    public static List<Instruction> createInstructionIds(ByteBuf input, int length) {
-        List<Instruction> instructions = new ArrayList<>();
-        if (input.readableBytes() != 0) {
-            int lengthOfInstructions = length;
-            while (lengthOfInstructions > 0) {
-                InstructionBuilder builder = new InstructionBuilder();
-                int type = input.readUnsignedShort();
-                int instructionLength = input.readUnsignedShort();
-                lengthOfInstructions -= instructionLength;
-                switch (type) {
-                case 1:
-                    builder.setType(GotoTable.class);
-                    break;
-                case 2:
-                    builder.setType(WriteMetadata.class);
-                    break;
-                case 3:
-                    builder.setType(WriteActions.class);
-                    break;
-                case 4:
-                    builder.setType(ApplyActions.class);
-                    break;
-                case 5:
-                    builder.setType(ClearActions.class);
-                    break;
-                case 6:
-                    builder.setType(Meter.class);
-                    break;
-                case 65535:
-                    builder.setType(Experimenter.class);
-                    ExperimenterInstructionBuilder expBuilder = new ExperimenterInstructionBuilder();
-                    expBuilder.setExperimenter(input.readUnsignedInt());
-                    builder.addAugmentation(ExperimenterInstruction.class, expBuilder.build());
-                    break;
-                default:
-                    break;
-                }
-                instructions.add(builder.build());
-            }
+    @Override
+    public Instruction deserializeHeader(ByteBuf input) {
+        InstructionBuilder builder = new InstructionBuilder();
+        int type = input.readUnsignedShort();
+        switch (type) {
+        case 1:
+            builder.setType(GotoTable.class);
+            break;
+        case 2:
+            builder.setType(WriteMetadata.class);
+            break;
+        case 3:
+            builder.setType(WriteActions.class);
+            break;
+        case 4:
+            builder.setType(ApplyActions.class);
+            break;
+        case 5:
+            builder.setType(ClearActions.class);
+            break;
+        case 6:
+            builder.setType(Meter.class);
+            break;
+        case 65535:
+            builder.setType(Experimenter.class);
+            ExperimenterInstructionBuilder expBuilder = new ExperimenterInstructionBuilder();
+            expBuilder.setExperimenter(input.readUnsignedInt());
+            builder.addAugmentation(ExperimenterInstruction.class, expBuilder.build());
+            break;
+        default:
+            break;
         }
-        return instructions;
+        return builder.build();
     }
 
     private static void createGotoTableInstruction(InstructionBuilder builder,
             ByteBuf input) {
         builder.setType(GotoTable.class);
+        input.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
         TableIdInstructionBuilder tableBuilder = new TableIdInstructionBuilder();
         tableBuilder.setTableId(input.readUnsignedByte());
         builder.addAugmentation(TableIdInstruction.class, tableBuilder.build());
@@ -167,8 +142,9 @@ public abstract class InstructionsDeserializer {
     
     private static void createMetadataInstruction(InstructionBuilder builder,
             ByteBuf input) {
-        input.skipBytes(WRITE_METADATA_PADDING);
         builder.setType(WriteMetadata.class);
+        input.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
+        input.skipBytes(WRITE_METADATA_PADDING);
         MetadataInstructionBuilder metadataBuilder = new MetadataInstructionBuilder();
         byte[] metadata = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];
         input.readBytes(metadata);
@@ -179,12 +155,20 @@ public abstract class InstructionsDeserializer {
         builder.addAugmentation(MetadataInstruction.class, metadataBuilder.build());
     }
     
-    private static void createActionRelatedInstruction(ByteBuf input,
-            InstructionBuilder builder, int actionsLength) {
+    private void createActionRelatedInstruction(ByteBuf input, InstructionBuilder builder) {
+        int instructionLength = input.readUnsignedShort();
         input.skipBytes(ACTIONS_RELATED_INSTRUCTION_PADDING);
         ActionsInstructionBuilder actionsBuilder = new ActionsInstructionBuilder();
-        actionsBuilder.setAction(ActionsDeserializer.createActions(input, actionsLength));
+        OFDeserializer<Action> deserializer = registry.getDeserializer(new MessageCodeKey(
+                EncodeConstants.OF13_VERSION_ID, EncodeConstants.EMPTY_VALUE, Action.class));
+        List<Action> actions = DecodingUtils.deserializeList(
+                instructionLength - WRITE_APPLY_CLEAR_ACTION_LENGTH, input, deserializer);
+        actionsBuilder.setAction(actions);
         builder.addAugmentation(ActionsInstruction.class, actionsBuilder.build());
     }
 
+    @Override
+    public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+        registry = deserializerRegistry;
+    }
 }