Commit 1176f0de268d70ba76c008eaaadf8ef93f2db6c2
Merge branch 'master' of github.com:thingsboard/thingsboard
Showing
9 changed files
with
99 additions
and
45 deletions
@@ -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> |