From 3e8f9e3242ec2b5fd34b859c2b7a07074df47750 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 11 Mar 2024 15:27:25 +0200 Subject: [PATCH 1/3] added ability to send string without quotes --- .../rule/engine/mqtt/TbMqttNode.java | 42 +++++++++- .../engine/mqtt/TbMqttNodeConfiguration.java | 2 + .../rule/engine/mqtt/TbMqttNodeTest.java | 79 +++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 6e80a1577b..7d8935f25e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -15,11 +15,14 @@ */ package org.thingsboard.rule.engine.mqtt; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import io.netty.buffer.Unpooled; import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.handler.ssl.SslContext; import io.netty.util.concurrent.Promise; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.mqtt.MqttClient; import org.thingsboard.mqtt.MqttClientConfig; import org.thingsboard.mqtt.MqttConnectResult; @@ -35,6 +38,7 @@ import org.thingsboard.rule.engine.external.TbAbstractExternalNode; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.plugin.ComponentClusteringMode; import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.data.util.TbPair; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -81,7 +85,8 @@ public class TbMqttNode extends TbAbstractExternalNode { public void onMsg(TbContext ctx, TbMsg msg) { String topic = TbNodeUtils.processPattern(this.mqttNodeConfiguration.getTopicPattern(), msg); var tbMsg = ackIfNeeded(ctx, msg); - this.mqttClient.publish(topic, Unpooled.wrappedBuffer(tbMsg.getData().getBytes(UTF8)), MqttQoS.AT_LEAST_ONCE, mqttNodeConfiguration.isRetainedMessage()) + this.mqttClient.publish(topic, Unpooled.wrappedBuffer(getData(tbMsg, mqttNodeConfiguration.isParseToPlainText()).getBytes(UTF8)), + MqttQoS.AT_LEAST_ONCE, mqttNodeConfiguration.isRetainedMessage()) .addListener(future -> { if (future.isSuccess()) { tellSuccess(ctx, tbMsg); @@ -153,4 +158,39 @@ public class TbMqttNode extends TbAbstractExternalNode { return this.mqttNodeConfiguration.isSsl() ? this.mqttNodeConfiguration.getCredentials().initSslContext() : null; } + private String getData(TbMsg tbMsg, boolean parseToPlainText) { + if (parseToPlainText) { + return parseJsonStringToPlainText(tbMsg.getData()); + } + return tbMsg.getData(); + } + + protected String parseJsonStringToPlainText(String data) { + if (data.startsWith("\"") && data.endsWith("\"") && data.length() >= 2) { + final String dataBefore = data; + try { + data = JacksonUtil.fromString(data, String.class); + } catch (Exception ignored) {} + log.trace("Trimming double quotes. Before trim: [{}], after trim: [{}]", dataBefore, data); + } + + return data; + } + + @Override + public TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException { + boolean hasChanges = false; + switch (fromVersion) { + case 0: + String parseToPlainText = "parseToPlainText"; + if (!oldConfiguration.has(parseToPlainText)) { + hasChanges = true; + ((ObjectNode) oldConfiguration).put(parseToPlainText, false); + } + break; + default: + break; + } + return new TbPair<>(hasChanges, oldConfiguration); + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java index 5f13b0e677..edf3618631 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java @@ -33,6 +33,7 @@ public class TbMqttNodeConfiguration implements NodeConfiguration givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() { + return Stream.of( + // default config for version 0 + Arguments.of(0, + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"}}", + true, + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}"), + // default config for version 1 with upgrade from version 0 + Arguments.of(1, + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}", + false, + "{\"topicPattern\":\"my-topic\",\"port\":1883,\"connectTimeoutSec\":10,\"cleanSession\":true, \"ssl\":false, \"retainedMessage\":false,\"credentials\":{\"type\":\"anonymous\"},\"parseToPlainText\":false}") + ); + + } + + @Override + protected TbNode getTestNode() { + return node; + } +} \ No newline at end of file From 311ef1bb8b789bbb72032df3c757d101924c9b55 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 11 Mar 2024 15:49:12 +0200 Subject: [PATCH 2/3] added a new line to the end of the file --- .../java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java index 1f110ef11c..661d4d7791 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java @@ -76,4 +76,4 @@ class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { protected TbNode getTestNode() { return node; } -} \ No newline at end of file +} From 837933a2e02f7a558f8684cb2eb185ce34aed7e8 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Tue, 12 Mar 2024 18:53:45 +0200 Subject: [PATCH 3/3] moved the static toPlainText() method to the JacksonUtil class --- .../thingsboard/common/util/JacksonUtil.java | 16 ++++++++++++++++ .../common/util/JacksonUtilTest.java | 14 ++++++++++++++ .../rule/engine/mqtt/TbMqttNode.java | 14 +------------- .../rule/engine/rest/TbHttpClient.java | 14 +------------- .../rule/engine/mqtt/TbMqttNodeTest.java | 19 ------------------- .../rule/engine/rest/TbHttpClientTest.java | 16 ---------------- 6 files changed, 32 insertions(+), 61 deletions(-) diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index 53c3860dde..dd20282d7e 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.KvEntry; @@ -50,6 +51,7 @@ import java.util.regex.Pattern; /** * Created by Valerii Sosliuk on 5/12/2017. */ +@Slf4j public class JacksonUtil { public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @@ -150,6 +152,20 @@ public class JacksonUtil { } } + public static String toPlainText(String data) { + if (data == null) { + return null; + } + if (data.startsWith("\"") && data.endsWith("\"") && data.length() >= 2) { + final String dataBefore = data; + try { + data = JacksonUtil.fromString(data, String.class); + } catch (Exception ignored) {} + log.trace("Trimming double quotes. Before trim: [{}], after trim: [{}]", dataBefore, data); + } + return data; + } + public static T treeToValue(JsonNode node, Class clazz) { try { return OBJECT_MAPPER.treeToValue(node, clazz); diff --git a/common/util/src/test/java/org/thingsboard/common/util/JacksonUtilTest.java b/common/util/src/test/java/org/thingsboard/common/util/JacksonUtilTest.java index 7e37d34509..dcddc6e07a 100644 --- a/common/util/src/test/java/org/thingsboard/common/util/JacksonUtilTest.java +++ b/common/util/src/test/java/org/thingsboard/common/util/JacksonUtilTest.java @@ -19,6 +19,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; @@ -55,4 +58,15 @@ public class JacksonUtilTest { Assert.assertEquals(asset.getName(), result.getName()); Assert.assertEquals(asset.getType(), result.getType()); } + + @ParameterizedTest + @ValueSource(strings = { "", "false", "\"", "\"\"", "\"This is a string with double quotes\"", "Path: /home/developer/test.txt", + "First line\nSecond line\n\nFourth line", "Before\rAfter", "Tab\tSeparated\tValues", "Test\bbackspace", "[]", + "[1, 2, 3]", "{\"key\": \"value\"}", "{\n\"temperature\": 25.5,\n\"humidity\": 50.2\n\"}", "Expression: (a + b) * c", + "世界", "Україна", "\u1F1FA\u1F1E6", "🇺🇦"}) + public void toPlainTextTest(String original) { + String serialized = JacksonUtil.toString(original); + Assertions.assertNotNull(serialized); + Assertions.assertEquals(original, JacksonUtil.toPlainText(serialized)); + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 7d8935f25e..5074024be5 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -160,23 +160,11 @@ public class TbMqttNode extends TbAbstractExternalNode { private String getData(TbMsg tbMsg, boolean parseToPlainText) { if (parseToPlainText) { - return parseJsonStringToPlainText(tbMsg.getData()); + return JacksonUtil.toPlainText(tbMsg.getData()); } return tbMsg.getData(); } - protected String parseJsonStringToPlainText(String data) { - if (data.startsWith("\"") && data.endsWith("\"") && data.length() >= 2) { - final String dataBefore = data; - try { - data = JacksonUtil.fromString(data, String.class); - } catch (Exception ignored) {} - log.trace("Trimming double quotes. Before trim: [{}], after trim: [{}]", dataBefore, data); - } - - return data; - } - @Override public TbPair upgrade(int fromVersion, JsonNode oldConfiguration) throws TbNodeException { boolean hasChanges = false; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java index 73671d0e36..006afb83dc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbHttpClient.java @@ -244,23 +244,11 @@ public class TbHttpClient { private String getData(TbMsg tbMsg, boolean ignoreBody, boolean parseToPlainText) { if (!ignoreBody && parseToPlainText) { - return parseJsonStringToPlainText(tbMsg.getData()); + return JacksonUtil.toPlainText(tbMsg.getData()); } return tbMsg.getData(); } - protected String parseJsonStringToPlainText(String data) { - if (data.startsWith("\"") && data.endsWith("\"") && data.length() >= 2) { - final String dataBefore = data; - try { - data = JacksonUtil.fromString(data, String.class); - } catch (Exception ignored) {} - log.trace("Trimming double quotes. Before trim: [{}], after trim: [{}]", dataBefore, data); - } - - return data; - } - private TbMsg processResponse(TbContext ctx, TbMsg origMsg, ResponseEntity response) { TbMsgMetaData metaData = origMsg.getMetaData(); metaData.putValue(STATUS, response.getStatusCode().name()); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java index 661d4d7791..b46ecdf6fe 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeTest.java @@ -15,22 +15,16 @@ */ package org.thingsboard.rule.engine.mqtt; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.Mockito; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.AbstractRuleNodeUpgradeTest; import org.thingsboard.rule.engine.api.TbNode; import java.util.stream.Stream; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; @ExtendWith(MockitoExtension.class) @@ -43,19 +37,6 @@ class TbMqttNodeTest extends AbstractRuleNodeUpgradeTest { node = mock(TbMqttNode.class); } - @ParameterizedTest - @ValueSource(strings = { "false", "\"", "\"\"", "\"This is a string with double quotes\"", "Path: /home/developer/test.txt", - "First line\nSecond line\n\nFourth line", "Before\rAfter", "Tab\tSeparated\tValues", "Test\bbackspace", "[]", - "[1, 2, 3]", "{\"key\": \"value\"}", "{\n\"temperature\": 25.5,\n\"humidity\": 50.2\n\"}", "Expression: (a + b) * c", - "世界", "Україна", "\u1F1FA\u1F1E6", "🇺🇦"}) - public void testParseJsonStringToPlainText(String original) { - Mockito.when(node.parseJsonStringToPlainText(anyString())).thenCallRealMethod(); - - String serialized = JacksonUtil.toString(original); - Assertions.assertNotNull(serialized); - Assertions.assertEquals(original, node.parseJsonStringToPlainText(serialized)); - } - private static Stream givenFromVersionAndConfig_whenUpgrade_thenVerifyHasChangesAndConfig() { return Stream.of( // default config for version 0 diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java index b8e9aa3e38..82dbc0e508 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/rest/TbHttpClientTest.java @@ -22,14 +22,11 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.mockserver.integration.ClientAndServer; import org.springframework.util.LinkedMultiValueMap; import org.springframework.web.client.AsyncRestTemplate; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; @@ -48,7 +45,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willCallRealMethod; import static org.mockito.Mockito.mock; @@ -226,16 +222,4 @@ public class TbHttpClientTest { Assertions.assertEquals(data.get("Set-Cookie"), "[\"sap-context=sap-client=075; path=/\",\"sap-token=sap-client=075; path=/\"]"); } - @ParameterizedTest - @ValueSource(strings = { "false", "\"", "\"\"", "\"This is a string with double quotes\"", "Path: /home/developer/test.txt", - "First line\nSecond line\n\nFourth line", "Before\rAfter", "Tab\tSeparated\tValues", "Test\bbackspace", "[]", - "[1, 2, 3]", "{\"key\": \"value\"}", "{\n\"temperature\": 25.5,\n\"humidity\": 50.2\n\"}", "Expression: (a + b) * c", - "世界", "Україна", "\u1F1FA\u1F1E6", "🇺🇦"}) - public void testParseJsonStringToPlainText(String original) { - Mockito.when(client.parseJsonStringToPlainText(anyString())).thenCallRealMethod(); - - String serialized = JacksonUtil.toString(original); - Assertions.assertNotNull(serialized); - Assertions.assertEquals(original, client.parseJsonStringToPlainText(serialized)); - } }