You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2019/05/31 15:49:54 UTC

[plc4x] branch feature/code-gen updated: - Implemented the serialization

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch feature/code-gen
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/code-gen by this push:
     new b4f3ecf  - Implemented the serialization
b4f3ecf is described below

commit b4f3ecf14b189080df2fcc7b7e8bc5cc08b97134
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Fri May 31 17:49:45 2019 +0200

    - Implemented the serialization
---
 .../language/java/JavaLanguageTemplateHelper.java  | 53 +++++++++++-
 .../main/resources/templates/java/io-template.ftlh | 96 ++++++++++++++++++++--
 .../resources/templates/java/pojo-template.ftlh    |  8 +-
 .../src/test/resources/specs/s7.spec               | 15 ++--
 .../src/main/resources/protocols/s7/protocol.spec  |  8 +-
 .../java/utils/{IoBuffer.java => ReadBuffer.java}  |  2 +-
 .../org/apache/plc4x/java/utils/WriteBuffer.java   | 69 ++++++++++++++++
 7 files changed, 223 insertions(+), 28 deletions(-)

diff --git a/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index 43e6769..d1c0ed9 100644
--- a/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/sandbox/code-generation/language-template-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -128,7 +128,7 @@ public class JavaLanguageTemplateHelper {
         }
     }
 
-    public String getIoBufferReadMethodCall(SimpleTypeReference simpleTypeReference) {
+    public String getReadBufferReadMethodCall(SimpleTypeReference simpleTypeReference) {
         switch (simpleTypeReference.getBaseType()) {
             case BIT: {
                 return "readBit()";
@@ -179,6 +179,57 @@ public class JavaLanguageTemplateHelper {
         return "Hurz";
     }
 
+    public String getWriteBufferReadMethodCall(SimpleTypeReference simpleTypeReference, String fieldName) {
+        switch (simpleTypeReference.getBaseType()) {
+            case BIT: {
+                return "writeBit((boolean) " + fieldName + ")";
+            }
+            case UINT: {
+                if (simpleTypeReference.getSize() <= 4) {
+                    return "writeUnsignedByte(" + simpleTypeReference.getSize() + ", (byte) " + fieldName + ")";
+                }
+                if (simpleTypeReference.getSize() <= 8) {
+                    return "writeUnsignedShort(" + simpleTypeReference.getSize() + ", (short) " + fieldName + ")";
+                }
+                if (simpleTypeReference.getSize() <= 16) {
+                    return "writeUnsignedInt(" + simpleTypeReference.getSize() + ", (int) " + fieldName + ")";
+                }
+                if (simpleTypeReference.getSize() <= 32) {
+                    return "writeUnsignedLong(" + simpleTypeReference.getSize() + ", (long) " + fieldName + ")";
+                }
+                return "writeUnsignedBigInteger" + simpleTypeReference.getSize() + ", (BigInteger) " + fieldName + ")";
+            }
+            case INT: {
+                if (simpleTypeReference.getSize() <= 8) {
+                    return "writeByte" + simpleTypeReference.getSize() + ", (byte) " + fieldName + ")";
+                }
+                if (simpleTypeReference.getSize() <= 16) {
+                    return "writeShort" + simpleTypeReference.getSize() + ", (short) " + fieldName + ")";
+                }
+                if (simpleTypeReference.getSize() <= 32) {
+                    return "writeInt" + simpleTypeReference.getSize() + ", (int) " + fieldName + ")";
+                }
+                if (simpleTypeReference.getSize() <= 64) {
+                    return "writeLong" + simpleTypeReference.getSize() + ", (long) " + fieldName + ")";
+                }
+                return "writeBigInteger" + simpleTypeReference.getSize() + ", (BigInteger) " + fieldName + ")";
+            }
+            case FLOAT: {
+                if (simpleTypeReference.getSize() <= 32) {
+                    return "writeFloat" + simpleTypeReference.getSize() + ", (float) " + fieldName + ")";
+                }
+                if (simpleTypeReference.getSize() <= 64) {
+                    return "writeDouble" + simpleTypeReference.getSize() + ", (double) " + fieldName + ")";
+                }
+                return "writeBigDecimal" + simpleTypeReference.getSize() + ", (BigDecimal) " + fieldName + ")";
+            }
+            case STRING: {
+                return "writeString" + simpleTypeReference.getSize() + ", (String) " + fieldName + ")";
+            }
+        }
+        return "Hurz";
+    }
+
     public String getReadMethodName(SimpleTypeReference simpleTypeReference) {
         String languageTypeName = getLanguageTypeNameForSpecType(simpleTypeReference);
         languageTypeName = languageTypeName.substring(0, 1).toUpperCase() + languageTypeName.substring(1);
diff --git a/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh b/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh
index 1bd0927..019eb20 100644
--- a/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh
+++ b/sandbox/code-generation/language-template-java/src/main/resources/templates/java/io-template.ftlh
@@ -40,8 +40,9 @@ package ${packageName}.io;
 
 import ${packageName}.*;
 import org.apache.commons.jexl3.*;
-import org.apache.plc4x.java.utils.IoBuffer;
+import org.apache.plc4x.java.utils.ReadBuffer;
 import org.apache.plc4x.java.utils.ParseException;
+import org.apache.plc4x.java.utils.WriteBuffer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,7 +54,7 @@ public class ${typeName}IO  {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(${typeName}IO.class);
 
-    public static <#if helper.isDiscriminatedType(type)>${typeName}Builder<#else>${typeName}</#if> parse(IoBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForSpecType(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
+    public static <#if helper.isDiscriminatedType(type)>${typeName}Builder<#else>${typeName}</#if> parse(ReadBuffer io<#if type.parserArguments?has_content>, <#list type.parserArguments as parserArgument>${helper.getLanguageTypeNameForSpecType(parserArgument.type)} ${parserArgument.name}<#sep>, </#sep></#list></#if>) throws ParseException {
         JexlEngine jexl = new JexlBuilder().create();
         JexlContext jc = new MapContext();
         <#if type.parserArguments?has_content>
@@ -67,18 +68,19 @@ public class ${typeName}IO  {
         // Array field
         JexlExpression ex${field.name} = jexl.createExpression("${field.lengthExpression}");
         int size = (int) ex${field.name}.evaluate(jc);
-        List<${helper.getLanguageTypeNameForSpecType(field.type)}> ${field.name}List = <#if helper.isCountArray(field)>new ArrayList<>(size)<#else>new LinkedList<>()</#if>;
         <#if helper.isCountArray(field)>
+        ${helper.getLanguageTypeNameForSpecType(field.type)}[] ${field.name} = new ${helper.getLanguageTypeNameForSpecType(field.type)}[size];
         for(int i = 0; i < size; i++) {
-            ${field.name}List.add(<#if helper.isSimpleType(field.type)>io.${helper.getIoBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>${parserArgument}<#sep>, </#sep></#list></#if>)</#if>);
+            ${field.name}[i] = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>${parserArgument}<#sep>, </#sep></#list></#if>)</#if>;
         }
         <#else>
+        List<${helper.getLanguageTypeNameForSpecType(field.type)}> ${field.name}List = <#if helper.isCountArray(field)>new ArrayList<>(size)<#else>new LinkedList<>()</#if>;
         int endPos = io.getPos() + size;
         while(io.getPos() < endPos) {
-            ${field.name}List.add(<#if helper.isSimpleType(field.type)>io.${helper.getIoBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>${parserArgument}<#sep>, </#sep></#list></#if>)</#if>);
+            ${field.name}List.add(<#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>${parserArgument}<#sep>, </#sep></#list></#if>)</#if>);
         }
-        </#if>
         ${helper.getLanguageTypeNameForSpecType(field.type)}[] ${field.name} = ${field.name}List.toArray(new ${helper.getLanguageTypeNameForSpecType(field.type)}[0]);
+        </#if>
         jc.set("${field.name}", ${field.name});
         <#break>
     <#case "const">
@@ -90,7 +92,6 @@ public class ${typeName}IO  {
         }
         jc.set("${field.name}", ${field.name});
         <#break>
-
     <#case "context">
 
         // Context Field (Artificial value not retrieved by the input, but the context)
@@ -115,7 +116,7 @@ public class ${typeName}IO  {
         // Optional Field (Can be skipped, if a given expression evaluates to false)
         ${helper.getLanguageTypeNameForSpecType(field.type)} ${field.name} = ${helper.getNullValueForType(field.type)};
         if(${field.conditionExpression}) {
-            ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getIoBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io);</#if>;
+            ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io);</#if>;
         }
         jc.set("${field.name}", ${field.name});
         <#break>
@@ -132,7 +133,7 @@ public class ${typeName}IO  {
     <#case "simple">
 
         // Simple field
-        ${helper.getLanguageTypeNameForSpecType(field.type)} ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getIoBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>${parserArgument}<#sep>, </#sep></#list></#if>)</#if>;
+        ${helper.getLanguageTypeNameForSpecType(field.type)} ${field.name} = <#if helper.isSimpleType(field.type)>io.${helper.getReadBufferReadMethodCall(field.type)}<#else>${field.type.name}IO.parse(io<#if field.params?has_content>, <#list field.params as parserArgument>${parserArgument}<#sep>, </#sep></#list></#if>)</#if>;
         jc.set("${field.name}", ${field.name});
         <#break>
     <#case "switch">
@@ -162,6 +163,83 @@ public class ${typeName}IO  {
         </#if>
     }
 
+    public static void serialize(WriteBuffer io, ${typeName} value) throws ParseException {
+        JexlEngine jexl = new JexlBuilder().create();
+        JexlContext jc = new MapContext();
+        jc.set("this", value);
+<#list type.fields as field>
+<#switch field.typeName>
+    <#case "array">
+
+        // Array field
+        if(value.get${field.name?cap_first}() != null) {
+            for(${helper.getLanguageTypeNameForSpecType(field.type)} element : value.get${field.name?cap_first}()) {
+                <#if helper.isSimpleType(field.type)>
+                io.${helper.getWriteBufferReadMethodCall(field.type, "element")};
+                <#else>
+                ${helper.getLanguageTypeNameForSpecType(field.type)}IO.serialize(io, element);
+                </#if>
+            }
+        }
+        <#break>
+    <#case "const">
+
+        // Const Field
+        io.${helper.getWriteBufferReadMethodCall(field.type, field.referenceValue)};
+        <#break>
+    <#case "context">
+
+        // Context Field (Artificial value not retrieved by the input, but the context)
+        <#break>
+    <#case "discriminator">
+
+        // Discriminator Field (Used as input to a switch field)
+        io.${helper.getWriteBufferReadMethodCall(field.type, "value.getDiscriminatorValues()[0]")};
+        <#break>
+    <#case "implicit">
+
+        // Implicit Field (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
+        JexlExpression ex${field.name?cap_first} = jexl.createExpression("${field.serializationExpression}");
+        io.${helper.getWriteBufferReadMethodCall(field.type, "ex" + field.name?cap_first + ".evaluate(jc)")};
+        <#break>
+    <#case "optional">
+
+        // Optional Field (Can be skipped, if a given expression evaluates to false)
+        if(value.get${field.name?cap_first}() != null) {
+            <#if helper.isSimpleType(field.type)>
+            io.${helper.getWriteBufferReadMethodCall(field.type, "value.get" + field.name?cap_first + "()")};
+            <#else>
+            ${helper.getLanguageTypeNameForSpecType(field.type)}IO.serialize(io, value.get${field.name?cap_first}());
+            </#if>
+        }
+        <#break>
+    <#case "reserved">
+
+        // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
+        io.${helper.getWriteBufferReadMethodCall(field.type, field.referenceValue)};
+        <#break>
+    <#case "simple">
+
+        // Simple field
+        <#if helper.isSimpleType(field.type)>
+        io.${helper.getWriteBufferReadMethodCall(field.type, "value.get" + field.name?cap_first + "()")};
+        <#else>
+        ${helper.getLanguageTypeNameForSpecType(field.type)}IO.serialize(io, value.get${field.name?cap_first}());
+        </#if>
+        <#break>
+    <#case "switch">
+
+        // Switch field (Depending on the discriminator values, passes the instantiation to a sub-type)
+        <#list field.cases as case>
+        if(value instanceof ${case.name}) {
+            ${case.name}IO.serialize(io, (${case.name}) value);
+        }<#sep> else </#sep>
+        </#list>
+        <#break>
+</#switch>
+</#list>
+    }
+
 <#if type.abstract>
     public static interface ${typeName}Builder {
         ${typeName} build(<#list type.propertyFields as field>${helper.getLanguageTypeNameForSpecType(field.type)}<#if field.lengthType??>[]</#if> ${field.name}<#sep>, </#sep></#list>);
diff --git a/sandbox/code-generation/language-template-java/src/main/resources/templates/java/pojo-template.ftlh b/sandbox/code-generation/language-template-java/src/main/resources/templates/java/pojo-template.ftlh
index 2dd7a11..7582c63 100644
--- a/sandbox/code-generation/language-template-java/src/main/resources/templates/java/pojo-template.ftlh
+++ b/sandbox/code-generation/language-template-java/src/main/resources/templates/java/pojo-template.ftlh
@@ -42,9 +42,9 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 <#if helper.isDiscriminatedType(type)>
 
     // Discriminator values used by the parser to determine the type to be used. All values have to apply.
-    public static final String[] DISCRIMINATOR_VALUES = new String[] {
+    public static final Object[] DISCRIMINATOR_VALUES = new String[] {
     <#list type.discriminatorValues as discriminatorValue>
-        "${discriminatorValue}"<#sep>, </#sep>
+        ${discriminatorValue}<#sep>, </#sep>
     </#list>
     };
 </#if>
@@ -73,11 +73,11 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
     }
 <#if type.abstract>
 
-    public abstract String[] getDiscriminatorValues();
+    public abstract Object[] getDiscriminatorValues();
 </#if>
 <#if helper.isDiscriminatedType(type)>
 
-    public String[] getDiscriminatorValues() {
+    public Object[] getDiscriminatorValues() {
         return DISCRIMINATOR_VALUES;
     }
 </#if>
diff --git a/sandbox/code-generation/plc4x-maven-plugin/src/test/resources/specs/s7.spec b/sandbox/code-generation/plc4x-maven-plugin/src/test/resources/specs/s7.spec
index e95c5bf..3ae0a1b 100644
--- a/sandbox/code-generation/plc4x-maven-plugin/src/test/resources/specs/s7.spec
+++ b/sandbox/code-generation/plc4x-maven-plugin/src/test/resources/specs/s7.spec
@@ -3,7 +3,7 @@
 ////////////////////////////////////////////////////////////////
 
 [type 'TPKTPacket'
-    [const    uint 8     'protocolId' '0x3']
+    [const    uint 8     'protocolId' '0x03']
     [reserved uint 8     '0x00']
     [implicit uint 16    'len'        'payload.size + 4']
     [field    COTPPacket 'payload']
@@ -83,15 +83,12 @@
     [implicit      uint 16 'payloadLength'   'payloads.size']
     [typeSwitch 'messageType'
         ['0x01' S7MessageRequest
-            [context string 'messageType' '"request"']
         ]
         ['0x03' S7MessageResponse
-            [context string 'messageType' '"response"']
             [field uint 8 'errorClass']
             [field uint 8 'errorCode']
         ]
         ['0x07' S7MessageUserData
-            [context string 'messageType' '"userData"']
         ]
     ]
     [field S7Parameter 'parameter' ['messageType']]
@@ -110,21 +107,21 @@
             [field    uint 16 'maxAmqCallee']
             [field    uint 16 'pduLength']
         ]
-        ['0x04','request' S7ParameterReadVarRequest
+        ['0x04','0x01' S7ParameterReadVarRequest
             [implicit   uint 8                    'numItems' 'items.size']
             [arrayField S7VarRequestParameterItem 'items'    count 'numItems']
         ]
-        ['0x04','response' S7ParameterReadVarResponse
+        ['0x04','0x03' S7ParameterReadVarResponse
             [field uint 8 'numItems']
         ]
-        ['0x05','request' S7ParameterWriteVarRequest
+        ['0x05','0x01' S7ParameterWriteVarRequest
             [implicit   uint 8                    'numItems' 'items.size']
             [arrayField S7VarRequestParameterItem 'items'    count 'numItems']
         ]
-        ['0x05','response' S7ParameterWriteVarResponse
+        ['0x05','0x03' S7ParameterWriteVarResponse
             [field uint 8 'numItems']
         ]
-        ['0x00','userData' S7ParameterUserData
+        ['0x00','0x07' S7ParameterUserData
             [implicit   uint 8       'numItems' 'items.size']
             [arrayField UserDataItem 'items' count 'numItems']
         ]
diff --git a/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec b/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec
index fae81f4..c364d54 100644
--- a/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec
+++ b/sandbox/code-generation/protocol-s7/src/main/resources/protocols/s7/protocol.spec
@@ -3,7 +3,7 @@
 ////////////////////////////////////////////////////////////////
 
 [type 'TPKTPacket'
-    [const    uint 8     'protocolId' '0x3']
+    [const    uint 8     'protocolId' '0x03']
     [reserved uint 8     '0x00']
     [implicit uint 16    'len'        'payload.size + 4']
     [field    COTPPacket 'payload']
@@ -162,9 +162,9 @@
             [field         uint 16 'cpuFunctionType']
             [field         uint 8  'subFunctionGroup']
             [field         uint 8  'sequenceNumber']
-            [optionalField uint 8  'dataUnitReferenceNumber' 'parameterLength == 8']
-            [optionalField uint 8  'lastDataUnit' 'parameterLength == 8']
-            [optionalField uint 8  'errorCode' 'parameterLength == 8']
+            [optionalField uint 8  'dataUnitReferenceNumber' 'size == 8']
+            [optionalField uint 8  'lastDataUnit' 'size == 8']
+            [optionalField uint 8  'errorCode' 'size == 8']
         ]
     ]
 ]
diff --git a/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/IoBuffer.java b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/ReadBuffer.java
similarity index 98%
rename from sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/IoBuffer.java
rename to sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/ReadBuffer.java
index 18652e6..0524629 100644
--- a/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/IoBuffer.java
+++ b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/ReadBuffer.java
@@ -22,7 +22,7 @@ package org.apache.plc4x.java.utils;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
-public class IoBuffer {
+public class ReadBuffer {
 
     public int getPos() {
         return 0;
diff --git a/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
new file mode 100644
index 0000000..44aadf7
--- /dev/null
+++ b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/WriteBuffer.java
@@ -0,0 +1,69 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package org.apache.plc4x.java.utils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class WriteBuffer {
+
+    public void writeBit(boolean value) {
+    }
+
+    public void writeUnsignedByte(int bitLength, byte value) {
+    }
+
+    public void writeUnsignedShort(int bitLength, short value) {
+    }
+
+    public void writeUnsignedInt(int bitLength, int value) {
+    }
+
+    public void writeUnsignedLong(int bitLength, long value) {
+    }
+
+    public void writeUnsignedBigInteger(int bitLength, BigInteger value) {
+    }
+
+    public void writeByte(int bitLength, byte value) {
+    }
+
+    public void writeShort(int bitLength, short value) {
+    }
+
+    public void writeInt(int bitLength, int value) {
+    }
+
+    public void writeLong(int bitLength, long value) {
+    }
+
+    public void writeBigInteger(int bitLength, BigInteger value) {
+    }
+
+    public void writeFloat(int bitLength, float value) {
+    }
+
+    public void writeDouble(int bitLength, double value) {
+    }
+
+    public void writeBigDecimal(int bitLength, BigDecimal value) {
+    }
+
+}