Commit 1176f0de268d70ba76c008eaaadf8ef93f2db6c2

Authored by Igor Kulikov
2 parents 40a99403 c83c2321

Merge branch 'master' of github.com:thingsboard/thingsboard

@@ -43,7 +43,7 @@ BEGIN @@ -43,7 +43,7 @@ BEGIN
43 into max_customer_ttl; 43 into max_customer_ttl;
44 max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl); 44 max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl);
45 if max_ttl IS NOT NULL AND max_ttl > 0 THEN 45 if max_ttl IS NOT NULL AND max_ttl > 0 THEN
46 - date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - (max_ttl / 1000)); 46 + date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl);
47 partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); 47 partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date);
48 RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; 48 RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date;
49 IF partition_by_max_ttl_date IS NOT NULL THEN 49 IF partition_by_max_ttl_date IS NOT NULL THEN
@@ -193,6 +193,9 @@ public class ThingsboardInstallService { @@ -193,6 +193,9 @@ public class ThingsboardInstallService {
193 databaseEntitiesUpgradeService.upgradeDatabase("3.2.1"); 193 databaseEntitiesUpgradeService.upgradeDatabase("3.2.1");
194 case "3.2.2": 194 case "3.2.2":
195 log.info("Upgrading ThingsBoard from version 3.2.2 to 3.3.0 ..."); 195 log.info("Upgrading ThingsBoard from version 3.2.2 to 3.3.0 ...");
  196 + if (databaseTsUpgradeService != null) {
  197 + databaseTsUpgradeService.upgradeDatabase("3.2.2");
  198 + }
196 databaseEntitiesUpgradeService.upgradeDatabase("3.2.2"); 199 databaseEntitiesUpgradeService.upgradeDatabase("3.2.2");
197 200
198 dataUpdateService.updateData("3.2.2"); 201 dataUpdateService.updateData("3.2.2");
@@ -209,6 +209,12 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe @@ -209,6 +209,12 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
209 executeQuery(conn, "DROP FUNCTION IF EXISTS delete_customer_records_from_ts_kv(character varying, character varying, bigint);"); 209 executeQuery(conn, "DROP FUNCTION IF EXISTS delete_customer_records_from_ts_kv(character varying, character varying, bigint);");
210 } 210 }
211 break; 211 break;
  212 + case "3.2.2":
  213 + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
  214 + log.info("Load Drop Partitions functions ...");
  215 + loadSql(conn, LOAD_DROP_PARTITIONS_FUNCTIONS_SQL, "2.4.3");
  216 + }
  217 + break;
212 default: 218 default:
213 throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); 219 throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
214 } 220 }
@@ -120,13 +120,17 @@ @@ -120,13 +120,17 @@
120 <groupId>org.apache.curator</groupId> 120 <groupId>org.apache.curator</groupId>
121 <artifactId>curator-recipes</artifactId> 121 <artifactId>curator-recipes</artifactId>
122 </dependency> 122 </dependency>
123 -  
124 <dependency> 123 <dependency>
125 <groupId>junit</groupId> 124 <groupId>junit</groupId>
126 <artifactId>junit</artifactId> 125 <artifactId>junit</artifactId>
127 <scope>test</scope> 126 <scope>test</scope>
128 </dependency> 127 </dependency>
129 <dependency> 128 <dependency>
  129 + <groupId>org.hamcrest</groupId>
  130 + <artifactId>hamcrest</artifactId>
  131 + <scope>test</scope>
  132 + </dependency>
  133 + <dependency>
130 <groupId>org.mockito</groupId> 134 <groupId>org.mockito</groupId>
131 <artifactId>mockito-core</artifactId> 135 <artifactId>mockito-core</artifactId>
132 <scope>test</scope> 136 <scope>test</scope>
@@ -41,6 +41,7 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; @@ -41,6 +41,7 @@ import org.thingsboard.server.common.transport.TransportServiceCallback;
41 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 41 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
42 import org.thingsboard.server.common.transport.util.SslUtil; 42 import org.thingsboard.server.common.transport.util.SslUtil;
43 import org.thingsboard.server.gen.transport.TransportProtos; 43 import org.thingsboard.server.gen.transport.TransportProtos;
  44 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
44 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; 45 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
45 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; 46 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
46 import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; 47 import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials;
@@ -61,6 +62,7 @@ import java.util.concurrent.TimeUnit; @@ -61,6 +62,7 @@ import java.util.concurrent.TimeUnit;
61 62
62 @Slf4j 63 @Slf4j
63 @Component 64 @Component
  65 +@TbLwM2mTransportComponent
64 @RequiredArgsConstructor 66 @RequiredArgsConstructor
65 public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier { 67 public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier {
66 68
@@ -228,29 +228,27 @@ public class JsonConverter { @@ -228,29 +228,27 @@ public class JsonConverter {
228 private static KeyValueProto buildNumericKeyValueProto(JsonPrimitive value, String key) { 228 private static KeyValueProto buildNumericKeyValueProto(JsonPrimitive value, String key) {
229 String valueAsString = value.getAsString(); 229 String valueAsString = value.getAsString();
230 KeyValueProto.Builder builder = KeyValueProto.newBuilder().setKey(key); 230 KeyValueProto.Builder builder = KeyValueProto.newBuilder().setKey(key);
231 - if (valueAsString.contains("e") || valueAsString.contains("E")) {  
232 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
233 - var bd = new BigDecimal(valueAsString);  
234 - if (bd.stripTrailingZeros().scale() <= 0) {  
235 - try {  
236 - return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build();  
237 - } catch (ArithmeticException e) {  
238 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build(); 231 + var bd = new BigDecimal(valueAsString);
  232 + if (bd.stripTrailingZeros().scale() <= 0) {
  233 + try {
  234 + return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build();
  235 + } catch (ArithmeticException e) {
  236 + if (isTypeCastEnabled) {
  237 + return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
  238 + } else {
  239 + throw new JsonSyntaxException("Big integer values are not supported!");
239 } 240 }
240 - } else {  
241 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();  
242 } 241 }
243 - } else if (valueAsString.contains(".")) {  
244 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(value.getAsDouble()).build();  
245 } else { 242 } else {
246 - try {  
247 - long longValue = Long.parseLong(value.getAsString());  
248 - return builder.setType(KeyValueType.LONG_V).setLongV(longValue).build();  
249 - } catch (NumberFormatException e) {  
250 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
251 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(new BigDecimal(valueAsString).doubleValue()).build(); 243 + if (bd.scale() <= 16) {
  244 + return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();
  245 + } else if (isTypeCastEnabled) {
  246 + return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
  247 + } else {
  248 + throw new JsonSyntaxException("Big integer values are not supported!");
252 } 249 }
253 } 250 }
  251 +
254 } 252 }
255 253
256 public static TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(JsonElement json, int requestId) throws JsonSyntaxException { 254 public static TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(JsonElement json, int requestId) throws JsonSyntaxException {
@@ -261,27 +259,24 @@ public class JsonConverter { @@ -261,27 +259,24 @@ public class JsonConverter {
261 private static void parseNumericValue(List<KvEntry> result, Entry<String, JsonElement> valueEntry, JsonPrimitive value) { 259 private static void parseNumericValue(List<KvEntry> result, Entry<String, JsonElement> valueEntry, JsonPrimitive value) {
262 String valueAsString = value.getAsString(); 260 String valueAsString = value.getAsString();
263 String key = valueEntry.getKey(); 261 String key = valueEntry.getKey();
264 - if (valueAsString.contains("e") || valueAsString.contains("E")) {  
265 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
266 - var bd = new BigDecimal(valueAsString);  
267 - if (bd.stripTrailingZeros().scale() <= 0) {  
268 - try {  
269 - result.add(new LongDataEntry(key, bd.longValueExact()));  
270 - } catch (ArithmeticException e) {  
271 - result.add(new DoubleDataEntry(key, bd.doubleValue())); 262 + var bd = new BigDecimal(valueAsString);
  263 + if (bd.stripTrailingZeros().scale() <= 0) {
  264 + try {
  265 + result.add(new LongDataEntry(key, bd.longValueExact()));
  266 + } catch (ArithmeticException e) {
  267 + if (isTypeCastEnabled) {
  268 + result.add(new StringDataEntry(key, bd.toPlainString()));
  269 + } else {
  270 + throw new JsonSyntaxException("Big integer values are not supported!");
272 } 271 }
273 - } else {  
274 - result.add(new DoubleDataEntry(key, bd.doubleValue()));  
275 } 272 }
276 - } else if (valueAsString.contains(".")) {  
277 - result.add(new DoubleDataEntry(key, value.getAsDouble()));  
278 } else { 273 } else {
279 - try {  
280 - long longValue = Long.parseLong(value.getAsString());  
281 - result.add(new LongDataEntry(key, longValue));  
282 - } catch (NumberFormatException e) {  
283 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
284 - result.add(new DoubleDataEntry(key, new BigDecimal(valueAsString).doubleValue())); 274 + if (bd.scale() <= 16) {
  275 + result.add(new DoubleDataEntry(key, bd.doubleValue()));
  276 + } else if (isTypeCastEnabled) {
  277 + result.add(new StringDataEntry(key, bd.toPlainString()));
  278 + } else {
  279 + throw new JsonSyntaxException("Big integer values are not supported!");
285 } 280 }
286 } 281 }
287 } 282 }
@@ -15,7 +15,9 @@ @@ -15,7 +15,9 @@
15 */ 15 */
16 16
17 import com.google.gson.JsonParser; 17 import com.google.gson.JsonParser;
  18 +import com.google.gson.JsonSyntaxException;
18 import org.junit.Assert; 19 import org.junit.Assert;
  20 +import org.junit.Before;
19 import org.junit.Test; 21 import org.junit.Test;
20 import org.junit.runner.RunWith; 22 import org.junit.runner.RunWith;
21 import org.mockito.junit.MockitoJUnitRunner; 23 import org.mockito.junit.MockitoJUnitRunner;
@@ -28,6 +30,11 @@ public class JsonConverterTest { @@ -28,6 +30,11 @@ public class JsonConverterTest {
28 30
29 private static final JsonParser JSON_PARSER = new JsonParser(); 31 private static final JsonParser JSON_PARSER = new JsonParser();
30 32
  33 + @Before
  34 + public void before() {
  35 + JsonConverter.setTypeCastEnabled(true);
  36 + }
  37 +
31 @Test 38 @Test
32 public void testParseBigDecimalAsLong() { 39 public void testParseBigDecimalAsLong() {
33 var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E+1}"), 0L); 40 var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E+1}"), 0L);
@@ -58,4 +65,33 @@ public class JsonConverterTest { @@ -58,4 +65,33 @@ public class JsonConverterTest {
58 Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue()); 65 Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue());
59 } 66 }
60 67
  68 + @Test
  69 + public void testParseBigDecimalAsStringOutOfLongRange() {
  70 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
  71 + Assert.assertEquals("99701010061400066000", result.get(0L).get(0).getStrValue().get());
  72 + }
  73 +
  74 + @Test
  75 + public void testParseBigDecimalAsStringOutOfLongRange2() {
  76 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 99701010061400066001}"), 0L);
  77 + Assert.assertEquals("99701010061400066001", result.get(0L).get(0).getStrValue().get());
  78 + }
  79 +
  80 + @Test
  81 + public void testParseBigDecimalAsStringOutOfLongRange3() {
  82 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E19}"), 0L);
  83 + Assert.assertEquals("10000000000000000000", result.get(0L).get(0).getStrValue().get());
  84 + }
  85 +
  86 + @Test(expected = JsonSyntaxException.class)
  87 + public void testParseBigDecimalOutOfLongRangeWithoutParsing() {
  88 + JsonConverter.setTypeCastEnabled(false);
  89 + JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 89701010051400054084}"), 0L);
  90 + }
  91 +
  92 + @Test(expected = JsonSyntaxException.class)
  93 + public void testParseBigDecimalOutOfLongRangeWithoutParsing2() {
  94 + JsonConverter.setTypeCastEnabled(false);
  95 + JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
  96 + }
61 } 97 }
@@ -63,7 +63,7 @@ BEGIN @@ -63,7 +63,7 @@ BEGIN
63 into max_customer_ttl; 63 into max_customer_ttl;
64 max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl); 64 max_ttl := GREATEST(system_ttl, max_customer_ttl, max_tenant_ttl);
65 if max_ttl IS NOT NULL AND max_ttl > 0 THEN 65 if max_ttl IS NOT NULL AND max_ttl > 0 THEN
66 - date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - (max_ttl / 1000)); 66 + date := to_timestamp(EXTRACT(EPOCH FROM current_timestamp) - max_ttl);
67 partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date); 67 partition_by_max_ttl_date := get_partition_by_max_ttl_date(partition_type, date);
68 RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date; 68 RAISE NOTICE 'Partition by max ttl: %', partition_by_max_ttl_date;
69 IF partition_by_max_ttl_date IS NOT NULL THEN 69 IF partition_by_max_ttl_date IS NOT NULL THEN
@@ -104,11 +104,12 @@ BEGIN @@ -104,11 +104,12 @@ BEGIN
104 END IF; 104 END IF;
105 END IF; 105 END IF;
106 END IF; 106 END IF;
107 - END IF;  
108 - IF partition_to_delete IS NOT NULL THEN  
109 - RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete;  
110 - EXECUTE format('DROP TABLE %I', partition_to_delete);  
111 - deleted := deleted + 1; 107 + IF partition_to_delete IS NOT NULL THEN
  108 + RAISE NOTICE 'Partition to delete by max ttl: %', partition_to_delete;
  109 + EXECUTE format('DROP TABLE IF EXISTS %I', partition_to_delete);
  110 + partition_to_delete := NULL;
  111 + deleted := deleted + 1;
  112 + END IF;
112 END IF; 113 END IF;
113 END LOOP; 114 END LOOP;
114 END IF; 115 END IF;
@@ -48,6 +48,7 @@ @@ -48,6 +48,7 @@
48 <json-path.version>2.2.0</json-path.version> 48 <json-path.version>2.2.0</json-path.version>
49 <junit.version>4.12</junit.version> 49 <junit.version>4.12</junit.version>
50 <jupiter.version>5.7.1</jupiter.version> 50 <jupiter.version>5.7.1</jupiter.version>
  51 + <hamcrest.version>2.2</hamcrest.version>
51 <slf4j.version>1.7.7</slf4j.version> 52 <slf4j.version>1.7.7</slf4j.version>
52 <logback.version>1.2.3</logback.version> 53 <logback.version>1.2.3</logback.version>
53 <mockito.version>3.3.3</mockito.version> 54 <mockito.version>3.3.3</mockito.version>
@@ -94,7 +95,7 @@ @@ -94,7 +95,7 @@
94 <hsqldb.version>2.5.0</hsqldb.version> 95 <hsqldb.version>2.5.0</hsqldb.version>
95 <dbunit.version>2.5.3</dbunit.version> 96 <dbunit.version>2.5.3</dbunit.version>
96 <spring-test-dbunit.version>1.2.1</spring-test-dbunit.version> 97 <spring-test-dbunit.version>1.2.1</spring-test-dbunit.version>
97 - <postgresql.driver.version>42.2.16</postgresql.driver.version> 98 + <postgresql.driver.version>42.2.20</postgresql.driver.version>
98 <sonar.exclusions>org/thingsboard/server/gen/**/*, 99 <sonar.exclusions>org/thingsboard/server/gen/**/*,
99 org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/* 100 org/thingsboard/server/extensions/core/plugin/telemetry/gen/**/*
100 </sonar.exclusions> 101 </sonar.exclusions>
@@ -1372,6 +1373,12 @@ @@ -1372,6 +1373,12 @@
1372 <scope>test</scope> 1373 <scope>test</scope>
1373 </dependency> 1374 </dependency>
1374 <dependency> 1375 <dependency>
  1376 + <groupId>org.hamcrest</groupId>
  1377 + <artifactId>hamcrest</artifactId>
  1378 + <version>${hamcrest.version}</version>
  1379 + <scope>test</scope>
  1380 + </dependency>
  1381 + <dependency>
1375 <groupId>org.junit.jupiter</groupId> 1382 <groupId>org.junit.jupiter</groupId>
1376 <artifactId>junit-jupiter-params</artifactId> 1383 <artifactId>junit-jupiter-params</artifactId>
1377 <version>${jupiter.version}</version> 1384 <version>${jupiter.version}</version>