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 2021/12/23 15:17:10 UTC
[plc4x] branch feature/mqtt5_support created (now 3a46821)
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a change to branch feature/mqtt5_support
in repository https://gitbox.apache.org/repos/asf/plc4x.git.
at 3a46821 feature: started implementing an mspec for the mqtt5 protocol.
This branch includes the following new commits:
new c21998d fix: Made it possible to use enum types in arrays, made at least simple fields also support encoding feature: added support for variable length uint 32 encoding (varLenUint32)
new 3a46821 feature: started implementing an mspec for the mqtt5 protocol.
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[plc4x] 01/02: fix: Made it possible to use enum types in arrays, made at least simple fields also support encoding feature: added support for variable length uint 32 encoding (varLenUint32)
Posted by cd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/mqtt5_support
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit c21998dde654673aec113e6a6a002d8fbf0c5334
Author: cdutz <ch...@c-ware.de>
AuthorDate: Thu Dec 23 16:14:46 2021 +0100
fix: Made it possible to use enum types in arrays, made at least simple fields also support encoding
feature: added support for variable length uint 32 encoding (varLenUint32)
---
.../language/java/JavaLanguageTemplateHelper.java | 25 ++++++++++++++++++++++
.../templates/java/model-template.java.ftlh | 16 ++++++++++++--
.../plc4x/java/spi/codegen/FieldCommons.java | 17 +++++++++++++++
.../java/spi/codegen/fields/FieldWriterArray.java | 12 +++++++++++
.../spi/codegen/fields/FieldWriterFactory.java | 4 ++++
.../codegen/io/DataReaderSimpleUnsignedLong.java | 10 +++++++--
.../codegen/io/DataWriterSimpleUnsignedLong.java | 10 +++++++--
.../plc4x/java/spi/generation/ReadBuffer.java | 17 +++++++++++++++
.../plc4x/java/spi/generation/WriteBuffer.java | 15 +++++++++++++
9 files changed, 120 insertions(+), 6 deletions(-)
diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index a0a6a72..db1a478 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -1135,6 +1135,31 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse(""));
}
+ public String getSizeInBits(TypedField field, List<Argument> parserArguments) {
+ String encoding = null;
+ final Optional<Term> encodingOptional = field.getEncoding();
+ if (encodingOptional.isPresent()) {
+ encoding = toParseExpression(field, field.getType(), encodingOptional.get(), parserArguments);
+ }
+ if(field.getType().isSimpleTypeReference()) {
+ final SimpleTypeReference simpleTypeReference = field.getType().asSimpleTypeReference().orElseThrow();
+ if(encoding != null) {
+ if("\"varLenUint32\"".equals(encoding)) {
+ if((simpleTypeReference.getSizeInBits() != 32) && (simpleTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.UINT)) {
+ throw new RuntimeException("varLenUint32 currently only supported for 'unit 32' typed fields");
+ }
+ String fieldName = field.asNamedField().orElseThrow().getName();
+ return "(" + fieldName + " <= 0x7F) ? 8 : (" + fieldName + " <= 0xFF7F) ? 16 : (" + fieldName + " <= 0xFFFF7F) ? 24 : (" + fieldName + " <= 0xFFFFFF7FL) ? 32 : -1";
+ } else {
+ throw new RuntimeException("Unsupported encoding '" + encoding + "'");
+ }
+ } else {
+ return "" + simpleTypeReference.getSizeInBits();
+ }
+ }
+ throw new RuntimeException("getSizeInBits only supported for simple types.");
+ }
+
public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, List<Argument> parserArguments) {
int sizeInBits = 0;
StringBuilder sb = new StringBuilder();
diff --git a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
index 07dc000..c2f3364 100644
--- a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
@@ -54,6 +54,8 @@ import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
import org.apache.plc4x.java.api.value.*;
import org.apache.plc4x.java.spi.codegen.io.DataWriterComplexDefault;
import org.apache.plc4x.java.spi.codegen.io.DataWriterEnumDefault;
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.generation.ByteOrder;
import org.apache.plc4x.java.spi.generation.Message;
import org.apache.plc4x.java.spi.generation.MessageIO;
import org.apache.plc4x.java.spi.generation.SerializationException;
@@ -191,6 +193,8 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
writeByteArrayField("${namedField.name}", ${namedField.name}, writeByteArray(writeBuffer, 8));
<#elseif arrayField.type.isSimpleTypeReference()>
writeSimpleTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)});
+ <#elseif helper.isEnumTypeReference(arrayField.type)>
+ writeEnumTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")});
<#else>
writeComplexTypeArrayField("${namedField.name}", ${namedField.name}, writeBuffer);
</#if>
@@ -281,7 +285,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
<#assign namedField = field.asNamedField().orElseThrow()>
// Simple Field (${namedField.name})
- <#if helper.isEnumTypeReference(typedField.type)>writeSimpleEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")});<#else>writeSimpleField("${namedField.name}", ${simpleField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)});</#if>
+ <#if helper.isEnumTypeReference(typedField.type)>writeSimpleEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")});<#else>writeSimpleField("${namedField.name}", ${simpleField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)}${helper.getFieldOptions(typedField, parserArguments)});</#if>
<#break>
<#case "switch">
<#assign switchField = field.asSwitchField().orElseThrow()>
@@ -330,11 +334,19 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
<#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
for(${complexTypeReference.name} element : ${arrayField.name}) {
boolean last = ++i >= ${arrayField.name}.size();
+ <#if helper.isEnumField(field)>
+ lengthInBits += ${helper.getEnumBaseTypeReference(arrayField.type).sizeInBits};
+ <#else>
lengthInBits += element.getLengthInBits();
+ </#if>
}
<#else>
for(Message element : ${arrayField.name}) {
+ <#if helper.isEnumField(field)>
+ lengthInBits += ${helper.getEnumBaseTypeReference(arrayField.type).sizeInBits};
+ <#else>
lengthInBits += element.getLengthInBits();
+ </#if>
}
</#if>
}
@@ -450,7 +462,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
<#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
<#else>
- lengthInBits += ${simpleTypeReference.sizeInBits};
+ lengthInBits += ${helper.getSizeInBits(simpleField, parserArguments)};
</#if>
<#elseif helper.isEnumField(field)>
lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
index 5225f60..66d4ab3 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
@@ -75,6 +75,23 @@ public interface FieldCommons {
}
}
+ default Optional<String> extractEncoding(WithReaderArgs... readerArgs) {
+ return extractEncoding(Stream.of(readerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+ }
+
+ default Optional<String> extractEncoding(WithWriterArgs... writerArgs) {
+ return extractEncoding(Stream.of(writerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+ }
+
+ default Optional<String> extractEncoding(WithReaderWriterArgs... readerWriterArgs) {
+ for (WithReaderWriterArgs arg : readerWriterArgs) {
+ if (arg instanceof withOptionEncoding) {
+ return Optional.of(((withOptionEncoding) arg).encoding());
+ }
+ }
+ return Optional.empty();
+ }
+
@FunctionalInterface
interface RunParseWrapped<T> {
T run() throws ParseException;
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java
index d1fdce0..474bcd2 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java
@@ -56,4 +56,16 @@ public class FieldWriterArray<T> implements FieldCommons {
}, writeBuffer, extractByteOder(writerArgs).orElse(null));
}
+ public void writeEnumTypeArrayField(String logicalName, List<T> values, DataWriter<T> dataWriter, WithWriterArgs... writerArgs) throws SerializationException {
+ switchSerializeByteOrderIfNecessary(() -> {
+ if (values != null) {
+ dataWriter.pushContext(logicalName, WithReaderWriterArgs.WithRenderAsList(true));
+ for (T value : values) {
+ dataWriter.write("value", value, writerArgs);
+ }
+ dataWriter.popContext(logicalName, WithReaderWriterArgs.WithRenderAsList(true));
+ }
+ }, dataWriter, extractByteOder(writerArgs).orElse(null));
+ }
+
}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java
index 2fd10c2..8ca7a67 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java
@@ -39,6 +39,10 @@ public class FieldWriterFactory {
new FieldWriterArray<Message>().writeComplexTypeArrayField(logicalName, value, writeBuffer, writerArgs);
}
+ public static <T> void writeEnumTypeArrayField(String logicalName, List<T> value, DataWriter<T> dataWriter, WithWriterArgs... writerArgs) throws SerializationException {
+ new FieldWriterArray<T>().writeEnumTypeArrayField(logicalName, value, dataWriter, writerArgs);
+ }
+
public static <T> void writeByteArrayField(String logicalName, byte[] value, DataWriter<byte[]> dataWriter, WithWriterArgs... writerArgs) throws SerializationException {
new FieldWriterArray<T>().writeByteArrayField(logicalName, value, dataWriter, writerArgs);
}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
index d36ba98..5d42da7 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
@@ -18,11 +18,12 @@
*/
package org.apache.plc4x.java.spi.codegen.io;
+import org.apache.plc4x.java.spi.codegen.FieldCommons;
import org.apache.plc4x.java.spi.generation.ParseException;
import org.apache.plc4x.java.spi.generation.ReadBuffer;
import org.apache.plc4x.java.spi.generation.WithReaderArgs;
-public class DataReaderSimpleUnsignedLong extends DataReaderSimpleBase<Long> {
+public class DataReaderSimpleUnsignedLong extends DataReaderSimpleBase<Long> implements FieldCommons {
public DataReaderSimpleUnsignedLong(ReadBuffer readBuffer, int bitLength) {
super(readBuffer, bitLength);
@@ -30,7 +31,12 @@ public class DataReaderSimpleUnsignedLong extends DataReaderSimpleBase<Long> {
@Override
public Long read(String logicalName, WithReaderArgs... readerArgs) throws ParseException {
- return readBuffer.readUnsignedLong(logicalName, bitLength, readerArgs);
+ String encoding = extractEncoding(readerArgs).orElse(null);
+ if("varLenUint32".equals(encoding)) {
+ return readBuffer.readVariableLengthUnsignedInteger(logicalName, bitLength, readerArgs);
+ } else {
+ return readBuffer.readUnsignedLong(logicalName, bitLength, readerArgs);
+ }
}
}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java
index 7d3e1e6..cbc917c 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java
@@ -18,11 +18,12 @@
*/
package org.apache.plc4x.java.spi.codegen.io;
+import org.apache.plc4x.java.spi.codegen.FieldCommons;
import org.apache.plc4x.java.spi.generation.SerializationException;
import org.apache.plc4x.java.spi.generation.WithWriterArgs;
import org.apache.plc4x.java.spi.generation.WriteBuffer;
-public class DataWriterSimpleUnsignedLong extends DataWriterSimpleBase<Long> {
+public class DataWriterSimpleUnsignedLong extends DataWriterSimpleBase<Long> implements FieldCommons {
public DataWriterSimpleUnsignedLong(WriteBuffer writeBuffer, int bitLength) {
super(writeBuffer, bitLength);
@@ -30,7 +31,12 @@ public class DataWriterSimpleUnsignedLong extends DataWriterSimpleBase<Long> {
@Override
public void write(String logicalName, Long value, WithWriterArgs... writerArgs) throws SerializationException {
- writeBuffer.writeUnsignedLong(logicalName, bitLength, value, writerArgs);
+ String encoding = extractEncoding(writerArgs).orElse(null);
+ if("varLenUint32".equals(encoding)) {
+ writeBuffer.writeVariableLengthUnsignedInteger(logicalName, bitLength, value, writerArgs);
+ } else {
+ writeBuffer.writeUnsignedLong(logicalName, bitLength, value, writerArgs);
+ }
}
}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
index 5bc4246..2c635ff 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
@@ -80,6 +80,23 @@ public interface ReadBuffer extends ByteOrderAware {
return readUnsignedBigInteger("", bitLength);
}
+ default long readVariableLengthUnsignedInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+ long value = readUnsignedShort(8);
+ if(value >= 0x7F) {
+ value = (value << 8) | (readUnsignedShort(8));
+ if(value >= 0xFF7F) {
+ value = (value << 8) | (readUnsignedShort(8));
+ if(value >= 0xFFFF7F) {
+ value = (value << 8) | (readUnsignedShort(8));
+ if(value >= 0xFFFFFF7F) {
+ throw new ParseException("Value too big for variable length 32 bit unsigned integer");
+ }
+ }
+ }
+ }
+ return value;
+ }
+
byte readSignedByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
default byte readSignedByte(int bitLength) throws ParseException {
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 7cf9eca..e953311 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
@@ -78,6 +78,21 @@ public interface WriteBuffer extends ByteOrderAware {
writeUnsignedBigInteger("", bitLength, value);
}
+ default void writeVariableLengthUnsignedInteger(String logicalName, int maxBitLength, Long value, WithWriterArgs... writerArgs) throws SerializationException {
+ if((value <= 0x7F) && (maxBitLength >= 8)) {
+ writeUnsignedShort(8, value.byteValue());
+ } else if((value <= 0xFF7F) && (maxBitLength >= 16)) {
+ writeUnsignedInt(16, value.shortValue());
+ } else if((value <= 0xFFFF7F) && (maxBitLength >= 24)) {
+ writeUnsignedLong(24, value.intValue());
+ } else if((value <= 0xFFFFFF7FL) && (maxBitLength >= 32)) {
+ // TODO: This sucks, I know ...
+ writeUnsignedBigInteger(32, new BigInteger(value.toString()));
+ } else {
+ throw new SerializationException("Error serializing variable length unsigned int with value " + value);
+ }
+ }
+
void writeSignedByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws SerializationException;
default void writeSignedByte(int bitLength, byte value) throws SerializationException {
[plc4x] 02/02: feature: started implementing an mspec for the mqtt5 protocol.
Posted by cd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/mqtt5_support
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 3a4682109439fdff04c0640f9e2979d4a54d4121
Author: cdutz <ch...@c-ware.de>
AuthorDate: Thu Dec 23 16:15:29 2021 +0100
feature: started implementing an mspec for the mqtt5 protocol.
---
protocols/mqtt/pom.xml | 43 ++
.../apache/plc4x/protocol/mqtt/MqttProtocol.java | 45 +++
...e.plc4x.plugins.codegenerator.protocol.Protocol | 19 +
.../src/main/resources/protocols/mqtt/mqtt.mspec | 438 +++++++++++++++++++++
.../protocols/mqtt/ParserSerializerTestsuite.xml | 81 ++++
protocols/pom.xml | 1 +
sandbox/mqtt/mqtt-c/pom.xml | 319 +++++++++++++++
sandbox/mqtt/mqtt-cs/pom.xml | 138 +++++++
sandbox/mqtt/mqtt-go/pom.xml | 352 +++++++++++++++++
sandbox/mqtt/mqtt-java/pom.xml | 116 ++++++
.../mqtt/readwrite/MqttParserSerializerTest.java | 29 ++
sandbox/mqtt/pom.xml | 41 ++
sandbox/pom.xml | 1 +
13 files changed, 1623 insertions(+)
diff --git a/protocols/mqtt/pom.xml b/protocols/mqtt/pom.xml
new file mode 100644
index 0000000..fb41ef5
--- /dev/null
+++ b/protocols/mqtt/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+
+ <name>Protocols: MQTT</name>
+ <description>Base protocol specifications for the MQTT protocol</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-protocol-base-mspec</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/protocols/mqtt/src/main/java/org/apache/plc4x/protocol/mqtt/MqttProtocol.java b/protocols/mqtt/src/main/java/org/apache/plc4x/protocol/mqtt/MqttProtocol.java
new file mode 100644
index 0000000..8482f5d
--- /dev/null
+++ b/protocols/mqtt/src/main/java/org/apache/plc4x/protocol/mqtt/MqttProtocol.java
@@ -0,0 +1,45 @@
+/*
+ * 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.protocol.mqtt;
+
+import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
+import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
+import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;
+
+import java.io.InputStream;
+import java.util.Map;
+
+public class MqttProtocol implements Protocol {
+
+ @Override
+ public String getName() {
+ return "mqtt";
+ }
+
+ @Override
+ public Map<String, TypeDefinition> getTypeDefinitions() throws GenerationException {
+ InputStream schemaInputStream = MqttProtocol.class.getResourceAsStream("/protocols/mqtt/mqtt.mspec");
+ if(schemaInputStream == null) {
+ throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
+ }
+ return new MessageFormatParser().parse(schemaInputStream);
+ }
+
+}
diff --git a/protocols/mqtt/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol b/protocols/mqtt/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
new file mode 100644
index 0000000..287fe27
--- /dev/null
+++ b/protocols/mqtt/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+org.apache.plc4x.protocol.mqtt.MqttProtocol
diff --git a/protocols/mqtt/src/main/resources/protocols/mqtt/mqtt.mspec b/protocols/mqtt/src/main/resources/protocols/mqtt/mqtt.mspec
new file mode 100644
index 0000000..94879f8
--- /dev/null
+++ b/protocols/mqtt/src/main/resources/protocols/mqtt/mqtt.mspec
@@ -0,0 +1,438 @@
+/*
+ * 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.
+ */
+
+[discriminatedType MQTT_ControlPacket byteOrder='BIG_ENDIAN'
+ [discriminator MQTT_ControlPacketType packetType ]
+ [abstract uint 8 remainingLength ]
+ [typeSwitch packetType
+ ['CONNECT' MQTT_ControlPacket_CONNECT
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple MQTT_String protocolName ]
+ [simple uint 8 protocolVersion ]
+ // Connect flags start
+ [simple bit userNameFlagSet ]
+ [simple bit passwordFlagSet ]
+ [simple bit willRetainFlagSet ]
+ [simple uint 2 willQosLevel ]
+ [simple bit willFlagSet ]
+ // Actually a session start ...
+ [simple bit cleanStartFlagSet ]
+ [reserved bit 'false' ]
+ // Connect flags end
+ [simple uint 16 keepAlive ]
+
+ // Properties
+ [simple uint 32 propertyLength encoding='"varLenUint32"']
+ [array MQTT_Property properties length 'propertyLength' ]
+
+ // Payload
+ [simple MQTT_String clientId ]
+ // TODO: If willFlagSet is true, the will properties come here (3.1.3.2)
+ // TODO: If willFlagSet is true, the will topic comes here (3.1.3.3)
+ // TODO: If willFlagSet is true, the will payload comes here (3.1.3.4)
+ // If userNameFlagSet, here comes the username. (String)
+ [optional MQTT_String username 'userNameFlagSet' ]
+ // If passwordFlagSet, here comes the password. (String)
+ [optional MQTT_String password 'passwordFlagSet' ]
+ ]
+ ['CONNACK' MQTT_ControlPacket_CONNACK
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ // Acknowledge flags start
+ [reserved uint 7 '0x00' ]
+ [simple bit sessionPresentFlagSet ]
+ // Acknowledge flags end
+ [simple MQTT_ReasonCode reasonCode ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+ ]
+ ['PUBLISH' MQTT_ControlPacket_PUBLISH
+ // Fixed Header
+ [simple bit dup ]
+ [simple MQTT_QOS qos ]
+ [simple bit retain ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple MQTT_String topicName ]
+ [optional uint 16 packetIdentifier 'qos != MQTT_QOS.AT_MOST_ONCE']
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+
+ // Payload
+ [array byte payload count 'remainingLength - curPos' ]
+ ]
+ // Used if QOS = 1
+ ['PUBACK' MQTT_ControlPacket_PUBACK
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+ [optional MQTT_ReasonCode reasonCode 'remainingLength - curPos < 3' ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+ ]
+ // Used if QOS = 2
+ ['PUBREC' MQTT_ControlPacket_PUBREC
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+ [optional MQTT_ReasonCode reasonCode 'remainingLength - curPos < 3' ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+ ]
+ ['PUBREL' MQTT_ControlPacket_PUBREL
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+ [optional MQTT_ReasonCode reasonCode 'remainingLength - curPos < 3' ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+ ]
+ ['PUBCOMP' MQTT_ControlPacket_PUBCOMP
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+ [optional MQTT_ReasonCode reasonCode 'remainingLength - curPos < 3' ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+ ]
+ ['SUBSCRIBE' MQTT_ControlPacket_SUBSCRIBE
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+
+ // Payload
+ [array Filter filters count 'remainingLength - curPos' ]
+ ]
+ ['SUBACK' MQTT_ControlPacket_SUBACK
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+
+ // Payload
+ [array MQTT_ReasonCode results count 'remainingLength - curPos' ]
+ ]
+ ['UNSUBSCRIBE' MQTT_ControlPacket_UNSUBSCRIBE
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+
+ // Payload
+ [array MQTT_String filters count 'remainingLength - curPos' ]
+ ]
+ ['UNSUBACK' MQTT_ControlPacket_UNSUBACK
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple uint 16 packetIdentifier ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+
+ // Payload
+ [array MQTT_ReasonCode results count 'remainingLength - curPos' ]
+ ]
+ ['PINGREQ' MQTT_ControlPacket_PINGREQ
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ ]
+ ['PINGRESP' MQTT_ControlPacket_PINGRESP
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ ]
+ ['DISCONNECT' MQTT_ControlPacket_DISCONNECT
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple MQTT_ReasonCode reason ]
+ ]
+ ['AUTH' MQTT_ControlPacket_AUTH
+ // Fixed Header
+ [reserved uint 4 '0x0' ]
+ [simple uint 8 remainingLength ]
+ // Variable Header
+ [simple MQTT_ReasonCode reason ]
+
+ // Properties
+ [optional uint 32 propertyLength 'remainingLength - curPos < 4' encoding='"varLenUint32"']
+ [array MQTT_Property properties length '(propertyLength != null) ? propertyLength : 0']
+ ]
+ ]
+]
+
+[discriminatedType MQTT_Property
+ [simple MQTT_PropertyType propertyType]
+ [typeSwitch propertyType
+ ['PAYLOAD_FORMAT_INDICATOR' MQTT_Property_PAYLOAD_FORMAT_INDICATOR
+ [simple uint 8 value ]
+ ]
+ ['MESSAGE_EXPIRY_INTERVAL' MQTT_Property_MESSAGE_EXPIRY_INTERVAL
+ [simple uint 32 value ]
+ ]
+ ['CONTENT_TYPE' MQTT_Property_CONTENT_TYPE
+ [simple MQTT_String value ]
+ ]
+ ['RESPONSE_TOPIC' MQTT_Property_RESPONSE_TOPIC
+ [simple MQTT_String value ]
+ ]
+ ['CORRELATION_DATA' MQTT_Property_CORRELATION_DATA
+ // TODO: Find out what "Binary Data" means ...
+ ]
+ ['SUBSCRIPTION_IDENTIFIER' MQTT_Property_SUBSCRIPTION_IDENTIFIER
+ [simple uint 32 value encoding='"varLenUint32"']
+ ]
+ ['SESSION_EXPIRY_INTERVAL' MQTT_Property_EXPIRY_INTERVAL
+ [simple uint 32 value ]
+ ]
+ ['ASSIGNED_CLIENT_IDENTIFIER' MQTT_Property_ASSIGNED_CLIENT_IDENTIFIER
+ [simple MQTT_String value ]
+ ]
+ ['SERVER_KEEP_ALIVE' MQTT_Property_SERVER_KEEP_ALIVE
+ [simple uint 16 value ]
+ ]
+ ['AUTHENTICATION_METHOD' MQTT_Property_AUTHENTICATION_METHOD
+ [simple MQTT_String value ]
+ ]
+ ['AUTHENTICATION_DATA' MQTT_Property_AUTHENTICATION_DATA
+ // TODO: Find out what "Binary Data" means ...
+ ]
+ ['REQUEST_PROBLEM_INFORMATION' MQTT_Property_REQUEST_PROBLEM_INFORMATION
+ // TODO: Probably an enum
+ [simple uint 8 value ]
+ ]
+ ['WILL_DELAY_INTERVAL' MQTT_Property_WILL_DELAY_INTERVAL
+ [simple uint 32 value ]
+ ]
+ ['REQUEST_RESPONSE_INFORMATION' MQTT_Property_REQUEST_RESPONSE_INFORMATION
+ // TODO: Probably an enum
+ [simple uint 8 value ]
+ ]
+ ['RESPONSE_INFORMATION' MQTT_Property_RESPONSE_INFORMATION
+ [simple MQTT_String value ]
+ ]
+ ['SERVER_REFERENCE' MQTT_Property_SERVER_REFERENCE
+ [simple MQTT_String value ]
+ ]
+ ['REASON_STRING' MQTT_Property_REASON_STRING
+ [simple MQTT_String value ]
+ ]
+ ['RECEIVE_MAXIMUM' MQTT_Property_RECEIVE_MAXIMUM
+ [simple uint 16 value ]
+ ]
+ ['TOPIC_ALIAS_MAXIMUM' MQTT_Property_TOPIC_ALIAS_MAXIMUM
+ [simple uint 16 value ]
+ ]
+ ['TOPIC_ALIAS' MQTT_Property_TOPIC_ALIAS
+ [simple uint 16 value ]
+ ]
+ ['MAXIMUM_QOS' MQTT_Property_MAXIMUM_QOS
+ [simple uint 8 value ]
+ ]
+ ['RETAIN_AVAILABLE' MQTT_Property_RETAIN_AVAILABLE
+ [simple uint 8 value ]
+ ]
+ ['USER_PROPERTY' MQTT_Property_USER_PROPERTY
+ [simple MQTT_String name ]
+ [simple MQTT_String value ]
+ ]
+ ['MAXIMUM_PACKET_SIZE' MQTT_Property_MAXIMUM_PACKET_SIZE
+ [simple uint 32 value ]
+ ]
+ ['WILDCARD_SUBSCRIPTION_AVAILABLE' MQTT_Property_WILDCARD_SUBSCRIPTION_AVAILABLE
+ [simple uint 8 value ]
+ ]
+ ['SUBSCRIPTION_IDENTIFIER_AVAILABLE' MQTT_Property_SUBSCRIPTION_IDENTIFIER_AVAILABLE
+ [simple uint 8 value ]
+ ]
+ ['SHARED_SUBSCRIPTION_AVAILABLE' MQTT_Property_SHARED_SUBSCRIPTION_AVAILABLE
+ [simple uint 8 value ]
+ ]
+ ]
+]
+
+[type Filter
+ [simple MQTT_String filter ]
+ // Subscription Options Start
+ [reserved uint 2 '0x0' ]
+ // Don't forward to clients with a client id equal to the sending one
+ [simple MQTT_RetainHandling retainHandling]
+ [simple bit retain ]
+ [simple bit noLocal ]
+ [simple MQTT_QOS maxQos ]
+ // Subscription Options End
+]
+
+[type MQTT_String
+ [implicit uint 16 stringLength 'STR_LEN(value)']
+ [simple vstring 'stringLength * 8' value ]
+]
+
+[enum uint 4 MQTT_ControlPacketType
+ ['0x0' RESERVED ]
+ ['0x1' CONNECT ]
+ ['0x2' CONNACK ]
+ ['0x3' PUBLISH ]
+ ['0x4' PUBACK ]
+ ['0x5' PUBREC ]
+ ['0x6' PUBREL ]
+ ['0x7' PUBCOMP ]
+ ['0x8' SUBSCRIBE ]
+ ['0x9' SUBACK ]
+ ['0xA' UNSUBSCRIBE]
+ ['0xB' UNSUBACK ]
+ ['0xC' PINGREQ ]
+ ['0xD' PINGRESP ]
+ ['0xE' DISCONNECT ]
+ ['0xF' AUTH ]
+]
+
+[enum uint 8 MQTT_PropertyType
+ ['0x01' PAYLOAD_FORMAT_INDICATOR ]
+ ['0x02' MESSAGE_EXPIRY_INTERVAL ]
+ ['0x03' CONTENT_TYPE ]
+ ['0x08' RESPONSE_TOPIC ]
+ ['0x09' CORRELATION_DATA ]
+ ['0x0B' SUBSCRIPTION_IDENTIFIER ]
+ ['0x11' SESSION_EXPIRY_INTERVAL ]
+ ['0x12' ASSIGNED_CLIENT_IDENTIFIER ]
+ ['0x13' SERVER_KEEP_ALIVE ]
+ ['0x15' AUTHENTICATION_METHOD ]
+ ['0x16' AUTHENTICATION_DATA ]
+ ['0x17' REQUEST_PROBLEM_INFORMATION ]
+ ['0x18' WILL_DELAY_INTERVAL ]
+ ['0x19' REQUEST_RESPONSE_INFORMATION ]
+ ['0x1A' RESPONSE_INFORMATION ]
+ ['0x1C' SERVER_REFERENCE ]
+ ['0x1F' REASON_STRING ]
+ ['0x21' RECEIVE_MAXIMUM ]
+ ['0x22' TOPIC_ALIAS_MAXIMUM ]
+ ['0x23' TOPIC_ALIAS ]
+ ['0x24' MAXIMUM_QOS ]
+ ['0x25' RETAIN_AVAILABLE ]
+ ['0x26' USER_PROPERTY ]
+ ['0x27' MAXIMUM_PACKET_SIZE ]
+ ['0x28' WILDCARD_SUBSCRIPTION_AVAILABLE ]
+ ['0x29' SUBSCRIPTION_IDENTIFIER_AVAILABLE]
+ ['0x2A' SHARED_SUBSCRIPTION_AVAILABLE ]
+]
+
+[enum uint 8 MQTT_ReasonCode (bit connackResponse, bit pubackPubrecResponse, bit pubrelPubcompResponse, bit subackResponse, bit unsubackResponse, bit disconnectReason, bit authReason)
+ ['0X00' SUCCESS ['true' , 'true' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0X01' GRANTED_QOS_1 ['false' , 'false' , 'false' , 'true' , 'false' , 'false' , 'false' ]]
+ ['0X02' GRANTED_QOS_2 ['false' , 'false' , 'false' , 'true' , 'false' , 'false' , 'false' ]]
+ ['0X04' DISCONNECT_WITH_WILL_MESSAGE ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0x10' NO_MATCHING_SUBSCRIBERS ['false' , 'true' , 'false' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0x11' NO_SUBSCRIPTION_EXISTED ['false' , 'false' , 'false' , 'false' , 'true' , 'false' , 'false' ]]
+ ['0X18' CONTINUE_AUTHENTICATION ['false' , 'false' , 'false' , 'false' , 'false' , 'false' , 'true' ]]
+ ['0X19' RE_AUTHENTICATE ['false' , 'false' , 'false' , 'false' , 'false' , 'false' , 'true' ]]
+ ['0X80' UNSPECIFIED_ERROR ['true' , 'true' , 'false' , 'true' , 'true' , 'true' , 'false' ]]
+ ['0X81' MALFORMED_PACKET ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X82' PROTOCOL_ERROR ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X83' IMPLEMENTATION_SPECIFIC_ERROR ['true' , 'true' , 'false' , 'true' , 'true' , 'true' , 'false' ]]
+ ['0X84' UNSUPPORTED_PROTOCOL_VERSION ['true' , 'false' , 'false' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0X85' CLIENT_IDENTIFIER_NOT_VALID ['true' , 'false' , 'false' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0X86' BAD_USER_NAME_OR_PASSWORD ['true' , 'false' , 'false' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0X87' NOT_AUTHORIZED ['true' , 'true' , 'false' , 'true' , 'true' , 'true' , 'false' ]]
+ ['0X88' SERVER_UNAVAILABLE ['true' , 'false' , 'false' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0X89' SERVER_BUSY ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X8A' BANNED ['true' , 'false' , 'false' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0X8B' SERVER_SHUTTING_DOWN ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X8C' BAD_AUTHENTICATION_METHOD ['true' , 'false' , 'false' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0X8D' KEEP_ALIVE_TIMEOUT ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X8E' SESSION_TAKEN_OVER ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X8F' TOPIC_FILTER_INVALID ['false' , 'false' , 'false' , 'true' , 'true' , 'true' , 'false' ]]
+ ['0X90' TOPIC_NAME_INVALID ['true' , 'true' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X91' PACKET_IDENTIFIER_IN_USE ['false' , 'true' , 'false' , 'true' , 'true' , 'false' , 'false' ]]
+ ['0X92' PACKET_IDENTIFIER_NOT_FOUND ['false' , 'false' , 'true' , 'false' , 'false' , 'false' , 'false' ]]
+ ['0X93' RECEIVE_MAXIMUM_EXCEEDED ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X94' TOPIC_ALIAS_INVALID ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X95' PACKET_TOO_LARGE ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X96' MESSAGE_RATE_TO_HIGH ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X97' QUOTA_EXCEEDED ['true' , 'true' , 'false' , 'true' , 'false' , 'true' , 'false' ]]
+ ['0X98' ADMINISTRATIVE_ACTION ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X99' PAYLOAD_FORMAT_INVALID ['true' , 'true' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X9A' RETAIN_NOT_SUPPORTED ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X9B' QOS_NOT_SUPPORTED ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X9C' USE_ANOTHER_SERVER ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X9D' SERVER_MOVED ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0X9E' SHARED_SUBSCRIPTIONS_NOT_SUPPORTED ['false' , 'false' , 'false' , 'true' , 'false' , 'true' , 'false' ]]
+ ['0X9F' CONNECTION_RATE_EXCEEDED ['true' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0XA0' MAXIMUM_CONNECT_TIME ['false' , 'false' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0XA1' SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED ['false' , 'false' , 'false' , 'true' , 'false' , 'true' , 'false' ]]
+ ['0XA2' WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED ['false' , 'false' , 'false' , 'true' , 'false' , 'true' , 'false' ]]
+]
+
+[enum uint 2 MQTT_QOS
+ ['0x0' AT_MOST_ONCE ]
+ ['0x1' AT_LEAST_ONCE]
+ ['0x2' EXACTLY_ONCE ]
+]
+
+[enum uint 2 MQTT_RetainHandling
+ ['0x0' SEND_RETAINED_MESSAGES_AT_THE_TIME_OF_THE_SUBSCRIBE ]
+ ['0x1' SEND_RETAINED_MESSAGES_AT_SUBSCRIBE_ONLY_IF_THE_SUBSCRIPTION_DOES_NOT_CURRENTLY_EXIST]
+ ['0x2' DO_NOT_SEND_RETAINED_MESSAGES_AT_THE_TIME_OF_SUBSCRIBE ]
+]
diff --git a/protocols/mqtt/src/test/resources/protocols/mqtt/ParserSerializerTestsuite.xml b/protocols/mqtt/src/test/resources/protocols/mqtt/ParserSerializerTestsuite.xml
new file mode 100644
index 0000000..1719da4
--- /dev/null
+++ b/protocols/mqtt/src/test/resources/protocols/mqtt/ParserSerializerTestsuite.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<test:testsuite xmlns:test="https://plc4x.apache.org/schemas/parser-serializer-testsuite.xsd"
+ byteOrder="BIG_ENDIAN">
+
+ <name>MQTT5</name>
+
+ <protocolName>mqtt</protocolName>
+ <outputFlavor>read-write</outputFlavor>
+
+ <testcase>
+ <name>MQTT Connection Request</name>
+ <raw>101d00044d51545405c200050000066c776d71747400037472790003747279</raw>
+ <root-type>MQTT_ControlPacket</root-type>
+ <xml>
+ <MQTT_ControlPacket>
+ <packetType>
+ <MQTT_ControlPacketType dataType="uint" bitLength="4" stringRepresentation="CONNECT">1</MQTT_ControlPacketType>
+ </packetType>
+ <MQTT_ControlPacket_CONNECT>
+ <reserved dataType="uint" bitLength="4">0</reserved>
+ <remainingLength dataType="uint" bitLength="8">29</remainingLength>
+ <protocolName>
+ <MQTT_String>
+ <stringLength dataType="uint" bitLength="16">4</stringLength>
+ <value dataType="string" bitLength="32" encoding="UTF-8">MQTT</value>
+ </MQTT_String>
+ </protocolName>
+ <protocolVersion dataType="uint" bitLength="8">5</protocolVersion>
+ <userNameFlagSet dataType="bit" bitLength="1">true</userNameFlagSet>
+ <passwordFlagSet dataType="bit" bitLength="1">true</passwordFlagSet>
+ <willRetainFlagSet dataType="bit" bitLength="1">false</willRetainFlagSet>
+ <willQosLevel dataType="uint" bitLength="2">0</willQosLevel>
+ <willFlagSet dataType="bit" bitLength="1">false</willFlagSet>
+ <cleanStartFlagSet dataType="bit" bitLength="1">true</cleanStartFlagSet>
+ <reserved dataType="bit" bitLength="1">false</reserved>
+ <keepAlive dataType="uint" bitLength="16">5</keepAlive>
+ <value dataType="uint" bitLength="8">0</value>
+ <properties isList="true">
+ </properties>
+ <clientId>
+ <MQTT_String>
+ <stringLength dataType="uint" bitLength="16">6</stringLength>
+ <value dataType="string" bitLength="48" encoding="UTF-8">lwmqtt</value>
+ </MQTT_String>
+ </clientId>
+ <username>
+ <MQTT_String>
+ <stringLength dataType="uint" bitLength="16">3</stringLength>
+ <value dataType="string" bitLength="24" encoding="UTF-8">try</value>
+ </MQTT_String>
+ </username>
+ <password>
+ <MQTT_String>
+ <stringLength dataType="uint" bitLength="16">3</stringLength>
+ <value dataType="string" bitLength="24" encoding="UTF-8">try</value>
+ </MQTT_String>
+ </password>
+ </MQTT_ControlPacket_CONNECT>
+ </MQTT_ControlPacket>
+ </xml>
+ </testcase>
+
+</test:testsuite>
\ No newline at end of file
diff --git a/protocols/pom.xml b/protocols/pom.xml
index 268f669..ea21e96 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -44,6 +44,7 @@
<module>genericcan</module>
<module>knxnetip</module>
<module>modbus</module>
+ <module>mqtt</module>
<module>opcua</module>
<module>plc4x</module>
<module>profinet</module>
diff --git a/sandbox/mqtt/mqtt-c/pom.xml b/sandbox/mqtt/mqtt-c/pom.xml
new file mode 100644
index 0000000..4e8fc83
--- /dev/null
+++ b/sandbox/mqtt/mqtt-c/pom.xml
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x.sandbox</groupId>
+ <artifactId>test-plc4x-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>test-plc4x-mqtt-c</artifactId>
+ <packaging>pom</packaging>
+ <name>Sandbox: Test MQTT Driver: C</name>
+
+ <properties>
+ <unity.version>2.5.2</unity.version>
+ <option.with-proxies>OFF</option.with-proxies>
+ </properties>
+
+ <!--
+ Notes:
+ - It turns out that the default version of CMake the cmake-maven-plugin uses is too
+ old to detect the recent boost version. So we need to manually download a newer version
+ and tell the plugin to use that instead.
+ - As downloading and building boost takes quite some time, we only do this, if no
+ target/lib/boost is found.
+ -->
+
+ <profiles>
+ <!-- Profile for linux -->
+ <profile>
+ <id>os-unix</id>
+ <activation>
+ <os>
+ <family>unix</family>
+ </os>
+ </activation>
+ <!-- Make the cmake executable executable -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>make-cmake-executable</id>
+ <phase>process-sources</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <basedir>${cmake.root}</basedir>
+ <executable>chmod</executable>
+ <arguments>
+ <argument>+x</argument>
+ <argument>cmake</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <!-- Profile for mac -->
+ <profile>
+ <id>os-mac</id>
+ <activation>
+ <os>
+ <family>mac</family>
+ </os>
+ </activation>
+ <!-- Make the cmake executable executable -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>make-cmake-executable</id>
+ <phase>process-sources</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <basedir>${cmake.root}</basedir>
+ <executable>chmod</executable>
+ <arguments>
+ <argument>+x</argument>
+ <argument>cmake</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.googlecode.maven-download-plugin</groupId>
+ <artifactId>download-maven-plugin</artifactId>
+ <executions>
+ <!-- First download the cmake binaries -->
+ <execution>
+ <id>get-cmake</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>wget</goal>
+ </goals>
+ <configuration>
+ <url>${cmake.url}</url>
+ <unpack>true</unpack>
+ <outputDirectory>${project.build.directory}</outputDirectory>
+ </configuration>
+ </execution>
+ <!--
+ Get additional stuff we need for the build.
+ -->
+ <execution>
+ <id>get-unity</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>wget</goal>
+ </goals>
+ <configuration>
+ <url>https://github.com/ThrowTheSwitch/Unity/archive/v${unity.version}.zip</url>
+ <unpack>true</unpack>
+ <outputDirectory>${project.build.directory}/dependency</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!--
+ Generate the driver code.
+ -->
+ <plugin>
+ <groupId>org.apache.plc4x.plugins</groupId>
+ <artifactId>plc4x-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-driver-mqtt</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate-driver</goal>
+ </goals>
+ <configuration>
+ <protocolName>mqtt</protocolName>
+ <languageName>c</languageName>
+ <outputFlavor>read-write</outputFlavor>
+ <outputDir>${project.basedir}/generated-sources</outputDir>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!--
+ Do the actual build.
+ -->
+ <plugin>
+ <groupId>com.googlecode.cmake-maven-project</groupId>
+ <artifactId>cmake-maven-plugin</artifactId>
+ <executions>
+ <!-- TODO: Commented out for now as when running in jenkins for code analysis, the second run would overwrite the results of the first -->
+ <!-- Generate the configuration for the main compilation -->
+ <!--execution>
+ <id>cmake-generate-compile</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ </execution>
+ <!- Compile the main code ->
+ <execution>
+ <id>cmake-execute-compile</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ </execution-->
+ <!-- Generate the configuration for the test compilation -->
+ <!--execution>
+ <id>cmake-generate-test-compile</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <options>
+ <option>-DUNITY_VERSION:STRING=${unity.version}</option>
+ <option>-DBUILD_PHASE=test-compile</option>
+ </options>
+ </configuration>
+ </execution-->
+ <!-- Compile the test code -->
+ <!--execution>
+ <id>cmake-execute-test-compile</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ </execution-->
+ </executions>
+ <configuration>
+ <!--
+ We need to use a newer version of cmake, so disable downloading
+ and tell the plugin where to find that version.
+ -->
+ <downloadBinaries>false</downloadBinaries>
+ <cmakeDir>${cmake.root}</cmakeDir>
+ <!--
+ Actually the path to the CMakeList.txt file which then again
+ tells to tool where to find the sources.
+ -->
+ <sourcePath>${project.basedir}</sourcePath>
+ <!--
+ Path to where the build configuration is generated
+ (This directory is then used in the compile step to actually perform the build)
+ -->
+ <targetPath>${project.build.directory}/build</targetPath>
+ <!--
+ Name of the generator the compile step will be executing.
+ -->
+ <generator>${cmake.generator}</generator>
+ <!-- The directory where the "generate" step generated the build configuration -->
+ <projectDirectory>${project.build.directory}/build</projectDirectory>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>run-tests</id>
+ <phase>test</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <basedir>${project.build.directory}/build</basedir>
+ <executable>${cmake.root}/ctest</executable>
+ <arguments>
+ <argument>--extra-verbose</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- For this module deploying maven artifacts doesn't make any sense -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ <!--
+ Developers working in plc4c will probably use an IDE like CLion to edit just this
+ Part of the project. These IDEs generate some work-directories we need to exclude.
+ -->
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes combine.children="append">
+ <exclude>cmake-*/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <!-- This dependency is just to ensure thrift is built first -->
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-language-c</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/sandbox/mqtt/mqtt-cs/pom.xml b/sandbox/mqtt/mqtt-cs/pom.xml
new file mode 100644
index 0000000..b5cdb3d
--- /dev/null
+++ b/sandbox/mqtt/mqtt-cs/pom.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x.sandbox</groupId>
+ <artifactId>test-plc4x-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>test-plc4x-mqtt-cs</artifactId>
+ <packaging>pom</packaging>
+ <name>Sandbox: Test MQTT Driver: C#</name>
+
+ <!-- Disabled for now as C# support is currently not installed in Apache SonarQube -->
+ <!--properties>
+ <sonar.language>c#</sonar.language>
+ </properties-->
+
+ <build>
+ <plugins>
+ <!-- Copy the test-resources in here -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-protocol-test-suites</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+ <classifier>tests</classifier>
+ <type>test-jar</type>
+ <outputDirectory>${project.basedir}/drivers/mqtt/resources</outputDirectory>
+ <includes>**/*.xml</includes>
+ <excludes>META-INF/**,org/**</excludes>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!--
+ Generate the driver code.
+ -->
+ <plugin>
+ <groupId>org.apache.plc4x.plugins</groupId>
+ <artifactId>plc4x-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-driver-mqtt</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate-driver</goal>
+ </goals>
+ <configuration>
+ <protocolName>mqtt</protocolName>
+ <languageName>C#</languageName>
+ <outputFlavor>read-write</outputFlavor>
+ <outputDir>${project.basedir}/drivers/mqtt/src</outputDir>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Build the project -->
+ <!--plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>dotnet-build</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>dotnet</executable>
+ <workingDirectory>${project.basedir}</workingDirectory>
+ <arguments>
+ <argument>build</argument>
+ <argument>plc4net.sln</argument>
+ <argument>- -configuration=Debug</argument>
+ <argument>- -output=${project.build.directory}/build</argument>
+ <argument>-p:Version=${project.version}</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin-->
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-language-cs</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/sandbox/mqtt/mqtt-go/pom.xml b/sandbox/mqtt/mqtt-go/pom.xml
new file mode 100644
index 0000000..5f7caf1
--- /dev/null
+++ b/sandbox/mqtt/mqtt-go/pom.xml
@@ -0,0 +1,352 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x.sandbox</groupId>
+ <artifactId>test-plc4x-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>test-plc4x-mqtt-go</artifactId>
+ <!--packaging>mvn-golang</packaging-->
+ <packaging>pom</packaging>
+ <name>Sandbox: Test MQTT Driver: Go</name>
+
+ <properties>
+ <!-- Tell Sonar where to find the sources -->
+ <sonar.sources>cmd,examples,internal,pkg</sonar.sources>
+ </properties>
+
+ <build>
+ <sourceDirectory>cmd</sourceDirectory>
+ <plugins>
+ <!--
+ Copy the test-resources in here
+ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-protocol-test-suites</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+ <classifier>tests</classifier>
+ <type>test-jar</type>
+ <outputDirectory>${project.basedir}/assets/testing</outputDirectory>
+ <includes>**/*.xml</includes>
+ <excludes>META-INF/**</excludes>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!--
+ Generate the driver code.
+ -->
+ <plugin>
+ <groupId>org.apache.plc4x.plugins</groupId>
+ <artifactId>plc4x-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-driver-mqtt</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate-driver</goal>
+ </goals>
+ <configuration>
+ <protocolName>mqtt</protocolName>
+ <languageName>go</languageName>
+ <outputFlavor>read-write</outputFlavor>
+ <outputDir>${project.basedir}/internal</outputDir>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!--plugin>
+ <groupId>com.igormaznitsa</groupId>
+ <artifactId>mvn-golang-wrapper</artifactId>
+ <version>2.3.9</version>
+ <extensions>true</extensions>
+ <executions>
+
+ <!- - Downloads the dependencies of the project - ->
+ <execution>
+ <id>default-get</id>
+ <phase>initialize</phase>
+ <goals>
+ <goal>get</goal>
+ </goals>
+ </execution>
+
+ <!- - Make sure the "stringer" extension as well als the "licenser" is downloaded - ->
+ <execution>
+ <id>get-tools</id>
+ <phase>initialize</phase>
+ <goals>
+ <goal>get</goal>
+ </goals>
+ <configuration>
+ <packages>
+ <package>golang.org/x/tools/cmd/stringer</package>
+ <package>github.com/elastic/go-licenser</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <!- - Run the go code-generation - ->
+ <execution>
+ <id>default-generate</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <packages>
+ <!- - We want to format every package here so we don't get dirty commits - ->
+ <package>./...</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <!- - Add the apache license header to stuff generated by the stringer - ->
+ <!- -
+ NOTE: Don't try merging the following 4 executions ...
+ It doesn't work by merging the "packages" sections
+ - ->
+ <execution>
+ <id>add-license</id>
+ <phase>process-sources</phase>
+ <goals>
+ <goal>custom</goal>
+ </goals>
+ <configuration>
+ <exec>go-licenser</exec>
+ <customCommand>-licensor</customCommand>
+ <buildFlags>
+ <flag>Apache Software Foundation (ASF)</flag>
+ </buildFlags>
+ <packages>
+ <package>internal/plc4go/mqtt/fieldtype_string.go</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <!- - Processes code that uses old APIs and rewrites them use newer ones - ->
+ <execution>
+ <id>default-fix</id>
+ <phase>process-sources</phase>
+ <goals>
+ <goal>fix</goal>
+ </goals>
+ </execution>
+
+ <!- - Format the codebase correctly (this mainly has an effect on generated code) - ->
+ <execution>
+ <id>default-fmt</id>
+ <phase>process-sources</phase>
+ <goals>
+ <goal>fmt</goal>
+ </goals>
+ <configuration>
+ <packages>
+ <!- - We want to format every package here so we don't get dirty commits - ->
+ <package>./...</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <!- - Get all dependencies for test cases - ->
+ <execution>
+ <id>get-test-dependencies</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>get</goal>
+ </goals>
+ <configuration>
+ <buildFlags>
+ <flag>-t</flag>
+ </buildFlags>
+ <packages>
+ <package>./...</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <!- - Make sure the xunit generator as well as gotestsum is installed - ->
+ <execution>
+ <id>test-get</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>get</goal>
+ </goals>
+ <configuration>
+ <packages>
+ <package>github.com/tebeka/go2xunit</package>
+ <package>gotest.tools/gotestsum</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <!- - Check all tests with producing report file in Golang format - ->
+ <execution>
+ <id>default-test</id>
+ <phase>test</phase>
+ <!- - TODO: Which goal?!? - ->
+ <configuration>
+ <buildFlags>
+ <flag>-v</flag>
+ </buildFlags>
+ <outLogFile>test-out-verbose.log</outLogFile>
+ <ignoreErrorExitCode>true</ignoreErrorExitCode>
+ <packages>
+ <package>./...</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>readable-test</id>
+ <!- - TODO: Possibly move to test or prepare-package - ->
+ <phase>test</phase>
+ <goals>
+ <goal>custom</goal>
+ </goals>
+ <configuration>
+ <exec>gotestsum</exec>
+ <customCommand>-f</customCommand>
+ <buildFlags>
+ <flag>short</flag>
+ </buildFlags>
+ <packages>
+ <package>./...</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <!- - Convert generated test report into xunit format and save as file - ->
+ <execution>
+ <id>makeXUnitReport</id>
+ <phase>test</phase>
+ <goals>
+ <goal>custom</goal>
+ </goals>
+ <configuration>
+ <skip>${skipTests}</skip>
+ <exec>go2xunit</exec>
+ <customCommand>-fail</customCommand>
+ <buildFlags>
+ <flag>-input</flag>
+ <flag>${project.build.directory}${file.separator}reports${file.separator}test-out-verbose.log</flag>
+ <flag>-output</flag>
+ </buildFlags>
+ <echo>
+ <info>XUnit report saved as ${xunit.report}</info>
+ </echo>
+ <packages>
+ <package>target${file.separator}surefire-reports${file.separator}xuint.xml</package>
+ </packages>
+ </configuration>
+ </execution>
+
+ <execution>
+ <id>run-go-vet</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>vet</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <packages>
+ <package>github.com/apache/plc4x/plc4go/cmd/main</package>
+ </packages>
+ <sources>${project.basedir}</sources>
+ <verbose>true</verbose>
+ </configuration>
+ </plugin-->
+
+ <!--
+ Create surefire folder for report
+ -->
+ <!--plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>3.0.0</version>
+ <executions>
+ <execution>
+ <id>generate-sources</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <target>
+ <mkdir dir="target${file.separator}surefire-reports" />
+ </target>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin-->
+
+ <!-- For this module deploying maven artifacts doesn't make any sense -->
+ <!--plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin-->
+ </plugins>
+ </build>
+
+ <!-- This dependency is just to ensure thrift is built first -->
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-language-go</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/sandbox/mqtt/mqtt-java/pom.xml b/sandbox/mqtt/mqtt-java/pom.xml
new file mode 100644
index 0000000..ddf884e
--- /dev/null
+++ b/sandbox/mqtt/mqtt-java/pom.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x.sandbox</groupId>
+ <artifactId>test-plc4x-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>test-plc4x-mqtt-java</artifactId>
+ <name>Sandbox: Test MQTT Driver: Java</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.plc4x.plugins</groupId>
+ <artifactId>plc4x-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-driver</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate-driver</goal>
+ </goals>
+ <configuration>
+ <protocolName>mqtt</protocolName>
+ <languageName>java</languageName>
+ <outputFlavor>read-write</outputFlavor>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-api</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-spi</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-transport-tcp</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-transport-raw-socket</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-utils-test-utils</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-code-generation-language-java</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-mqtt</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ <classifier>tests</classifier>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/sandbox/mqtt/mqtt-java/src/test/java/org/apache/plc4x/java/mqtt/readwrite/MqttParserSerializerTest.java b/sandbox/mqtt/mqtt-java/src/test/java/org/apache/plc4x/java/mqtt/readwrite/MqttParserSerializerTest.java
new file mode 100644
index 0000000..0d72840
--- /dev/null
+++ b/sandbox/mqtt/mqtt-java/src/test/java/org/apache/plc4x/java/mqtt/readwrite/MqttParserSerializerTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.mqtt.readwrite;
+
+import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
+
+public class MqttParserSerializerTest extends ParserSerializerTestsuiteRunner {
+
+ public MqttParserSerializerTest() {
+ super("/protocols/mqtt/ParserSerializerTestsuite.xml");
+ }
+
+}
diff --git a/sandbox/mqtt/pom.xml b/sandbox/mqtt/pom.xml
new file mode 100644
index 0000000..7cc4053
--- /dev/null
+++ b/sandbox/mqtt/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x.sandbox</groupId>
+ <artifactId>plc4x-sandbox</artifactId>
+ <version>0.10.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>test-plc4x-mqtt</artifactId>
+ <packaging>pom</packaging>
+
+ <name>Sandbox: Test MQTT Driver</name>
+
+ <modules>
+ <module>mqtt-c</module>
+ <module>mqtt-cs</module>
+ <module>mqtt-go</module>
+ <module>mqtt-java</module>
+ </modules>
+
+</project>
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 80ffbca..22abe69 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -37,6 +37,7 @@
<modules>
<module>code-gen</module>
<module>discovery</module>
+ <module>mqtt</module>
<module>plc-simulator</module>
<module>test-java-bacnetip-driver</module>