This is an automated email from the ASF dual-hosted git repository.
sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new c533745 plc4j: simple xml based writer
c533745 is described below
commit c53374587d2fcb31b1f98bc291192209c41afe8d
Author: Sebastian Rühl <[email protected]>
AuthorDate: Tue Apr 20 14:16:40 2021 +0200
plc4j: simple xml based writer
---
plc4go/internal/plc4go/spi/utils/ReadBuffer.go | 4 +
.../plc4go/spi/utils/ReadBufferXmlBased.go | 1 +
plc4go/internal/plc4go/spi/utils/WriteBuffer.go | 2 +
plc4j/drivers/s7/src/test/java/s7IoTest.java | 121 +++++++++++
.../plc4x/java/spi/generation/WriteBuffer.java | 1 +
.../java/spi/generation/WriteBufferXmlBased.java | 240 +++++++++++++++++++++
6 files changed, 369 insertions(+)
diff --git a/plc4go/internal/plc4go/spi/utils/ReadBuffer.go
b/plc4go/internal/plc4go/spi/utils/ReadBuffer.go
index 0ebb3a3..3404f44 100644
--- a/plc4go/internal/plc4go/spi/utils/ReadBuffer.go
+++ b/plc4go/internal/plc4go/spi/utils/ReadBuffer.go
@@ -24,8 +24,11 @@ import (
)
type ReadBuffer interface {
+ // GetPos return the current byte position
GetPos() uint16
+ // HasMore returns true if there are bitLength bits available
HasMore(bitLength uint8) bool
+ // PullContext signals that we expect now a context with the supplied
logical name
PullContext(logicalName string, readerArgs ...WithReaderArgs) error
ReadBit(logicalName string, readerArgs ...WithReaderArgs) (bool, error)
ReadUint8(logicalName string, bitLength uint8, readerArgs
...WithReaderArgs) (uint8, error)
@@ -41,6 +44,7 @@ type ReadBuffer interface {
ReadFloat64(logicalName string, singed bool, exponentBitLength uint8,
mantissaBitLength uint8, readerArgs ...WithReaderArgs) (float64, error)
ReadBigFloat(logicalName string, signed bool, exponentBitLength uint8,
mantissaBitLength uint8, readerArgs ...WithReaderArgs) (*big.Float, error)
ReadString(logicalName string, bitLength uint32, readerArgs
...WithReaderArgs) (string, error)
+ // CloseContext signals that we expect the end of the context with the
supplied logical name
CloseContext(logicalName string, readerArgs ...WithReaderArgs) error
}
diff --git a/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go
b/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go
index 2757976..50d43ac 100644
--- a/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go
+++ b/plc4go/internal/plc4go/spi/utils/ReadBufferXmlBased.go
@@ -56,6 +56,7 @@ func (x *xmlReadBuffer) GetPos() uint16 {
}
func (x *xmlReadBuffer) HasMore(bitLength uint8) bool {
+ // TODO: work with x.InputOffset() and check if we are at EOF
return true
}
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBuffer.go
b/plc4go/internal/plc4go/spi/utils/WriteBuffer.go
index 5bbd1c8..1ea6fcd 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBuffer.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBuffer.go
@@ -24,6 +24,7 @@ import (
)
type WriteBuffer interface {
+ // PushContext signals opening context with the supplied logical name
PushContext(logicalName string, writerArgs ...WithWriterArgs) error
WriteBit(logicalName string, value bool, writerArgs ...WithWriterArgs)
error
WriteUint8(logicalName string, bitLength uint8, value uint8, writerArgs
...WithWriterArgs) error
@@ -39,6 +40,7 @@ type WriteBuffer interface {
WriteFloat64(logicalName string, bitLength uint8, value float64,
writerArgs ...WithWriterArgs) error
WriteBigFloat(logicalName string, bitLength uint8, value *big.Float,
writerArgs ...WithWriterArgs) error
WriteString(logicalName string, bitLength uint8, encoding string, value
string, writerArgs ...WithWriterArgs) error
+ // PopContext signals work done with the context with the supplied
logical name
PopContext(logicalName string, writerArgs ...WithWriterArgs) error
}
diff --git a/plc4j/drivers/s7/src/test/java/s7IoTest.java
b/plc4j/drivers/s7/src/test/java/s7IoTest.java
new file mode 100644
index 0000000..977cb9b
--- /dev/null
+++ b/plc4j/drivers/s7/src/test/java/s7IoTest.java
@@ -0,0 +1,121 @@
+/*
+ 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.
+ */
+
+import org.apache.plc4x.java.s7.readwrite.*;
+import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
+import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize;
+import org.apache.plc4x.java.s7.readwrite.types.DataTransportErrorCode;
+import org.apache.plc4x.java.s7.readwrite.types.DataTransportSize;
+import org.apache.plc4x.java.spi.generation.WriteBufferXmlBased;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class s7IoTest {
+
+ @Disabled("Till the output is aligned to the one of golang")
+ @Test
+ void TestS7MessageBytes() throws Exception {
+ String wantXml =
+ "<TPKTPacket>\n" +
+ " <protocolId bitLength=\"8\"
dataType=\"uint8\">3</protocolId>\n" +
+ " <reserved bitLength=\"8\" dataType=\"uint8\">0</reserved>\n" +
+ " <len bitLength=\"16\" dataType=\"uint16\">29</len>\n" +
+ " <COTPPacket>\n" +
+ " <headerLength bitLength=\"8\"
dataType=\"uint18\">5</headerLength>\n" +
+ " <tpduCode bitLength=\"8\"
dataType=\"uint8\">240</tpduCode>\n" +
+ " <COTPPacketData>\n" +
+ " <eot bitLength=\"1\" dataType=\"bit\">false</eot>\n" +
+ " <tpduRef bitLength=\"7\"
dataType=\"uint8\">13</tpduRef>\n" +
+ " </COTPPacketData>\n" +
+ " <parameters>\n" +
+ " <COTPParameter>\n" +
+ " <parameterType bitLength=\"8\"
dataType=\"uint8\">192</parameterType>\n" +
+ " <parameterLength bitLength=\"8\"
dataType=\"uint8\">1</parameterLength>\n" +
+ " <COTPParameterTpduSize>\n" +
+ " <COTPTpduSize bitLength=\"8\"
dataType=\"uint8\" stringRepresentation=\"SIZE_4096\">12</COTPTpduSize>\n" +
+ " </COTPParameterTpduSize>\n" +
+ " </COTPParameter>\n" +
+ " </parameters>\n" +
+ " <S7Message>\n" +
+ " <protocolId bitLength=\"8\"
dataType=\"uint8\">50</protocolId>\n" +
+ " <messageType bitLength=\"8\"
dataType=\"uint8\">3</messageType>\n" +
+ " <reserved bitLength=\"16\"
dataType=\"uint16\">0</reserved>\n" +
+ " <tpduReference bitLength=\"16\"
dataType=\"uint16\">11</tpduReference>\n" +
+ " <parameterLength bitLength=\"16\"
dataType=\"uint16\">2</parameterLength>\n" +
+ " <payloadLength bitLength=\"16\"
dataType=\"uint16\">5</payloadLength>\n" +
+ " <S7MessageResponseData>\n" +
+ " <errorClass bitLength=\"8\"
dataType=\"uint8\">0</errorClass>\n" +
+ " <errorCode bitLength=\"8\"
dataType=\"uint8\">0</errorCode>\n" +
+ " </S7MessageResponseData>\n" +
+ " <S7Parameter>\n" +
+ " <parameterType bitLength=\"8\"
dataType=\"uint8\">4</parameterType>\n" +
+ " <S7ParameterReadVarResponse>\n" +
+ " <numItems bitLength=\"8\"
dataType=\"uint8\">1</numItems>\n" +
+ " </S7ParameterReadVarResponse>\n" +
+ " </S7Parameter>\n" +
+ " <S7Payload>\n" +
+ " <S7PayloadReadVarResponse>\n" +
+ " <items>\n" +
+ " <S7VarPayloadDataItem>\n" +
+ " <DataTransportErrorCode
bitLength=\"8\" dataType=\"uint8\"
stringRepresentation=\"OK\">255</DataTransportErrorCode>\n" +
+ " <DataTransportSize bitLength=\"8\"
dataType=\"uint8\" stringRepresentation=\"BIT\">3</DataTransportSize>\n" +
+ " <dataLength bitLength=\"16\"
dataType=\"uint16\">1</dataLength>\n" +
+ " <data>\n" +
+ " <value bitLength=\"8\"
dataType=\"int8\">1</value>\n" +
+ " </data>\n" +
+ " <padding></padding>\n" +
+ " </S7VarPayloadDataItem>\n" +
+ " </items>\n" +
+ " </S7PayloadReadVarResponse>\n" +
+ " </S7Payload>\n" +
+ " </S7Message>\n" +
+ " </COTPPacket>\n" +
+ "</TPKTPacket>";
+
+
+ TPKTPacket tpktPacket = new TPKTPacket(
+ new COTPPacketData(
+ new COTPParameter[]{new
COTPParameterTpduSize(COTPTpduSize.SIZE_4096)},
+ new S7MessageResponseData(
+ 11,
+ new S7ParameterReadVarResponse((short) 1),
+ new S7PayloadReadVarResponse(
+ new S7VarPayloadDataItem[]{
+ new S7VarPayloadDataItem(
+ DataTransportErrorCode.OK,
+ DataTransportSize.BIT,
+ new byte[]{0x1}
+ )
+ }
+ ),
+ (short) 0,
+ (short) 0
+ ),
+ false,
+ (short) 13
+ )
+ );
+ WriteBufferXmlBased writeBufferXmlBased = new WriteBufferXmlBased();
+ TPKTPacketIO.staticSerialize(writeBufferXmlBased, tpktPacket);
+ String gotXml = writeBufferXmlBased.getXmlString();
+ assertEquals(wantXml,gotXml);
+ }
+}
diff --git
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
index cc74f17..23cd4b4 100644
---
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
+++
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
@@ -23,6 +23,7 @@ import java.math.BigDecimal;
import java.math.BigInteger;
public interface WriteBuffer {
+ // TODO: check if this is really needed or if this is just an artifact
int getPos();
void pushContext(String logicalName);
diff --git
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
new file mode 100644
index 0000000..6d32130
--- /dev/null
+++
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
@@ -0,0 +1,240 @@
+/*
+ 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.spi.generation;
+
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayOutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Stack;
+
+public class WriteBufferXmlBased implements WriteBuffer {
+
+ Stack<Element> stack;
+
+ Document document;
+
+ public WriteBufferXmlBased() {
+ DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
+ try {
+ this.document =
documentBuilderFactory.newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ throw new PlcRuntimeException(e);
+ }
+ this.stack = new Stack<>();
+ }
+
+ @Override
+ public int getPos() {
+ return 0;
+ }
+
+ @Override
+ public void pushContext(String logicalName) {
+ stack.push(document.createElement(logicalName));
+ }
+
+ @Override
+ public void writeBit(String logicalName, boolean value) throws
ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "bit");
+ element.setAttribute("bitLength", "1");
+
element.appendChild(document.createTextNode(Boolean.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeUnsignedByte(String logicalName, int bitLength, byte
value) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "uint8");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Byte.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeUnsignedShort(String logicalName, int bitLength, short
value) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "uint16");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Short.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeUnsignedInt(String logicalName, int bitLength, int value)
throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "uint32");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Integer.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeUnsignedLong(String logicalName, int bitLength, long
value) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "uint64");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Long.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeUnsignedBigInteger(String logicalName, int bitLength,
BigInteger value) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "bigInt");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+ element.appendChild(document.createTextNode(value.toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeByte(String logicalName, int bitLength, byte value)
throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "int8");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Byte.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeShort(String logicalName, int bitLength, short value)
throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "int16");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Short.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeInt(String logicalName, int bitLength, int value) throws
ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "int32");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Integer.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeLong(String logicalName, int bitLength, long value)
throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "int64");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+
element.appendChild(document.createTextNode(Long.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeBigInteger(String logicalName, int bitLength, BigInteger
value) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "bigInt");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+ element.appendChild(document.createTextNode(value.toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeFloat(String logicalName, float value, int bitsExponent,
int bitsMantissa) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "float32");
+ element.setAttribute("bitLength", String.valueOf((value < 0 ? 1 : 0) +
bitsExponent + bitsMantissa));
+
element.appendChild(document.createTextNode(Float.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeDouble(String logicalName, double value, int
bitsExponent, int bitsMantissa) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "float64");
+ element.setAttribute("bitLength", String.valueOf((value < 0 ? 1 : 0) +
bitsExponent + bitsMantissa));
+
element.appendChild(document.createTextNode(Double.valueOf(value).toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeBigDecimal(String logicalName, int bitLength, BigDecimal
value) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "bigFloat");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+ element.appendChild(document.createTextNode(value.toString()));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void writeString(String logicalName, int bitLength, String
encoding, String value) throws ParseException {
+ Element element =
document.createElement(sanitizeLogicalName(logicalName));
+ element.setAttribute("dataType", "string");
+ element.setAttribute("bitLength", String.valueOf(bitLength));
+ element.appendChild(document.createTextNode(value));
+ stack.peek().appendChild(element);
+ }
+
+ @Override
+ public void popContext(String logicalName) {
+ Element currentContext = stack.pop();
+ if (!currentContext.getTagName().equals(logicalName)) {
+ throw new PlcRuntimeException("Unexpected pop context '" +
currentContext.getTagName() + '\'');
+ }
+ if (stack.isEmpty()) {
+ document.appendChild(currentContext);
+ return;
+ }
+ stack.peek().appendChild(currentContext);
+ }
+
+ public String getXmlString() {
+ try {
+ Transformer transformer =
TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
+ //transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
"roles.dtd");
+
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+ ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
+ transformer.transform(new DOMSource(document),
+ new StreamResult(byteArrayOutputStream));
+
+ return byteArrayOutputStream.toString();
+ } catch (TransformerException e) {
+ throw new PlcRuntimeException(e);
+ }
+ }
+
+
+ private String sanitizeLogicalName(String logicalName) {
+ if (logicalName.equals("")) {
+ return "value";
+ }
+ return logicalName;
+ }
+}