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) {
+ }
+
+}