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/06/07 13:12:51 UTC
[plc4x] branch feature/code-gen updated: - Finished implementing a
first working version of 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 0dc23da - Finished implementing a first working version of the serialization.
0dc23da is described below
commit 0dc23da026b9c63fd7dcb93bfd9381b72509a4e5
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Fri Jun 7 15:12:31 2019 +0200
- Finished implementing a first working version of the serialization.
---
.../language/java/JavaLanguageTemplateHelper.java | 18 +--
.../main/resources/templates/java/io-template.ftlh | 34 +++--
.../resources/templates/java/pojo-template.ftlh | 94 ++++++++++++-
.../codegenerator/parser/imaginary/Imaginary.g4 | 4 +-
.../src/main/resources/protocols/s7/protocol.spec | 24 ++--
.../code-generation/test-java-s7-driver/pom.xml | 5 +
.../github/jinahya/bit/io/MyDefaultBitInput.java | 35 +++++
.../org/apache/plc4x/java/utils/ReadBuffer.java | 31 ++---
.../org/apache/plc4x/java/utils/SizeAware.java | 26 ++++
.../org/apache/plc4x/java/utils/WriteBuffer.java | 155 ++++++++++++++++-----
.../src/test/java/BenchmarkGeneratedS7.java | 44 +++++-
11 files changed, 382 insertions(+), 88 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 744bc4c..d57b64c 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
@@ -190,31 +190,31 @@ public class JavaLanguageTemplateHelper {
}
case UINT: {
if (simpleTypeReference.getSize() <= 4) {
- return "writeUnsignedByte(" + simpleTypeReference.getSize() + ", (byte) " + fieldName + ")";
+ return "writeUnsignedByte(" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").byteValue())";
}
if (simpleTypeReference.getSize() <= 8) {
- return "writeUnsignedShort(" + simpleTypeReference.getSize() + ", (short) " + fieldName + ")";
+ return "writeUnsignedShort(" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").shortValue())";
}
if (simpleTypeReference.getSize() <= 16) {
- return "writeUnsignedInt(" + simpleTypeReference.getSize() + ", (int) " + fieldName + ")";
+ return "writeUnsignedInt(" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").intValue())";
}
if (simpleTypeReference.getSize() <= 32) {
- return "writeUnsignedLong(" + simpleTypeReference.getSize() + ", (long) " + fieldName + ")";
+ return "writeUnsignedLong(" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").longValue()";
}
return "writeUnsignedBigInteger" + simpleTypeReference.getSize() + ", (BigInteger) " + fieldName + ")";
}
case INT: {
if (simpleTypeReference.getSize() <= 8) {
- return "writeByte" + simpleTypeReference.getSize() + ", (byte) " + fieldName + ")";
+ return "writeByte" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").byteValue())";
}
if (simpleTypeReference.getSize() <= 16) {
- return "writeShort" + simpleTypeReference.getSize() + ", (short) " + fieldName + ")";
+ return "writeShort" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").shortValue())";
}
if (simpleTypeReference.getSize() <= 32) {
- return "writeInt" + simpleTypeReference.getSize() + ", (int) " + fieldName + ")";
+ return "writeInt" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").intValue())";
}
if (simpleTypeReference.getSize() <= 64) {
- return "writeLong" + simpleTypeReference.getSize() + ", (long) " + fieldName + ")";
+ return "writeLong" + simpleTypeReference.getSize() + ", ((Number) " + fieldName + ").longValue())";
}
return "writeBigInteger" + simpleTypeReference.getSize() + ", (BigInteger) " + fieldName + ")";
}
@@ -272,7 +272,7 @@ public class JavaLanguageTemplateHelper {
}
public String toWriteExpression(String expression) {
- return null;
+ return expression;
}
}
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 f167a8a..5b14c11 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
@@ -66,11 +66,16 @@ public class ${typeName}IO {
private static JexlExpression ex${field.name?cap_first};
<#assign needJexl=true>
<#break>
- </#switch>
+ <#case "implicit">
+ private static JexlExpression ex${field.name?cap_first};
+ <#assign needJexl=true>
+ <#break>
+</#switch>
</#list>
<#if needJexl>
+ private static JexlEngine jexl;
static {
- JexlEngine jexl = new JexlBuilder().create();
+ jexl = new JexlBuilder().create();
<#list type.fields as field>
<#switch field.typeName>
<#case "array">
@@ -79,6 +84,9 @@ public class ${typeName}IO {
<#case "optional">
ex${field.name?cap_first} = jexl.createExpression("${field.conditionExpression}");
<#break>
+ <#case "implicit">
+ ex${field.name?cap_first} = jexl.createExpression("${field.serializationExpression}");
+ <#break>
</#switch>
</#list>
}
@@ -86,11 +94,13 @@ public class ${typeName}IO {
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 {
int startPos = io.getPos();
+<#if needJexl>
JexlContext jc = new MapContext();
<#if type.parserArguments?has_content>
<#list type.parserArguments as parserArgument>
jc.set("${parserArgument.name}", ${parserArgument.name});
</#list></#if>
+</#if>
<#list type.fields as field>
<#switch field.typeName>
<#case "array">
@@ -122,19 +132,25 @@ public class ${typeName}IO {
if(${field.name} != ${typeName}.${field.name?upper_case}) {
throw new ParseException("Expected constant value " + ${typeName}.${field.name?upper_case} + " but got " + ${field.name});
}
+<#if needJexl>
jc.set("${field.name}", ${field.name});
+</#if>
<#break>
<#case "discriminator">
// Discriminator Field (Used as input to a switch field)
${helper.getLanguageTypeNameForSpecType(field.type)} ${field.name} = io.${helper.getReadMethodName(field.type)}(${field.type.size});
+<#if needJexl>
jc.set("${field.name}", ${field.name});
- <#break>
+</#if>
+ <#break>
<#case "implicit">
// Implicit Field (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
${helper.getLanguageTypeNameForSpecType(field.type)} ${field.name} = io.${helper.getReadMethodName(field.type)}(${field.type.size});
+<#if needJexl>
jc.set("${field.name}", ${field.name});
+</#if>
<#break>
<#case "optional">
@@ -159,7 +175,9 @@ public class ${typeName}IO {
// Simple field
${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>;
+<#if needJexl>
jc.set("${field.name}", ${field.name});
+</#if>
<#break>
<#case "switch">
@@ -188,9 +206,9 @@ public class ${typeName}IO {
}
public static void serialize(WriteBuffer io, ${typeName} value) throws ParseException {
- JexlEngine jexl = new JexlBuilder().create();
- JexlContext jc = new MapContext();
- jc.set("this", value);
+<#if needJexl>
+ JexlContext jc = new ObjectContext<>(jexl, value);
+</#if>
<#list type.fields as field>
<#switch field.typeName>
<#case "array">
@@ -223,13 +241,11 @@ public class ${typeName}IO {
<#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)
- JexlExpression ex${field.name?cap_first} = jexl.createExpression("${field.conditionExpression}");
if(ex${field.name?cap_first}.evaluate(jc) == Boolean.TRUE) {
<#if helper.isSimpleType(field.type)>
io.${helper.getWriteBufferReadMethodCall(field.type, "value.get" + field.name?cap_first + "()")};
@@ -240,7 +256,7 @@ public class ${typeName}IO {
<#break>
<#case "reserved">
- // Reserved Field (Compartmentalized so the "reserved" variable can't leak)
+ // Reserved Field.
io.${helper.getWriteBufferReadMethodCall(field.type, field.referenceValue)};
<#break>
<#case "simple">
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 2beed05..45bdf89 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
@@ -38,7 +38,34 @@ ${packageName?replace(".", "/")}/${typeName}.java
package ${packageName};
-public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??> extends ${type.parentType.name}</#if> {
+import org.apache.commons.jexl3.*;
+import org.apache.plc4x.java.utils.SizeAware;
+
+public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??> extends ${type.parentType.name}</#if> implements SizeAware {
+
+<#assign needJexl=false>
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "optional">
+ private static JexlExpression ex${field.name?cap_first};
+ <#assign needJexl=true>
+ <#break>
+</#switch>
+</#list>
+<#if needJexl>
+ private static JexlEngine jexl;
+ static {
+ jexl = new JexlBuilder().create();
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "optional">
+ ex${field.name?cap_first} = jexl.createExpression("${field.conditionExpression}");
+ <#break>
+</#switch>
+</#list>
+ }
+</#if>
+
<#if helper.isDiscriminatedType(type)>
// Discriminator values used by the parser to determine the type to be used. All values have to apply.
@@ -88,4 +115,69 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
}
</#list>
+ @Override
+ public int getLengthInBytes() {
+<#if needJexl>
+ JexlContext jc = new ObjectContext<>(jexl, this);
+</#if>
+ int lengthInBits = <#if type.parentType??>super.getLengthInBytes() * 8<#else>0</#if>;
+<#list type.fields as field>
+<#switch field.typeName>
+ <#case "array">
+
+ // Array field
+ <#if helper.isSimpleType(field.type)>
+ lengthInBits += ${field.type.size} * ${field.name}.length;
+ <#else>
+ for(SizeAware element : ${field.name}) {
+ lengthInBits += element.getLengthInBytes() * 8;
+ }
+ </#if>
+ <#break>
+ <#case "const">
+
+ // Const Field (${field.name})
+ lengthInBits += ${field.type.size};
+ <#break>
+ <#case "discriminator">
+
+ // Discriminator Field (${field.name})
+ lengthInBits += ${field.type.size};
+ <#break>
+ <#case "implicit">
+
+ // Implicit Field (${field.name})
+ lengthInBits += ${field.type.size};
+ <#break>
+ <#case "optional">
+
+ // Optional Field (${field.name})
+ if(ex${field.name?cap_first}.evaluate(jc) == Boolean.TRUE) {
+ lengthInBits += ${field.type.size};
+ }
+ <#break>
+ <#case "reserved">
+
+ // Reserved Field
+ lengthInBits += ${field.type.size};
+ <#break>
+ <#case "simple">
+
+ // Simple field (${field.name})
+ <#if helper.isSimpleType(field.type)>
+ lengthInBits += ${field.type.size};
+ <#else>
+ lengthInBits += ${field.name}.getLengthInBytes() * 8;
+ </#if>
+ <#break>
+ <#case "switch">
+
+ // Length of sub-type elements will be added by sub-type...
+ <#break>
+</#switch>
+</#list>
+
+ return lengthInBits / 8;
+ }
+
}
\ No newline at end of file
diff --git a/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4 b/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4
index 6a866a4..1448442 100644
--- a/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4
+++ b/sandbox/code-generation/plc4x-maven-plugin/src/main/antlr4/org/apache/plc4x/codegenerator/parser/imaginary/Imaginary.g4
@@ -117,8 +117,8 @@ multipleExpressions
innerExpression
: HEX_LITERAL
| INTEGER_LITERAL
- | IDENTIFIER // Variable reference
- | innerExpression '.' IDENTIFIER // Field Reference
+ | IDENTIFIER '()'? // Variable reference or method call
+ | innerExpression '.' IDENTIFIER '()'? // Field Reference or method call
| innerExpression BinaryOperator innerExpression // Addition
| innerExpression LBRACKET INTEGER_LITERAL RBRACKET
| '(' innerExpression ')'
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 66e9fe9..18bcab0 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
@@ -5,7 +5,7 @@
[type 'TPKTPacket'
[const uint 8 'protocolId' '0x03']
[reserved uint 8 '0x00']
- [implicit uint 16 'len' 'payload.size + 4']
+ [implicit uint 16 'len' 'payload.lengthInBytes + 4']
[field COTPPacket 'payload']
]
@@ -14,7 +14,7 @@
////////////////////////////////////////////////////////////////
[discriminatedType 'COTPPacket'
- [implicit uint 8 'headerLength' 'size - (payload.size + 1)']
+ [implicit uint 8 'headerLength' 'lengthInBytes - (payload.lengthInBytes + 1)']
[discriminator uint 8 'tpduCode']
[typeSwitch 'tpduCode'
['0xF0' COTPPacketData
@@ -79,8 +79,8 @@
[discriminator uint 8 'messageType']
[reserved uint 16 '0x0000']
[field uint 16 'tpduReference']
- [implicit uint 16 'parameterLength' 'parameters.size']
- [implicit uint 16 'payloadLength' 'payloads.size']
+ [implicit uint 16 'parameterLength' 'parameter.lengthInBytes']
+ [implicit uint 16 'payloadLength' 'payload.lengthInBytes']
[typeSwitch 'messageType'
['0x01' S7MessageRequest
]
@@ -108,21 +108,21 @@
[field uint 16 'pduLength']
]
['0x04','0x01' S7ParameterReadVarRequest
- [implicit uint 8 'numItems' 'items.size']
+ [implicit uint 8 'numItems' 'items.size()']
[arrayField S7VarRequestParameterItem 'items' count 'numItems']
]
['0x04','0x03' S7ParameterReadVarResponse
[field uint 8 'numItems']
]
['0x05','0x01' S7ParameterWriteVarRequest
- [implicit uint 8 'numItems' 'items.size']
+ [implicit uint 8 'numItems' 'items.size()']
[arrayField S7VarRequestParameterItem 'items' count 'numItems']
]
['0x05','0x03' S7ParameterWriteVarResponse
[field uint 8 'numItems']
]
['0x00','0x07' S7ParameterUserData
- [implicit uint 8 'numItems' 'items.size']
+ [implicit uint 8 'numItems' 'items.size()']
[arrayField UserDataItem 'items' count 'numItems']
]
]
@@ -132,7 +132,7 @@
[discriminator uint 8 'parameterItemType']
[typeSwitch 'parameterItemType'
['0x12' S7VarRequestParameterItemAddress
- [implicit uint 8 'addressLength' 'address.size']
+ [implicit uint 8 'addressLength' 'address.lengthInBytes']
[field S7Address 'address']
]
]
@@ -158,13 +158,13 @@
[discriminator uint 8 'itemType']
[typeSwitch 'itemType'
['0x12' UserDataItemCPUFunctions
- [implicit uint 8 'parameterLength' 'size']
+ [implicit uint 8 'parameterLength' 'lengthInBytes']
[field uint 16 'cpuFunctionType']
[field uint 8 'subFunctionGroup']
[field uint 8 'sequenceNumber']
- [optionalField uint 8 'dataUnitReferenceNumber' 'size == 8']
- [optionalField uint 8 'lastDataUnit' 'size == 8']
- [optionalField uint 8 'errorCode' 'size == 8']
+ [optionalField uint 8 'dataUnitReferenceNumber' 'lengthInBytes == 8']
+ [optionalField uint 8 'lastDataUnit' 'lengthInBytes == 8']
+ [optionalField uint 8 'errorCode' 'lengthInBytes == 8']
]
]
]
diff --git a/sandbox/code-generation/test-java-s7-driver/pom.xml b/sandbox/code-generation/test-java-s7-driver/pom.xml
index 5933593..b1ca6bf 100644
--- a/sandbox/code-generation/test-java-s7-driver/pom.xml
+++ b/sandbox/code-generation/test-java-s7-driver/pom.xml
@@ -66,6 +66,11 @@
<artifactId>commons-compress</artifactId>
<version>1.18</version>
</dependency>
+ <dependency>
+ <groupId>com.github.jinahya</groupId>
+ <artifactId>bit-io</artifactId>
+ <version>1.4.2</version>
+ </dependency>
<dependency>
<groupId>commons-codec</groupId>
diff --git a/sandbox/code-generation/test-java-s7-driver/src/main/java/com/github/jinahya/bit/io/MyDefaultBitInput.java b/sandbox/code-generation/test-java-s7-driver/src/main/java/com/github/jinahya/bit/io/MyDefaultBitInput.java
new file mode 100644
index 0000000..eb538d9
--- /dev/null
+++ b/sandbox/code-generation/test-java-s7-driver/src/main/java/com/github/jinahya/bit/io/MyDefaultBitInput.java
@@ -0,0 +1,35 @@
+/*
+ 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 com.github.jinahya.bit.io;
+
+/**
+ * Modified version that exposes the position.
+ */
+public class MyDefaultBitInput extends DefaultBitInput<ArrayByteInput> {
+
+ public MyDefaultBitInput(ArrayByteInput delegate) {
+ super(delegate);
+ }
+
+ public long getPos() {
+ return count;
+ }
+
+}
diff --git a/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/ReadBuffer.java b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/ReadBuffer.java
index ff059dc..17ac0c1 100644
--- a/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/ReadBuffer.java
+++ b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/ReadBuffer.java
@@ -19,31 +19,28 @@
package org.apache.plc4x.java.utils;
-import org.apache.commons.compress.utils.BitInputStream;
+import com.github.jinahya.bit.io.*;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
-import java.nio.ByteOrder;
public class ReadBuffer {
- private BitInputStream bis;
+ private MyDefaultBitInput bi;
-
public ReadBuffer(byte[] input) {
- ByteArrayInputStream bais = new ByteArrayInputStream(input);
- bis = new BitInputStream(bais, ByteOrder.BIG_ENDIAN);
+ ArrayByteInput abi = new ArrayByteInput(input);
+ bi = new MyDefaultBitInput(abi);
}
public int getPos() {
- return (int) bis.getBytesRead();
+ return (int) bi.getPos();
}
public boolean readBit() throws ParseException {
try {
- return bis.readBits(1) == 1;
+ return bi.readBoolean();
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -57,7 +54,7 @@ public class ReadBuffer {
throw new ParseException("unsigned byte can only contain max 4 bits");
}
try {
- return (byte) bis.readBits(bitLength);
+ return bi.readByte(true, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -71,7 +68,7 @@ public class ReadBuffer {
throw new ParseException("unsigned short can only contain max 8 bits");
}
try {
- return (short) bis.readBits(bitLength);
+ return bi.readShort(true, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -85,7 +82,7 @@ public class ReadBuffer {
throw new ParseException("unsigned int can only contain max 16 bits");
}
try {
- return (int) bis.readBits(bitLength);
+ return bi.readInt(true, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -99,7 +96,7 @@ public class ReadBuffer {
throw new ParseException("unsigned long can only contain max 32 bits");
}
try {
- return bis.readBits(bitLength);
+ return bi.readLong(true, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -117,7 +114,7 @@ public class ReadBuffer {
throw new ParseException("byte can only contain max 8 bits");
}
try {
- return (byte) bis.readBits(bitLength);
+ return bi.readByte(false, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -131,7 +128,7 @@ public class ReadBuffer {
throw new ParseException("short can only contain max 16 bits");
}
try {
- return (short) bis.readBits(bitLength);
+ return bi.readShort(false, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -145,7 +142,7 @@ public class ReadBuffer {
throw new ParseException("int can only contain max 32 bits");
}
try {
- return (int) bis.readBits(bitLength);
+ return bi.readInt(false, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
@@ -159,7 +156,7 @@ public class ReadBuffer {
throw new ParseException("long can only contain max 64 bits");
}
try {
- return bis.readBits(bitLength);
+ return bi.readLong(false, bitLength);
} catch (IOException e) {
throw new ParseException("Error reading", e);
}
diff --git a/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/SizeAware.java b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/SizeAware.java
new file mode 100644
index 0000000..c11d379
--- /dev/null
+++ b/sandbox/code-generation/test-java-s7-driver/src/main/java/org/apache/plc4x/java/utils/SizeAware.java
@@ -0,0 +1,26 @@
+/*
+ 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;
+
+public interface SizeAware {
+
+ int getLengthInBytes();
+
+}
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
index 211239d..bfe6de5 100644
--- 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
@@ -19,75 +19,168 @@
package org.apache.plc4x.java.utils;
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
+import com.github.jinahya.bit.io.BitOutput;
+import com.github.jinahya.bit.io.BufferByteOutput;
+import com.github.jinahya.bit.io.DefaultBitOutput;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.nio.ByteBuffer;
public class WriteBuffer {
- private int bytePos;
- private byte bitPos;
- private ByteArrayOutputStream baos;
- private DataOutputStream dos;
+ private ByteBuffer bb;
+ private BufferByteOutput bbo;
+ private BitOutput bo;
- public WriteBuffer() {
- bytePos = 0;
- bitPos = 0;
- baos = new ByteArrayOutputStream();
- dos = new DataOutputStream(baos);
+ public WriteBuffer(int size) {
+ bb = ByteBuffer.allocate(size);
+ bbo = new BufferByteOutput<>(bb);
+ bo = new DefaultBitOutput<>(bbo);
}
- public byte[] getMessage() throws ParseException {
+ public byte[] getData() {
+ return bb.array();
+ }
+
+ public void writeBit(boolean value) throws ParseException {
try {
- dos.flush();
+ bo.writeBoolean(value);
} catch (IOException e) {
- throw new ParseException("Unable to flush buffer");
+ throw new ParseException("Error reading", e);
}
- return baos.toByteArray();
- }
-
- public void writeBit(boolean value) {
}
- public void writeUnsignedByte(int bitLength, byte value) {
+ public void writeUnsignedByte(int bitLength, byte value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("unsigned byte must contain at least 1 bit");
+ }
+ if(bitLength > 4) {
+ throw new ParseException("unsigned byte can only contain max 4 bits");
+ }
+ try {
+ bo.writeByte(true, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeUnsignedShort(int bitLength, short value) {
+ public void writeUnsignedShort(int bitLength, short value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("unsigned short must contain at least 1 bit");
+ }
+ if(bitLength > 8) {
+ throw new ParseException("unsigned short can only contain max 8 bits");
+ }
+ try {
+ bo.writeShort(true, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeUnsignedInt(int bitLength, int value) {
+ public void writeUnsignedInt(int bitLength, int value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("unsigned int must contain at least 1 bit");
+ }
+ if(bitLength > 16) {
+ throw new ParseException("unsigned int can only contain max 16 bits");
+ }
+ try {
+ bo.writeInt(true, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeUnsignedLong(int bitLength, long value) {
+ public void writeUnsignedLong(int bitLength, long value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("unsigned long must contain at least 1 bit");
+ }
+ if(bitLength > 32) {
+ throw new ParseException("unsigned long can only contain max 32 bits");
+ }
+ try {
+ bo.writeLong(true, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeUnsignedBigInteger(int bitLength, BigInteger value) {
+ public void writeUnsignedBigInteger(int bitLength, BigInteger value) throws ParseException {
+ throw new UnsupportedOperationException("not implemented yet");
}
- public void writeByte(int bitLength, byte value) {
+ public void writeByte(int bitLength, byte value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("byte must contain at least 1 bit");
+ }
+ if(bitLength > 8) {
+ throw new ParseException("byte can only contain max 8 bits");
+ }
+ try {
+ bo.writeByte(false, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeShort(int bitLength, short value) {
+ public void writeShort(int bitLength, short value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("short must contain at least 1 bit");
+ }
+ if(bitLength > 16) {
+ throw new ParseException("short can only contain max 16 bits");
+ }
+ try {
+ bo.writeShort(false, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeInt(int bitLength, int value) {
+ public void writeInt(int bitLength, int value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("int must contain at least 1 bit");
+ }
+ if(bitLength > 32) {
+ throw new ParseException("int can only contain max 32 bits");
+ }
+ try {
+ bo.writeInt(false, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeLong(int bitLength, long value) {
+ public void writeLong(int bitLength, long value) throws ParseException {
+ if(bitLength <= 0) {
+ throw new ParseException("long must contain at least 1 bit");
+ }
+ if(bitLength > 64) {
+ throw new ParseException("long can only contain max 64 bits");
+ }
+ try {
+ bo.writeLong(false, bitLength, value);
+ } catch (IOException e) {
+ throw new ParseException("Error reading", e);
+ }
}
- public void writeBigInteger(int bitLength, BigInteger value) {
+ public void writeBigInteger(int bitLength, BigInteger value) throws ParseException {
+ throw new UnsupportedOperationException("not implemented yet");
}
- public void writeFloat(int bitLength, float value) {
+ public void writeFloat(int bitLength, float value) throws ParseException {
+ throw new UnsupportedOperationException("not implemented yet");
}
- public void writeDouble(int bitLength, double value) {
+ public void writeDouble(int bitLength, double value) throws ParseException {
+ throw new UnsupportedOperationException("not implemented yet");
}
- public void writeBigDecimal(int bitLength, BigDecimal value) {
+ public void writeBigDecimal(int bitLength, BigDecimal value) throws ParseException {
+ throw new UnsupportedOperationException("not implemented yet");
}
}
diff --git a/sandbox/code-generation/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java b/sandbox/code-generation/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
index 9ba58b3..a0a7fb3 100644
--- a/sandbox/code-generation/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
+++ b/sandbox/code-generation/test-java-s7-driver/src/test/java/BenchmarkGeneratedS7.java
@@ -21,20 +21,50 @@ import org.apache.commons.codec.binary.Hex;
import org.apache.plc4x.java.s7.TPKTPacket;
import org.apache.plc4x.java.s7.io.TPKTPacketIO;
import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.java.utils.WriteBuffer;
+
+import java.util.Arrays;
public class BenchmarkGeneratedS7 {
public static void main(String[] args) throws Exception {
- byte[] data = Hex.decodeHex("0300006702f080320100000001005600000407120a10060001032b84000160120a10020001032b840001a0120a10010001032b840001a9120a10050001032b84000150120a10020001032b84000198120a10040001032b84000140120a10020001032b84000190");
+ // 00
+ byte[] rData = Hex.decodeHex("0300006702f080320100000001005600000407120a10060001032b84000160120a10020001032b840001a0120a10010001032b840001a9120a10050001032b84000150120a10020001032b84000198120a10040001032b84000140120a10020001032b84000190");
long start = System.currentTimeMillis();
- int numRuns = 20000;
+ int numRuns = 1;
+
+ // Benchmark the parsing code
+ TPKTPacket packet = null;
+ for(int i = 0; i < numRuns; i++) {
+ ReadBuffer rBuf = new ReadBuffer(rData);
+ packet = TPKTPacketIO.parse(rBuf);
+ }
+ long endParsing = System.currentTimeMillis();
+
+ System.out.println("Parsed " + numRuns + " packets in " + (endParsing - start) + "ms");
+ System.out.println("That's " + ((float) (endParsing - start) / numRuns) + "ms per packet");
+
+ // Benchmark the serializing code
+ byte[] oData = null;
for(int i = 0; i < numRuns; i++) {
- ReadBuffer buf = new ReadBuffer(data);
- TPKTPacket packet = TPKTPacketIO.parse(buf);
+ WriteBuffer wBuf = new WriteBuffer(packet.getLengthInBytes());
+ TPKTPacketIO.serialize(wBuf, packet);
+ oData = wBuf.getData();
+ }
+ long endSerializing = System.currentTimeMillis();
+
+ System.out.println("Serialized " + numRuns + " packets in " + (endSerializing - endParsing) + "ms");
+ System.out.println("That's " + ((float) (endSerializing - endParsing) / numRuns) + "ms per packet");
+ if(!Arrays.equals(rData, oData)) {
+ for(int i = 0; i < rData.length; i++) {
+ if(rData[i] != oData[i]) {
+ System.out.println("Difference in byte " + i);
+ }
+ }
+ System.out.println("Not equals");
+ } else {
+ System.out.println("Bytes equal");
}
- long end = System.currentTimeMillis();
- System.out.println("Parsed " + numRuns + " packets in " + (end - start) + "ms");
- System.out.println("That's " + ((float) (end - start) / numRuns) + "ms per packet");
}
}