From 643563ec6a8cdce5df02b1e4adfc8d7a8d9c00ae Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Wed, 11 Nov 2020 13:24:10 +0200 Subject: [PATCH 01/32] bug-fix: trip animation for multiple devices --- .../components/widget/lib/maps/leaflet-map.ts | 38 +++--- .../trip-animation.component.ts | 111 ++++++++++++------ 2 files changed, 99 insertions(+), 50 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 5d6f39850e..6944e4d23d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -599,26 +599,32 @@ export default abstract class LeafletMap { return polygon; } - updatePoints(pointsData: FormattedData[], getTooltip: (point: FormattedData, setTooltip?: boolean) => string) { - if (this.points) { + updatePoints(pointsData: FormattedData[][], getTooltip: (point: FormattedData[], setTooltip?: boolean) => string) { + for(let i = 0; i < pointsData.length; i++) { + let pointsList = pointsData[i]; + if(i === 0) { + if (this.points) { this.map.removeLayer(this.points); + } + this.points = new FeatureGroup(); } - this.points = new FeatureGroup(); - pointsData.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { - const point = L.circleMarker(this.convertPosition(data), { - color: this.options.pointColor, - radius: this.options.pointSize - }); - if (!this.options.pointTooltipOnRightPanel) { - point.on('click', () => getTooltip(data)); - } - else { - createTooltip(point, this.options, data.$datasource, getTooltip(data, false)); - } - this.points.addLayer(point); + pointsList.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { + const point = L.circleMarker(this.convertPosition(data), { + color: this.options.pointColor, + radius: this.options.pointSize + }); + if (!this.options.pointTooltipOnRightPanel) { + point.on('click', () => getTooltip([data])); + } else { + createTooltip(point, this.options, data.$datasource, getTooltip([data], false)); + } + this.points.addLayer(point); }); - this.map.addLayer(this.points); + if(i === 0) { + this.map.addLayer(this.points); + } } + } // Polyline diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 99c399d3f2..b51cda6cbb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -47,6 +47,9 @@ import moment from 'moment'; import { isUndefined } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; +interface dataMap { + [key: string] : FormattedData +} @Component({ // tslint:disable-next-line:component-selector @@ -70,7 +73,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy interpolatedTimeData = []; widgetConfig: WidgetConfig; settings: TripAnimationSettings; - mainTooltip = ''; + mainTooltips = []; visibleTooltip = false; activeTrip: FormattedData; label: string; @@ -115,7 +118,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.historicalData = parseArray(this.ctx.data).filter(arr => arr.length); if (this.historicalData.length) { this.calculateIntervals(); - this.timeUpdated(this.currentTime && this.currentTime > this.minTime ? this.currentTime : this.minTime); + this.timeUpdated(this.minTime); } this.mapWidget.map.map?.invalidateSize(); this.cd.detectChanges(); @@ -138,34 +141,41 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy timeUpdated(time: number) { this.currentTime = time; - const currentPosition = this.interpolatedTimeData + let currentPosition = this.interpolatedTimeData .map(dataSource => dataSource[time]) - .filter(ds => ds); - if (isUndefined(currentPosition[0])) { - const timePoints = Object.keys(this.interpolatedTimeData[0]).map(item => parseInt(item, 10)); - for (let i = 1; i < timePoints.length; i++) { - if (timePoints[i - 1] < time && timePoints[i] > time) { - const beforePosition = this.interpolatedTimeData[0][timePoints[i - 1]]; - const afterPosition = this.interpolatedTimeData[0][timePoints[i]]; - const ratio = getRatio(timePoints[i - 1], timePoints[i], time); - currentPosition[0] = { - ...beforePosition, - time, - ...interpolateOnLineSegment(beforePosition, afterPosition, this.settings.latKeyName, this.settings.lngKeyName, ratio) + for(let j = 0; j < this.interpolatedTimeData.length; j++) { + if (isUndefined(currentPosition[j])) { + const timePoints = Object.keys(this.interpolatedTimeData[j]).map(item => parseInt(item, 10)); + for (let i = 1; i < timePoints.length; i++) { + if (timePoints[i - 1] < time && timePoints[i] > time) { + const beforePosition = this.interpolatedTimeData[j][timePoints[i - 1]]; + const afterPosition = this.interpolatedTimeData[j][timePoints[i]]; + const ratio = getRatio(timePoints[i - 1], timePoints[i], time); + currentPosition[j] = { + ...beforePosition, + time, + ...interpolateOnLineSegment(beforePosition, afterPosition, this.settings.latKeyName, this.settings.lngKeyName, ratio) + } + break; } - break; } } } - this.calcLabel(); - this.calcTooltip(currentPosition.find(position => position.entityName === this.activeTrip.entityName)); + for(let j = 0; j < this.interpolatedTimeData.length; j++) { + if (isUndefined(currentPosition[j])) { + currentPosition[j] = this.calculateLastPoints(this.interpolatedTimeData[j], time); + } + } + this.calcLabel(currentPosition); + this.calcTooltip(currentPosition, true); if (this.mapWidget && this.mapWidget.map && this.mapWidget.map.map) { - this.mapWidget.map.updatePolylines(this.interpolatedTimeData.map(ds => _.values(ds)), true, this.activeTrip); + const formattedInterpolatedTimeData = this.interpolatedTimeData.map(ds => _.values(ds)); + this.mapWidget.map.updatePolylines(formattedInterpolatedTimeData, true); if (this.settings.showPolygon) { this.mapWidget.map.updatePolygons(this.interpolatedTimeData); } if (this.settings.showPoints) { - this.mapWidget.map.updatePoints(_.values(_.union(this.interpolatedTimeData)[0]), this.calcTooltip); + this.mapWidget.map.updatePoints(formattedInterpolatedTimeData, this.calcTooltip); } this.mapWidget.map.updateMarkers(currentPosition, true, (trip) => { this.activeTrip = trip; @@ -177,6 +187,23 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy setActiveTrip() { } + private calculateLastPoints(dataSource: dataMap, time: number): FormattedData { + const timeArr = Object.keys(dataSource); + let index = timeArr.findIndex((dtime, index) => { + return Number(dtime) >= time; + }); + + if(index !== -1) { + if(Number(timeArr[index]) !== time && index !== 0) { + index--; + } + } else { + index = timeArr.length - 1; + } + + return dataSource[timeArr[index]]; + } + calculateIntervals() { this.historicalData.forEach((dataSource, index) => { this.minTime = dataSource[0]?.time || Infinity; @@ -194,23 +221,39 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy } } - calcTooltip = (point?: FormattedData): string => { - const data = point ? point : this.activeTrip; - const tooltipPattern: string = this.settings.useTooltipFunction ? - safeExecute(this.settings.tooltipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern; - const tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true); - this.mainTooltip = this.sanitizer.sanitize( - SecurityContext.HTML, tooltipText); - this.cd.detectChanges(); - this.activeTrip = point; + calcTooltip = (points?: FormattedData[], isMainTooltip: boolean = false): string => { + let tooltipText; + if(isMainTooltip) { + this.mainTooltips = [] + } + for (let point of points) { + const data = point ? point : this.activeTrip; + const tooltipPattern: string = this.settings.useTooltipFunction ? + safeExecute(this.settings.tooltipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern; + tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true); + if(isMainTooltip) { + this.mainTooltips.push(this.sanitizer.sanitize(SecurityContext.HTML, tooltipText)); + } + this.cd.detectChanges(); + this.activeTrip = point; + } return tooltipText; } - calcLabel() { - const data = this.activeTrip; - const labelText: string = this.settings.useLabelFunction ? - safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; - this.label = (parseWithTranslation.parseTemplate(labelText, data, true)); + calcLabel(formattedDataArr: FormattedData[]) { + // const data = this.activeTrip; + // const labelText: string = this.settings.useLabelFunction ? + // safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; + // this.label = (parseWithTranslation.parseTemplate(labelText, data, true)); + // console.log(this.label, 'this.label'); + this.label = ''; + for (let formattedData of formattedDataArr) { + const data = formattedData; + const labelText: string = this.settings.useLabelFunction ? + safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; + const label = (parseWithTranslation.parseTemplate(labelText, data, true)); + this.label = this.label.length ? this.label + ',' + label : label; + } } interpolateArray(originData: FormattedData[]) { From 33b1cee2d018a277d7179e3d6fcd4600f0dd99dc Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Wed, 11 Nov 2020 13:27:18 +0200 Subject: [PATCH 02/32] bug-fix: trip animation for multiple devices --- .../widget/trip-animation/trip-animation.component.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index b51cda6cbb..a392481259 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -241,11 +241,6 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy } calcLabel(formattedDataArr: FormattedData[]) { - // const data = this.activeTrip; - // const labelText: string = this.settings.useLabelFunction ? - // safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; - // this.label = (parseWithTranslation.parseTemplate(labelText, data, true)); - // console.log(this.label, 'this.label'); this.label = ''; for (let formattedData of formattedDataArr) { const data = formattedData; From 2e624994da5da91f42b127f02bb6777432cba433 Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Wed, 11 Nov 2020 14:38:24 +0200 Subject: [PATCH 03/32] additional fix to component html --- .../widget/trip-animation/trip-animation.component.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html index 2ea80cf2af..be82969986 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html @@ -28,8 +28,12 @@
+ [ngClass]="{'trip-animation-tooltip-hidden':!visibleTooltip}" + [ngStyle]="{'background-color': settings.tooltipColor, 'opacity': settings.tooltipOpacity, 'color': settings.tooltipFontColor}"> +
+
Date: Wed, 11 Nov 2020 16:22:57 +0200 Subject: [PATCH 04/32] added # filter topic handling --- .../transport/mqtt/util/MqttTopicFilterFactory.java | 13 +++++++++---- .../mqtt/util/MqttTopicFilterFactoryTest.java | 11 ++++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java index 4d5a9a7c2b..9893f8cbef 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java @@ -34,10 +34,15 @@ public class MqttTopicFilterFactory { } return filters.computeIfAbsent(topicFilter, filter -> { if (filter.contains("+") || filter.contains("#")) { - String regex = filter - .replace("\\", "\\\\") - .replace("+", "[^/]+") - .replace("/#", "($|/.*)"); + String regex; + if (filter.equals("#")) { + regex = filter.replace("#", "^(?!/).+"); + } else { + regex = filter + .replace("\\", "\\\\") + .replace("+", "[^/]+") + .replace("/#", "($|/.*)"); + } log.debug("Converting [{}] to [{}]", filter, regex); return new RegexTopicFilter(regex); } else { diff --git a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java index 0b854d51ef..f3a65bda14 100644 --- a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java +++ b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java @@ -20,7 +20,6 @@ import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; import javax.script.ScriptException; -import java.util.regex.Pattern; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -32,6 +31,9 @@ public class MqttTopicFilterFactoryTest { private static String TEST_STR_2 = "Sensor/Temperature"; private static String TEST_STR_3 = "Sensor/Temperature2/House/48"; + private static String TEST_STR_4 = String.format("%s%n%s", "/Sensor/Temperature", "/House/48"); + private static String TEST_STR_5 = "/" + TEST_STR_1; + @Test public void metadataCanBeUpdated() throws ScriptException { MqttTopicFilter filter = MqttTopicFilterFactory.toFilter("Sensor/Temperature/House/+"); @@ -51,6 +53,13 @@ public class MqttTopicFilterFactoryTest { assertTrue(filter.filter(TEST_STR_1)); assertTrue(filter.filter(TEST_STR_2)); assertFalse(filter.filter(TEST_STR_3)); + + filter = MqttTopicFilterFactory.toFilter("#"); + assertTrue(filter.filter(TEST_STR_1)); + assertTrue(filter.filter(TEST_STR_2)); + assertTrue(filter.filter(TEST_STR_3)); + assertFalse(filter.filter(TEST_STR_4)); + assertFalse(filter.filter(TEST_STR_5)); } } From 4ee38a15d3c658dc6b276af95f6290f90f1f0dcf Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 11 Nov 2020 19:31:21 +0200 Subject: [PATCH 05/32] change regex for # filter --- .../transport/mqtt/util/MqttTopicFilterFactory.java | 2 +- .../mqtt/util/MqttTopicFilterFactoryTest.java | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java index 9893f8cbef..98e472ba5c 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java @@ -36,7 +36,7 @@ public class MqttTopicFilterFactory { if (filter.contains("+") || filter.contains("#")) { String regex; if (filter.equals("#")) { - regex = filter.replace("#", "^(?!/).+"); + regex = filter.replace("#", "\\S+"); } else { regex = filter .replace("\\", "\\\\") diff --git a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java index f3a65bda14..2ec05fac78 100644 --- a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java +++ b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java @@ -30,9 +30,10 @@ public class MqttTopicFilterFactoryTest { private static String TEST_STR_1 = "Sensor/Temperature/House/48"; private static String TEST_STR_2 = "Sensor/Temperature"; private static String TEST_STR_3 = "Sensor/Temperature2/House/48"; - - private static String TEST_STR_4 = String.format("%s%n%s", "/Sensor/Temperature", "/House/48"); - private static String TEST_STR_5 = "/" + TEST_STR_1; + private static String TEST_STR_4 = "/Sensor/Temperature2/House/48"; + private static String TEST_STR_5 = String.format("%s%n%s", "/Sensor/Temperature", "/House/48"); + private static String TEST_STR_6 = ""; + private static String TEST_STR_7 = " "; @Test public void metadataCanBeUpdated() throws ScriptException { @@ -58,8 +59,10 @@ public class MqttTopicFilterFactoryTest { assertTrue(filter.filter(TEST_STR_1)); assertTrue(filter.filter(TEST_STR_2)); assertTrue(filter.filter(TEST_STR_3)); - assertFalse(filter.filter(TEST_STR_4)); + assertTrue(filter.filter(TEST_STR_4)); assertFalse(filter.filter(TEST_STR_5)); + assertFalse(filter.filter(TEST_STR_6)); + assertFalse(filter.filter(TEST_STR_7)); } } From 3127678d17788d8e8101bda0921e4af78e2b56cb Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 16 Nov 2020 16:52:24 +0200 Subject: [PATCH 06/32] added AlwaysTrueTopicFilter --- .../mqtt/util/AlwaysTrueTopicFilter.java | 27 +++++++++++++++++++ .../mqtt/util/MqttTopicFilterFactory.java | 2 +- .../mqtt/util/MqttTopicFilterFactoryTest.java | 13 ++++----- 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/AlwaysTrueTopicFilter.java diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/AlwaysTrueTopicFilter.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/AlwaysTrueTopicFilter.java new file mode 100644 index 0000000000..9952c4b507 --- /dev/null +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/AlwaysTrueTopicFilter.java @@ -0,0 +1,27 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed 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.thingsboard.server.transport.mqtt.util; + +import lombok.Data; + +@Data +public class AlwaysTrueTopicFilter implements MqttTopicFilter { + + @Override + public boolean filter(String topic) { + return true; + } +} diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java index 98e472ba5c..f2b4ef27e2 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java @@ -36,7 +36,7 @@ public class MqttTopicFilterFactory { if (filter.contains("+") || filter.contains("#")) { String regex; if (filter.equals("#")) { - regex = filter.replace("#", "\\S+"); + return new AlwaysTrueTopicFilter(); } else { regex = filter .replace("\\", "\\\\") diff --git a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java index 2ec05fac78..fac2e5c01d 100644 --- a/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java +++ b/common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactoryTest.java @@ -31,9 +31,8 @@ public class MqttTopicFilterFactoryTest { private static String TEST_STR_2 = "Sensor/Temperature"; private static String TEST_STR_3 = "Sensor/Temperature2/House/48"; private static String TEST_STR_4 = "/Sensor/Temperature2/House/48"; - private static String TEST_STR_5 = String.format("%s%n%s", "/Sensor/Temperature", "/House/48"); - private static String TEST_STR_6 = ""; - private static String TEST_STR_7 = " "; + private static String TEST_STR_5 = "Sensor/ Temperature"; + private static String TEST_STR_6 = "/"; @Test public void metadataCanBeUpdated() throws ScriptException { @@ -60,9 +59,11 @@ public class MqttTopicFilterFactoryTest { assertTrue(filter.filter(TEST_STR_2)); assertTrue(filter.filter(TEST_STR_3)); assertTrue(filter.filter(TEST_STR_4)); - assertFalse(filter.filter(TEST_STR_5)); - assertFalse(filter.filter(TEST_STR_6)); - assertFalse(filter.filter(TEST_STR_7)); + assertTrue(filter.filter(TEST_STR_5)); + assertTrue(filter.filter(TEST_STR_6)); + + filter = MqttTopicFilterFactory.toFilter("Sensor/Temperature#"); + assertFalse(filter.filter(TEST_STR_2)); } } From 22c91039553c1ef31c86a3fdfd437ff115e04320 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 16 Nov 2020 16:55:24 +0200 Subject: [PATCH 07/32] fix MqttTopicFilterFactory toFilter --- .../mqtt/util/MqttTopicFilterFactory.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java index f2b4ef27e2..0c3b497591 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/MqttTopicFilterFactory.java @@ -33,16 +33,13 @@ public class MqttTopicFilterFactory { throw new IllegalArgumentException("Topic filter can't be empty!"); } return filters.computeIfAbsent(topicFilter, filter -> { - if (filter.contains("+") || filter.contains("#")) { - String regex; - if (filter.equals("#")) { - return new AlwaysTrueTopicFilter(); - } else { - regex = filter - .replace("\\", "\\\\") - .replace("+", "[^/]+") - .replace("/#", "($|/.*)"); - } + if (filter.equals("#")) { + return new AlwaysTrueTopicFilter(); + } else if (filter.contains("+") || filter.contains("#")) { + String regex = filter + .replace("\\", "\\\\") + .replace("+", "[^/]+") + .replace("/#", "($|/.*)"); log.debug("Converting [{}] to [{}]", filter, regex); return new RegexTopicFilter(regex); } else { From 9a03fbadc75d6ff3f1a08467645a2314224caa65 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 10 Dec 2020 17:55:16 +0200 Subject: [PATCH 08/32] added ability to get attributes and timeseries keys by entity query --- .../controller/EntityQueryController.java | 51 +++++++++++++++++++ .../dao/attributes/AttributesService.java | 3 ++ .../dao/timeseries/TimeseriesService.java | 2 + .../server/dao/attributes/AttributesDao.java | 3 ++ .../dao/attributes/BaseAttributesService.java | 6 +++ .../sql/attributes/AttributeKvRepository.java | 3 ++ .../dao/sql/attributes/JpaAttributeDao.java | 7 +++ .../dao/sqlts/SqlTimeseriesLatestDao.java | 6 +++ .../sqlts/latest/TsKvLatestRepository.java | 5 ++ .../dao/timeseries/BaseTimeseriesService.java | 5 ++ .../CassandraBaseTimeseriesLatestDao.java | 5 ++ .../dao/timeseries/TimeseriesLatestDao.java | 2 + 12 files changed, 98 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 94417886d6..e58eee59a6 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -23,15 +23,25 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.exception.ThingsboardException; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; +import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; +import org.thingsboard.server.dao.attributes.AttributesService; +import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.query.EntityQueryService; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + @RestController @TbCoreComponent @RequestMapping("/api") @@ -40,6 +50,12 @@ public class EntityQueryController extends BaseController { @Autowired private EntityQueryService entityQueryService; + @Autowired + private AttributesService attributesService; + + @Autowired + private TimeseriesService timeseriesService; + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST) @@ -76,4 +92,39 @@ public class EntityQueryController extends BaseController { throw handleException(e); } } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/entitiesQuery/find/keys/timeseries", method = RequestMethod.POST) + @ResponseBody + public List findEntityTimeseriesKeysByQuery(@RequestBody EntityDataQuery query) throws ThingsboardException { + TenantId tenantId = getTenantId(); + return getKeys(query, entityIds -> timeseriesService.findAllKeysByEntityIds(tenantId, entityIds)); + } + + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/entitiesQuery/find/keys/attributes", method = RequestMethod.POST) + @ResponseBody + public List findEntityAttributesKeysByQuery(@RequestBody EntityDataQuery query) throws ThingsboardException { + TenantId tenantId = getTenantId(); + return getKeys(query, entityIds -> attributesService.findAllKeysByEntityIds(tenantId, entityIds.get(0).getEntityType(), entityIds)); + } + + private List getKeys(EntityDataQuery query, Function, List> function) throws ThingsboardException { + checkNotNull(query); + try { + EntityDataPageLink pageLink = query.getPageLink(); + if (pageLink.getPageSize() > 100) { + pageLink.setPageSize(100); + } + List ids = this.entityQueryService.findEntityDataByQuery(getCurrentUser(), query).getData().stream() + .map(EntityData::getEntityId) + .collect(Collectors.toList()); + if (ids.isEmpty()) { + return Collections.emptyList(); + } + return function.apply(ids); + } catch (Exception e) { + throw handleException(e); + } + } } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java index 2e5c895f84..47f1f91376 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/attributes/AttributesService.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.attributes; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -42,4 +43,6 @@ public interface AttributesService { List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); + List findAllKeysByEntityIds(TenantId tenantId, EntityType entityType, List entityIds); + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java index dbfbe3d0f5..ccf933e03d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesService.java @@ -50,4 +50,6 @@ public interface TimeseriesService { ListenableFuture> removeAllLatest(TenantId tenantId, EntityId entityId); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); + + List findAllKeysByEntityIds(TenantId tenantId, List entityIds); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesDao.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesDao.java index 458a251f8a..f1af5a1b1b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributesDao.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.attributes; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -41,4 +42,6 @@ public interface AttributesDao { ListenableFuture> removeAll(TenantId tenantId, EntityId entityId, String attributeType, List keys); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); + + List findAllKeysByEntityIds(TenantId tenantId, EntityType entityType, List entityIds); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java index 2e18006036..24f988c79d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/BaseAttributesService.java @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -65,6 +66,11 @@ public class BaseAttributesService implements AttributesService { return attributesDao.findAllKeysByDeviceProfileId(tenantId, deviceProfileId); } + @Override + public List findAllKeysByEntityIds(TenantId tenantId, EntityType entityType, List entityIds) { + return attributesDao.findAllKeysByEntityIds(tenantId, entityType, entityIds); + } + @Override public ListenableFuture> save(TenantId tenantId, EntityId entityId, String scope, List attributes) { validate(entityId, scope); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvRepository.java index f6c3e195e7..3d14730b54 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvRepository.java @@ -56,5 +56,8 @@ public interface AttributeKvRepository extends CrudRepository findAllKeysByTenantId(@Param("tenantId") UUID tenantId); + @Query(value = "SELECT DISTINCT attribute_key FROM attribute_kv WHERE entity_type = :entityType " + + "AND entity_id in :entityIds ORDER BY attribute_key", nativeQuery = true) + List findAllKeysByEntityIds(@Param("entityType") String entityType, @Param("entityIds") List entityIds); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java index a95bd4b612..a6a9348e8f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java @@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -145,6 +146,12 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl } } + @Override + public List findAllKeysByEntityIds(TenantId tenantId, EntityType entityType, List entityIds) { + return attributeKvRepository + .findAllKeysByEntityIds(entityType.name(), entityIds.stream().map(EntityId::getId).collect(Collectors.toList())); + } + @Override public ListenableFuture save(TenantId tenantId, EntityId entityId, String attributeType, AttributeKvEntry attribute) { AttributeKvEntity entity = new AttributeKvEntity(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java index ff602e6eed..a97fa97a5c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/SqlTimeseriesLatestDao.java @@ -61,6 +61,7 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.function.Function; +import java.util.stream.Collectors; @Slf4j @Component @@ -169,6 +170,11 @@ public class SqlTimeseriesLatestDao extends BaseAbstractSqlTimeseriesDao impleme } } + @Override + public List findAllKeysByEntityIds(TenantId tenantId, List entityIds) { + return tsKvLatestRepository.findAllKeysByEntityIds(entityIds.stream().map(EntityId::getId).collect(Collectors.toList())); + } + private ListenableFuture getNewLatestEntryFuture(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { ListenableFuture> future = findNewLatestEntryFuture(tenantId, entityId, query); return Futures.transformAsync(future, entryList -> { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java index cd3db69d70..da8c921487 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java @@ -36,4 +36,9 @@ public interface TsKvLatestRepository extends CrudRepository getKeysByTenantId(@Param("tenant_id") UUID tenantId); + @Query(value = "SELECT DISTINCT ts_kv_dictionary.key AS strKey FROM ts_kv_latest " + + "INNER JOIN ts_kv_dictionary ON ts_kv_latest.key = ts_kv_dictionary.key_id " + + "WHERE ts_kv_latest.entity_id IN :entityIds ORDER BY ts_kv_dictionary.key", nativeQuery = true) + List findAllKeysByEntityIds(@Param("entityIds") List entityIds); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java index 7160baf939..12e081d234 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/BaseTimeseriesService.java @@ -121,6 +121,11 @@ public class BaseTimeseriesService implements TimeseriesService { return timeseriesLatestDao.findAllKeysByDeviceProfileId(tenantId, deviceProfileId); } + @Override + public List findAllKeysByEntityIds(TenantId tenantId, List entityIds) { + return timeseriesLatestDao.findAllKeysByEntityIds(tenantId, entityIds); + } + @Override public ListenableFuture save(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) { validate(entityId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java index f086f913c0..2cb67f1260 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesLatestDao.java @@ -86,6 +86,11 @@ public class CassandraBaseTimeseriesLatestDao extends AbstractCassandraBaseTimes return Collections.emptyList(); } + @Override + public List findAllKeysByEntityIds(TenantId tenantId, List entityIds) { + return Collections.emptyList(); + } + @Override public ListenableFuture saveLatest(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry) { BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(getLatestStmt().bind()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java index 0b7156e03e..b2cd346277 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/TimeseriesLatestDao.java @@ -35,4 +35,6 @@ public interface TimeseriesLatestDao { ListenableFuture removeLatest(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query); List findAllKeysByDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId); + + List findAllKeysByEntityIds(TenantId tenantId, List entityIds); } From 0d9f36ead79ccaad8fa20528c130004bdb4574a7 Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Thu, 10 Dec 2020 18:08:12 +0200 Subject: [PATCH 09/32] Addition to ServicesMap --- ui-ngx/src/app/modules/home/models/services.map.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui-ngx/src/app/modules/home/models/services.map.ts b/ui-ngx/src/app/modules/home/models/services.map.ts index 8a8fbbce4e..75956db4e4 100644 --- a/ui-ngx/src/app/modules/home/models/services.map.ts +++ b/ui-ngx/src/app/modules/home/models/services.map.ts @@ -32,9 +32,11 @@ import { DashboardService } from '@core/http/dashboard.service'; import { UserService } from '@core/http/user.service'; import { AlarmService } from '@core/http/alarm.service'; import { Router } from '@angular/router'; +import { BroadcastService } from "@core/services/broadcast.service"; export const ServicesMap = new Map>( [ + ['broadcastService', BroadcastService], ['deviceService', DeviceService], ['alarmService', AlarmService], ['assetService', AssetService], From 235946691bfcb96fa0c10b689d6fc69b0c61bce5 Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Thu, 10 Dec 2020 18:20:51 +0200 Subject: [PATCH 10/32] Revert "Addition to ServicesMap" This reverts commit 0d9f36ead79ccaad8fa20528c130004bdb4574a7. --- ui-ngx/src/app/modules/home/models/services.map.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/models/services.map.ts b/ui-ngx/src/app/modules/home/models/services.map.ts index 75956db4e4..8a8fbbce4e 100644 --- a/ui-ngx/src/app/modules/home/models/services.map.ts +++ b/ui-ngx/src/app/modules/home/models/services.map.ts @@ -32,11 +32,9 @@ import { DashboardService } from '@core/http/dashboard.service'; import { UserService } from '@core/http/user.service'; import { AlarmService } from '@core/http/alarm.service'; import { Router } from '@angular/router'; -import { BroadcastService } from "@core/services/broadcast.service"; export const ServicesMap = new Map>( [ - ['broadcastService', BroadcastService], ['deviceService', DeviceService], ['alarmService', AlarmService], ['assetService', AssetService], From f63b4b1f7c3b843b391cb244307538400439e9e4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 15 Dec 2020 16:16:02 +0200 Subject: [PATCH 11/32] created findEntityTimeseriesAndAttributesKeysByQuery instead findEntityTimeseriesKeysByQuery and findEntityAttributesKeysByQuery --- .../controller/EntityQueryController.java | 45 ++---- .../query/DefaultEntityQueryService.java | 135 ++++++++++++++++++ .../service/query/EntityQueryService.java | 6 + 3 files changed, 151 insertions(+), 35 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index e58eee59a6..1fa802e18a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -16,14 +16,16 @@ package org.thingsboard.server.controller; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.async.DeferredResult; import org.thingsboard.server.common.data.exception.ThingsboardException; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; @@ -32,16 +34,9 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; -import org.thingsboard.server.dao.attributes.AttributesService; -import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.query.EntityQueryService; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; - @RestController @TbCoreComponent @RequestMapping("/api") @@ -50,13 +45,6 @@ public class EntityQueryController extends BaseController { @Autowired private EntityQueryService entityQueryService; - @Autowired - private AttributesService attributesService; - - @Autowired - private TimeseriesService timeseriesService; - - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST) @ResponseBody @@ -96,35 +84,22 @@ public class EntityQueryController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/find/keys/timeseries", method = RequestMethod.POST) @ResponseBody - public List findEntityTimeseriesKeysByQuery(@RequestBody EntityDataQuery query) throws ThingsboardException { + public DeferredResult findEntityTimeseriesAndAttributesKeysByQuery(@RequestBody EntityDataQuery query, + @RequestParam("timeseries") boolean isTimeseries, + @RequestParam("attributes") boolean isAttributes) throws ThingsboardException { TenantId tenantId = getTenantId(); - return getKeys(query, entityIds -> timeseriesService.findAllKeysByEntityIds(tenantId, entityIds)); - } - - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entitiesQuery/find/keys/attributes", method = RequestMethod.POST) - @ResponseBody - public List findEntityAttributesKeysByQuery(@RequestBody EntityDataQuery query) throws ThingsboardException { - TenantId tenantId = getTenantId(); - return getKeys(query, entityIds -> attributesService.findAllKeysByEntityIds(tenantId, entityIds.get(0).getEntityType(), entityIds)); - } - - private List getKeys(EntityDataQuery query, Function, List> function) throws ThingsboardException { checkNotNull(query); try { EntityDataPageLink pageLink = query.getPageLink(); if (pageLink.getPageSize() > 100) { pageLink.setPageSize(100); } - List ids = this.entityQueryService.findEntityDataByQuery(getCurrentUser(), query).getData().stream() - .map(EntityData::getEntityId) - .collect(Collectors.toList()); - if (ids.isEmpty()) { - return Collections.emptyList(); - } - return function.apply(ids); + DeferredResult response = new DeferredResult<>(); + entityQueryService.getKeysByQueryCallback(getCurrentUser(), tenantId, query, isTimeseries, isAttributes, response); + return response; } catch (Exception e) { throw handleException(e); } } + } diff --git a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java index b8ccad466d..337e2cdb07 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java @@ -15,11 +15,24 @@ */ package org.thingsboard.server.service.query; +import com.datastax.oss.driver.internal.core.util.CollectionsUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.checkerframework.checker.nullness.qual.Nullable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; @@ -31,12 +44,24 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder; import org.thingsboard.server.common.data.query.EntityKey; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.model.ModelConstants; +import org.thingsboard.server.dao.timeseries.TimeseriesService; +import org.thingsboard.server.dao.util.mapping.JacksonUtil; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.executors.DbCallbackExecutorService; +import org.thingsboard.server.service.security.AccessValidator; import org.thingsboard.server.service.security.model.SecurityUser; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; @Service @Slf4j @@ -52,6 +77,15 @@ public class DefaultEntityQueryService implements EntityQueryService { @Value("${server.ws.max_entities_per_alarm_subscription:1000}") private int maxEntitiesPerAlarmSubscription; + @Autowired + private DbCallbackExecutorService dbCallbackExecutor; + + @Autowired + private TimeseriesService timeseriesService; + + @Autowired + private AttributesService attributesService; + @Override public long countEntitiesByQuery(SecurityUser securityUser, EntityCountQuery query) { return entityService.countEntitiesByQuery(securityUser.getTenantId(), securityUser.getCustomerId(), query); @@ -89,6 +123,107 @@ public class DefaultEntityQueryService implements EntityQueryService { } } + @Override + public void getKeysByQueryCallback(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, + boolean isTimeseries, boolean isAttributes, DeferredResult response) { + if (!isAttributes && !isTimeseries) { + getEmptyResponseCallback(response); + return; + } + + List ids = this.findEntityDataByQuery(securityUser, query).getData().stream() + .map(EntityData::getEntityId) + .collect(Collectors.toList()); + if (ids.isEmpty()) { + getEmptyResponseCallback(response); + return; + } + + Set types = ids.stream().map(EntityId::getEntityType).collect(Collectors.toSet()); + ListenableFuture> timeseriesKeysFuture; + ListenableFuture> attributesKeysFuture; + + if (isTimeseries) { + timeseriesKeysFuture = dbCallbackExecutor.submit(() -> timeseriesService.findAllKeysByEntityIds(tenantId, ids)); + } else { + timeseriesKeysFuture = null; + } + + if (isAttributes) { + Map> typesMap = ids.stream().collect(Collectors.groupingBy(EntityId::getEntityType)); + List>> futures = new ArrayList<>(typesMap.size()); + typesMap.forEach((type, entityIds) -> futures.add(dbCallbackExecutor.submit(() -> attributesService.findAllKeysByEntityIds(tenantId, type, entityIds)))); + attributesKeysFuture = Futures.transform(Futures.allAsList(futures), lists -> { + if (CollectionUtils.isEmpty(lists)) { + return null; + } + + return lists.stream().flatMap(List::stream).distinct().sorted().collect(Collectors.toList()); + }, dbCallbackExecutor); + } else { + attributesKeysFuture = null; + } + + if (timeseriesKeysFuture != null && attributesKeysFuture != null) { + Futures.whenAllComplete(timeseriesKeysFuture, attributesKeysFuture).call(() -> { + try { + getResponseCallback(response, types, timeseriesKeysFuture.get(), attributesKeysFuture.get()); + } catch (Exception e) { + log.error("Failed to fetch timeseries and attributes keys!", e); + AccessValidator.handleError(e, response, HttpStatus.INTERNAL_SERVER_ERROR); + } + + return null; + }, dbCallbackExecutor); + } else if (timeseriesKeysFuture != null) { + Futures.addCallback(timeseriesKeysFuture, new FutureCallback>() { + @Override + public void onSuccess(@Nullable List keys) { + getResponseCallback(response, types, keys, null); + } + + @Override + public void onFailure(Throwable t) { + log.error("Failed to fetch timeseries keys!", t); + AccessValidator.handleError(t, response, HttpStatus.INTERNAL_SERVER_ERROR); + } + + }, dbCallbackExecutor); + } else { + Futures.addCallback(attributesKeysFuture, new FutureCallback>() { + @Override + public void onSuccess(@Nullable List keys) { + getResponseCallback(response, types, null, keys); + } + + @Override + public void onFailure(Throwable t) { + log.error("Failed to fetch attributes keys!", t); + AccessValidator.handleError(t, response, HttpStatus.INTERNAL_SERVER_ERROR); + } + }, dbCallbackExecutor); + } + } + + private void getResponseCallback(DeferredResult response, Set types, List timeseriesKeys, List attributesKeys) { + ObjectNode json = JacksonUtil.newObjectNode(); + addItemsToArrayNode(json.putArray("types"), types); + addItemsToArrayNode(json.putArray("timeseriesKeys"), timeseriesKeys); + addItemsToArrayNode(json.putArray("attributesKeys"), attributesKeys); + + response.setResult(new ResponseEntity(json, HttpStatus.OK)); + } + + private void getEmptyResponseCallback(DeferredResult response) { + getResponseCallback(response, null, null, null); + } + + private void addItemsToArrayNode(ArrayNode arrayNode, Collection collection) { + if (!CollectionUtils.isEmpty(collection)) { + collection.forEach(item -> arrayNode.add(item.toString())); + } + } + private EntityDataQuery buildEntityDataQuery(AlarmDataQuery query) { EntityDataSortOrder sortOrder = query.getPageLink().getSortOrder(); EntityDataSortOrder entitiesSortOrder; diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java index 15f7d86252..459fb144d1 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java @@ -15,6 +15,9 @@ */ package org.thingsboard.server.service.query; +import org.springframework.http.ResponseEntity; +import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; @@ -31,4 +34,7 @@ public interface EntityQueryService { PageData findAlarmDataByQuery(SecurityUser securityUser, AlarmDataQuery query); + void getKeysByQueryCallback(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, + boolean isTimeseries, boolean isAttributes, DeferredResult response); + } From dfb82bf28fb13ed7cf590eb37366487e7a6a80da Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 16 Dec 2020 11:05:35 +0200 Subject: [PATCH 12/32] findEntityTimeseriesAndAttributesKeysByQuery improvements --- .../controller/EntityQueryController.java | 10 +- .../query/DefaultEntityQueryService.java | 110 +++++++++--------- .../service/query/EntityQueryService.java | 4 +- 3 files changed, 61 insertions(+), 63 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 1fa802e18a..4325d6f2be 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -45,6 +45,8 @@ public class EntityQueryController extends BaseController { @Autowired private EntityQueryService entityQueryService; + private static final int MAX_PAGE_SIZE = 100; + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST) @ResponseBody @@ -91,12 +93,10 @@ public class EntityQueryController extends BaseController { checkNotNull(query); try { EntityDataPageLink pageLink = query.getPageLink(); - if (pageLink.getPageSize() > 100) { - pageLink.setPageSize(100); + if (pageLink.getPageSize() > MAX_PAGE_SIZE) { + pageLink.setPageSize(MAX_PAGE_SIZE); } - DeferredResult response = new DeferredResult<>(); - entityQueryService.getKeysByQueryCallback(getCurrentUser(), tenantId, query, isTimeseries, isAttributes, response); - return response; + return entityQueryService.getKeysByQuery(getCurrentUser(), tenantId, query, isTimeseries, isAttributes); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java index 337e2cdb07..d8be5040c9 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.query; -import com.datastax.oss.driver.internal.core.util.CollectionsUtils; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.FutureCallback; @@ -61,6 +60,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; @Service @@ -123,25 +123,38 @@ public class DefaultEntityQueryService implements EntityQueryService { } } + private EntityDataQuery buildEntityDataQuery(AlarmDataQuery query) { + EntityDataSortOrder sortOrder = query.getPageLink().getSortOrder(); + EntityDataSortOrder entitiesSortOrder; + if (sortOrder == null || sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { + entitiesSortOrder = new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, ModelConstants.CREATED_TIME_PROPERTY)); + } else { + entitiesSortOrder = sortOrder; + } + EntityDataPageLink edpl = new EntityDataPageLink(maxEntitiesPerAlarmSubscription, 0, null, entitiesSortOrder); + return new EntityDataQuery(query.getEntityFilter(), edpl, query.getEntityFields(), query.getLatestValues(), query.getKeyFilters()); + } + @Override - public void getKeysByQueryCallback(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, - boolean isTimeseries, boolean isAttributes, DeferredResult response) { + public DeferredResult getKeysByQuery(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, + boolean isTimeseries, boolean isAttributes) { + final DeferredResult response = new DeferredResult<>(); if (!isAttributes && !isTimeseries) { - getEmptyResponseCallback(response); - return; + replyWithEmptyResponse(response); + return response; } List ids = this.findEntityDataByQuery(securityUser, query).getData().stream() .map(EntityData::getEntityId) .collect(Collectors.toList()); if (ids.isEmpty()) { - getEmptyResponseCallback(response); - return; + replyWithEmptyResponse(response); + return response; } Set types = ids.stream().map(EntityId::getEntityType).collect(Collectors.toSet()); - ListenableFuture> timeseriesKeysFuture; - ListenableFuture> attributesKeysFuture; + final ListenableFuture> timeseriesKeysFuture; + final ListenableFuture> attributesKeysFuture; if (isTimeseries) { timeseriesKeysFuture = dbCallbackExecutor.submit(() -> timeseriesService.findAllKeysByEntityIds(tenantId, ids)); @@ -155,67 +168,49 @@ public class DefaultEntityQueryService implements EntityQueryService { typesMap.forEach((type, entityIds) -> futures.add(dbCallbackExecutor.submit(() -> attributesService.findAllKeysByEntityIds(tenantId, type, entityIds)))); attributesKeysFuture = Futures.transform(Futures.allAsList(futures), lists -> { if (CollectionUtils.isEmpty(lists)) { - return null; + return Collections.emptyList(); } - return lists.stream().flatMap(List::stream).distinct().sorted().collect(Collectors.toList()); }, dbCallbackExecutor); } else { attributesKeysFuture = null; } - if (timeseriesKeysFuture != null && attributesKeysFuture != null) { - Futures.whenAllComplete(timeseriesKeysFuture, attributesKeysFuture).call(() -> { + if (isTimeseries && isAttributes) { + Futures.whenAllComplete(timeseriesKeysFuture, attributesKeysFuture).run(() -> { try { - getResponseCallback(response, types, timeseriesKeysFuture.get(), attributesKeysFuture.get()); + replyWithResponse(response, types, timeseriesKeysFuture.get(), attributesKeysFuture.get()); } catch (Exception e) { log.error("Failed to fetch timeseries and attributes keys!", e); AccessValidator.handleError(e, response, HttpStatus.INTERNAL_SERVER_ERROR); } - - return null; - }, dbCallbackExecutor); - } else if (timeseriesKeysFuture != null) { - Futures.addCallback(timeseriesKeysFuture, new FutureCallback>() { - @Override - public void onSuccess(@Nullable List keys) { - getResponseCallback(response, types, keys, null); - } - - @Override - public void onFailure(Throwable t) { - log.error("Failed to fetch timeseries keys!", t); - AccessValidator.handleError(t, response, HttpStatus.INTERNAL_SERVER_ERROR); - } - }, dbCallbackExecutor); + } else if (isTimeseries) { + addCallback(timeseriesKeysFuture, keys -> replyWithResponse(response, types, keys, null), + error -> { + log.error("Failed to fetch timeseries keys!", error); + AccessValidator.handleError(error, response, HttpStatus.INTERNAL_SERVER_ERROR); + }); } else { - Futures.addCallback(attributesKeysFuture, new FutureCallback>() { - @Override - public void onSuccess(@Nullable List keys) { - getResponseCallback(response, types, null, keys); - } - - @Override - public void onFailure(Throwable t) { - log.error("Failed to fetch attributes keys!", t); - AccessValidator.handleError(t, response, HttpStatus.INTERNAL_SERVER_ERROR); - } - }, dbCallbackExecutor); + addCallback(attributesKeysFuture, keys -> replyWithResponse(response, types, null, keys), + error -> { + log.error("Failed to fetch attributes keys!", error); + AccessValidator.handleError(error, response, HttpStatus.INTERNAL_SERVER_ERROR); + }); } + return response; } - private void getResponseCallback(DeferredResult response, Set types, List timeseriesKeys, List attributesKeys) { + private void replyWithResponse(DeferredResult response, Set types, List timeseriesKeys, List attributesKeys) { ObjectNode json = JacksonUtil.newObjectNode(); addItemsToArrayNode(json.putArray("types"), types); addItemsToArrayNode(json.putArray("timeseriesKeys"), timeseriesKeys); addItemsToArrayNode(json.putArray("attributesKeys"), attributesKeys); - response.setResult(new ResponseEntity(json, HttpStatus.OK)); } - private void getEmptyResponseCallback(DeferredResult response) { - getResponseCallback(response, null, null, null); + private void replyWithEmptyResponse(DeferredResult response) { + replyWithResponse(response, Collections.emptySet(), Collections.emptyList(), Collections.emptyList()); } private void addItemsToArrayNode(ArrayNode arrayNode, Collection collection) { @@ -224,15 +219,18 @@ public class DefaultEntityQueryService implements EntityQueryService { } } - private EntityDataQuery buildEntityDataQuery(AlarmDataQuery query) { - EntityDataSortOrder sortOrder = query.getPageLink().getSortOrder(); - EntityDataSortOrder entitiesSortOrder; - if (sortOrder == null || sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { - entitiesSortOrder = new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, ModelConstants.CREATED_TIME_PROPERTY)); - } else { - entitiesSortOrder = sortOrder; - } - EntityDataPageLink edpl = new EntityDataPageLink(maxEntitiesPerAlarmSubscription, 0, null, entitiesSortOrder); - return new EntityDataQuery(query.getEntityFilter(), edpl, query.getEntityFields(), query.getLatestValues(), query.getKeyFilters()); + private void addCallback(ListenableFuture> future, Consumer> success, Consumer error) { + Futures.addCallback(future, new FutureCallback>() { + @Override + public void onSuccess(@Nullable List keys) { + success.accept(keys); + } + + @Override + public void onFailure(Throwable t) { + error.accept(t); + } + }, dbCallbackExecutor); } + } diff --git a/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java index 459fb144d1..763453c815 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/EntityQueryService.java @@ -34,7 +34,7 @@ public interface EntityQueryService { PageData findAlarmDataByQuery(SecurityUser securityUser, AlarmDataQuery query); - void getKeysByQueryCallback(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, - boolean isTimeseries, boolean isAttributes, DeferredResult response); + DeferredResult getKeysByQuery(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, + boolean isTimeseries, boolean isAttributes); } From 91bb1ed504af2c413863c9b95c4d5d1bf3c3563f Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 16 Dec 2020 11:21:28 +0200 Subject: [PATCH 13/32] refactored findEntityTimeseriesAndAttributesKeysByQuery --- .../thingsboard/server/controller/EntityQueryController.java | 2 +- .../server/service/query/DefaultEntityQueryService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java index 4325d6f2be..2df8298d23 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityQueryController.java @@ -84,7 +84,7 @@ public class EntityQueryController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/entitiesQuery/find/keys/timeseries", method = RequestMethod.POST) + @RequestMapping(value = "/entitiesQuery/find/keys", method = RequestMethod.POST) @ResponseBody public DeferredResult findEntityTimeseriesAndAttributesKeysByQuery(@RequestBody EntityDataQuery query, @RequestParam("timeseries") boolean isTimeseries, diff --git a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java index d8be5040c9..74c1b844ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java @@ -203,7 +203,7 @@ public class DefaultEntityQueryService implements EntityQueryService { private void replyWithResponse(DeferredResult response, Set types, List timeseriesKeys, List attributesKeys) { ObjectNode json = JacksonUtil.newObjectNode(); - addItemsToArrayNode(json.putArray("types"), types); + addItemsToArrayNode(json.putArray("entityTypes"), types); addItemsToArrayNode(json.putArray("timeseriesKeys"), timeseriesKeys); addItemsToArrayNode(json.putArray("attributesKeys"), attributesKeys); response.setResult(new ResponseEntity(json, HttpStatus.OK)); From 96ff9ddeddaa37273b2065906ca0373b66d2109f Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Wed, 16 Dec 2020 17:36:08 +0200 Subject: [PATCH 14/32] Fixes after review --- .../components/widget/lib/maps/leaflet-map.ts | 2 +- .../trip-animation/trip-animation.component.html | 2 +- .../trip-animation/trip-animation.component.scss | 5 ++++- .../trip-animation/trip-animation.component.ts | 15 +++++++-------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index b74323a00a..43c954aeed 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -629,7 +629,7 @@ export default abstract class LeafletMap { } this.points.addLayer(point); }); - if(i === 0) { + if(i === (pointsData.length - 1)) { this.map.addLayer(this.points); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html index be82969986..8d0998f063 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html @@ -32,7 +32,7 @@ [ngStyle]="{'background-color': settings.tooltipColor, 'opacity': settings.tooltipOpacity, 'color': settings.tooltipFontColor}">
+ ngStyle="{'padding': '10px 0'}">
diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.scss b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.scss index cdb28f8a27..b1a49da9fb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.scss @@ -73,6 +73,9 @@ } .trip-animation-tooltip { + display: flex; + overflow: auto; + max-height: 90%; position: absolute; top: 30px; right: 0; @@ -86,4 +89,4 @@ } } } -} \ No newline at end of file +} diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index a392481259..4477d855a2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -141,7 +141,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy timeUpdated(time: number) { this.currentTime = time; - let currentPosition = this.interpolatedTimeData + const currentPosition = this.interpolatedTimeData .map(dataSource => dataSource[time]) for(let j = 0; j < this.interpolatedTimeData.length; j++) { if (isUndefined(currentPosition[j])) { @@ -175,7 +175,7 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.mapWidget.map.updatePolygons(this.interpolatedTimeData); } if (this.settings.showPoints) { - this.mapWidget.map.updatePoints(formattedInterpolatedTimeData, this.calcTooltip); + this.mapWidget.map.updatePoints(formattedInterpolatedTimeData.map(ds => _.union(ds)), this.calcTooltip); } this.mapWidget.map.updateMarkers(currentPosition, true, (trip) => { this.activeTrip = trip; @@ -235,20 +235,19 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy this.mainTooltips.push(this.sanitizer.sanitize(SecurityContext.HTML, tooltipText)); } this.cd.detectChanges(); - this.activeTrip = point; } return tooltipText; } calcLabel(formattedDataArr: FormattedData[]) { - this.label = ''; + let labelToSet = ''; for (let formattedData of formattedDataArr) { - const data = formattedData; const labelText: string = this.settings.useLabelFunction ? - safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; - const label = (parseWithTranslation.parseTemplate(labelText, data, true)); - this.label = this.label.length ? this.label + ',' + label : label; + safeExecute(this.settings.labelFunction, [formattedData, this.historicalData, formattedData.dsIndex]) : this.settings.label; + const label = (parseWithTranslation.parseTemplate(labelText, formattedData, true)); + labelToSet = labelToSet.length ? labelToSet + ',' + label : label; } + this.label = labelToSet; } interpolateArray(originData: FormattedData[]) { From 65027b9c17f13ebcb9d11d317013bacf28bfdda1 Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Wed, 16 Dec 2020 18:42:55 +0200 Subject: [PATCH 15/32] Additions to fixes after review --- .../widget/trip-animation/trip-animation.component.html | 2 +- .../widget/trip-animation/trip-animation.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html index 8d0998f063..6264231b68 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html @@ -32,7 +32,7 @@ [ngStyle]="{'background-color': settings.tooltipColor, 'opacity': settings.tooltipOpacity, 'color': settings.tooltipFontColor}">
+ style="padding: 10px 0">
diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 4477d855a2..5872c9023e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -234,8 +234,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy if(isMainTooltip) { this.mainTooltips.push(this.sanitizer.sanitize(SecurityContext.HTML, tooltipText)); } - this.cd.detectChanges(); } + this.cd.detectChanges(); return tooltipText; } From 3aa97eec06b2fa94e56ce4b66dff542a73ee9804 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 17 Dec 2020 13:32:03 +0200 Subject: [PATCH 16/32] UI: Improvement autocomplete data keys in datasource widget --- .../query/DefaultEntityQueryService.java | 4 +- ui-ngx/src/app/core/http/entity.service.ts | 74 ++++++++++++++++++- .../widget/data-key-config.component.ts | 34 ++++++--- .../widget/data-keys.component.models.ts | 2 +- .../components/widget/data-keys.component.ts | 37 +++++++--- .../widget/widget-config.component.ts | 62 +++------------- ui-ngx/src/app/shared/models/entity.models.ts | 6 ++ 7 files changed, 139 insertions(+), 80 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java index 74c1b844ef..c9726693bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java @@ -204,8 +204,8 @@ public class DefaultEntityQueryService implements EntityQueryService { private void replyWithResponse(DeferredResult response, Set types, List timeseriesKeys, List attributesKeys) { ObjectNode json = JacksonUtil.newObjectNode(); addItemsToArrayNode(json.putArray("entityTypes"), types); - addItemsToArrayNode(json.putArray("timeseriesKeys"), timeseriesKeys); - addItemsToArrayNode(json.putArray("attributesKeys"), attributesKeys); + addItemsToArrayNode(json.putArray("timeseries"), timeseriesKeys); + addItemsToArrayNode(json.putArray("attribute"), attributesKeys); response.setResult(new ResponseEntity(json, HttpStatus.OK)); } diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 9263838ffa..fee7fb0094 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -41,10 +41,16 @@ import { AttributeScope, DataKeyType } from '@shared/models/telemetry/telemetry. import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-utils'; import { RuleChainService } from '@core/http/rule-chain.service'; import { AliasInfo, StateParams, SubscriptionInfo } from '@core/api/widget-api.models'; -import { Datasource, DatasourceType, KeyInfo } from '@app/shared/models/widget.models'; +import { DataKey, Datasource, DatasourceType, KeyInfo } from '@app/shared/models/widget.models'; import { UtilsService } from '@core/services/utils.service'; import { AliasFilterType, EntityAlias, EntityAliasFilter, EntityAliasFilterResult } from '@shared/models/alias.models'; -import { entityFields, EntityInfo, ImportEntitiesResultInfo, ImportEntityData } from '@shared/models/entity.models'; +import { + EntitiesKeysByQuery, + entityFields, + EntityInfo, + ImportEntitiesResultInfo, + ImportEntityData +} from '@shared/models/entity.models'; import { EntityRelationService } from '@core/http/entity-relation.service'; import { deepClone, isDefined, isDefinedAndNotNull } from '@core/utils'; import { Asset } from '@shared/models/asset.models'; @@ -376,6 +382,13 @@ export class EntityService { return this.http.post>('/api/entitiesQuery/find', query, defaultHttpOptionsFromConfig(config)); } + public findEntityKeysByQuery(query: EntityDataQuery, attributes = true, timeseries = true, + config?: RequestConfig): Observable { + return this.http.post( + `/api/entitiesQuery/find/keys?attributes=${attributes}×eries=${timeseries}`, + query, defaultHttpOptionsFromConfig(config)); + } + public findAlarmDataByQuery(query: AlarmDataQuery, config?: RequestConfig): Observable> { return this.http.post>('/api/alarmsQuery/find', query, defaultHttpOptionsFromConfig(config)); } @@ -595,7 +608,7 @@ export class EntityService { return entityTypes; } - private getEntityFieldKeys(entityType: EntityType, searchText: string): Array { + private getEntityFieldKeys(entityType: EntityType, searchText: string = ''): Array { const entityFieldKeys: string[] = [entityFields.createdTime.keyName]; const query = searchText.toLowerCase(); switch (entityType) { @@ -637,7 +650,7 @@ export class EntityService { return query ? entityFieldKeys.filter((entityField) => entityField.toLowerCase().indexOf(query) === 0) : entityFieldKeys; } - private getAlarmKeys(searchText: string): Array { + private getAlarmKeys(searchText: string = ''): Array { const alarmKeys: string[] = Object.keys(alarmFields); const query = searchText.toLowerCase(); return query ? alarmKeys.filter((alarmField) => alarmField.toLowerCase().indexOf(query) === 0) : alarmKeys; @@ -672,6 +685,59 @@ export class EntityService { ); } + public getEntityKeysByEntityFilter(filter: EntityFilter, types: DataKeyType[], config?: RequestConfig): Observable> { + if (!types.length) { + return of([]); + } + let entitiesKeysByQuery$: Observable; + if (filter !== null && types.some(type => [DataKeyType.timeseries, DataKeyType.attribute].includes(type))) { + const dataQuery = { + entityFilter: filter, + pageLink: createDefaultEntityDataPageLink(100), + }; + entitiesKeysByQuery$ = this.findEntityKeysByQuery(dataQuery, types.includes(DataKeyType.attribute), + types.includes(DataKeyType.timeseries), config); + } else { + entitiesKeysByQuery$ = of({ + attribute: [], + timeseries: [], + entityTypes: [], + }); + } + return entitiesKeysByQuery$.pipe( + map((entitiesKeys) => { + const dataKeys: Array = []; + types.forEach(type => { + let keys: Array; + switch (type) { + case DataKeyType.entityField: + if (entitiesKeys.entityTypes.length) { + const entitiesFields = []; + entitiesKeys.entityTypes.forEach(entityType => entitiesFields.push(...this.getEntityFieldKeys(entityType))); + keys = Array.from(new Set(entitiesFields)); + } + break; + case DataKeyType.alarm: + keys = this.getAlarmKeys(); + break; + case DataKeyType.attribute: + case DataKeyType.timeseries: + if (entitiesKeys[type].length) { + keys = entitiesKeys[type]; + } + break; + } + if (keys) { + dataKeys.push(...keys.map(key => { + return {name: key, type}; + })); + } + }); + return dataKeys; + }) + ); + } + public createDatasourcesFromSubscriptionsInfo(subscriptionsInfo: Array): Array { const datasources = subscriptionsInfo.map(subscriptionInfo => this.createDatasourceFromSubscriptionInfo(subscriptionInfo)); this.utils.generateColors(datasources); diff --git a/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.ts index fde4b1a32f..a4187d9b6c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/data-key-config.component.ts @@ -36,7 +36,7 @@ import { EntityService } from '@core/http/entity.service'; import { DataKeysCallbacks } from '@home/components/widget/data-keys.component.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { Observable, of } from 'rxjs'; -import { map, mergeMap, tap } from 'rxjs/operators'; +import { map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators'; import { alarmFields } from '@shared/models/alarm.models'; import { JsFuncComponent } from '@shared/components/js-func.component'; import { JsonFormComponentData } from '@shared/components/json-form/json-form-component.models'; @@ -95,6 +95,7 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con filteredKeys: Observable>; private latestKeySearchResult: Array = null; + private fetchObservable$: Observable> = null; keySearchText = ''; @@ -205,31 +206,42 @@ export class DataKeyConfigComponent extends PageComponent implements OnInit, Con } private fetchKeys(searchText?: string): Observable> { - if (this.latestKeySearchResult === null || this.keySearchText !== searchText) { + if (this.keySearchText !== searchText || this.latestKeySearchResult === null) { this.keySearchText = searchText; - let fetchObservable: Observable> = null; + const dataKeyFilter = this.createKeyFilter(this.keySearchText); + return this.getKeys().pipe( + map(name => name.filter(dataKeyFilter)), + tap(res => this.latestKeySearchResult = res) + ); + } + return of(this.latestKeySearchResult); + } + + private getKeys() { + if (this.fetchObservable$ === null) { + let fetchObservable: Observable>; if (this.modelValue.type === DataKeyType.alarm) { - const dataKeyFilter = this.createDataKeyFilter(this.keySearchText); - fetchObservable = of(this.alarmKeys.filter(dataKeyFilter)); + fetchObservable = of(this.alarmKeys); } else { if (this.entityAliasId) { const dataKeyTypes = [this.modelValue.type]; - fetchObservable = this.callbacks.fetchEntityKeys(this.entityAliasId, this.keySearchText, dataKeyTypes); + fetchObservable = this.callbacks.fetchEntityKeys(this.entityAliasId, dataKeyTypes); } else { fetchObservable = of([]); } } - return fetchObservable.pipe( + this.fetchObservable$ = fetchObservable.pipe( map((dataKeys) => dataKeys.map((dataKey) => dataKey.name)), - tap(res => this.latestKeySearchResult = res) + publishReplay(1), + refCount() ); } - return of(this.latestKeySearchResult); + return this.fetchObservable$; } - private createDataKeyFilter(query: string): (key: DataKey) => boolean { + private createKeyFilter(query: string): (key: string) => boolean { const lowercaseQuery = query.toLowerCase(); - return key => key.name.toLowerCase().indexOf(lowercaseQuery) === 0; + return key => key.toLowerCase().startsWith(lowercaseQuery); } public validateOnSubmit() { diff --git a/ui-ngx/src/app/modules/home/components/widget/data-keys.component.models.ts b/ui-ngx/src/app/modules/home/components/widget/data-keys.component.models.ts index 452e390faa..f5a937a4be 100644 --- a/ui-ngx/src/app/modules/home/components/widget/data-keys.component.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/data-keys.component.models.ts @@ -20,5 +20,5 @@ import { Observable } from 'rxjs'; export interface DataKeysCallbacks { generateDataKey: (chip: any, type: DataKeyType) => DataKey; - fetchEntityKeys: (entityAliasId: string, query: string, types: Array) => Observable>; + fetchEntityKeys: (entityAliasId: string, types: Array) => Observable>; } diff --git a/ui-ngx/src/app/modules/home/components/widget/data-keys.component.ts b/ui-ngx/src/app/modules/home/components/widget/data-keys.component.ts index 22c9663be8..e31ad036c9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/data-keys.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/data-keys.component.ts @@ -38,7 +38,7 @@ import { Validators } from '@angular/forms'; import { Observable, of } from 'rxjs'; -import { filter, map, mergeMap, share, tap } from 'rxjs/operators'; +import { filter, map, mergeMap, publishReplay, refCount, share, tap } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { AppState } from '@app/core/core.state'; import { TranslateService } from '@ngx-translate/core'; @@ -142,6 +142,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, AfterVie searchText = ''; private latestSearchTextResult: Array = null; + private fetchObservable$: Observable> = null; private dirty = false; @@ -260,6 +261,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, AfterVie if (!change.firstChange && change.currentValue !== change.previousValue) { if (propName === 'entityAliasId') { this.searchText = ''; + this.fetchObservable$ = null; this.latestSearchTextResult = null; this.dirty = true; } else if (['widgetType', 'datasourceType'].includes(propName)) { @@ -405,14 +407,24 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, AfterVie return key ? key.name : undefined; } - fetchKeys(searchText?: string): Observable> { - if (this.latestSearchTextResult === null || this.searchText !== searchText) { + private fetchKeys(searchText?: string): Observable> { + if (this.searchText !== searchText || this.latestSearchTextResult === null) { this.searchText = searchText; - let fetchObservable: Observable> = null; + const dataKeyFilter = this.createDataKeyFilter(this.searchText); + return this.getKeys().pipe( + map(name => name.filter(dataKeyFilter)), + tap(res => this.latestSearchTextResult = res) + ); + } + return of(this.latestSearchTextResult); + } + + private getKeys(): Observable> { + if (this.fetchObservable$ === null) { + let fetchObservable: Observable>; if (this.datasourceType === DatasourceType.function) { - const dataKeyFilter = this.createDataKeyFilter(this.searchText); const targetKeysList = this.widgetType === widgetType.alarm ? this.alarmKeys : this.functionTypeKeys; - fetchObservable = of(targetKeysList.filter(dataKeyFilter)); + fetchObservable = of(targetKeysList); } else { if (this.entityAliasId) { const dataKeyTypes = [DataKeyType.timeseries]; @@ -420,24 +432,25 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, AfterVie dataKeyTypes.push(DataKeyType.attribute); dataKeyTypes.push(DataKeyType.entityField); if (this.widgetType === widgetType.alarm) { - dataKeyTypes.push(DataKeyType.alarm); + dataKeyTypes.push(DataKeyType.alarm); } } - fetchObservable = this.callbacks.fetchEntityKeys(this.entityAliasId, this.searchText, dataKeyTypes); + fetchObservable = this.callbacks.fetchEntityKeys(this.entityAliasId, dataKeyTypes); } else { fetchObservable = of([]); } } - return fetchObservable.pipe( - tap(res => this.latestSearchTextResult = res) + this.fetchObservable$ = fetchObservable.pipe( + publishReplay(1), + refCount() ); } - return of(this.latestSearchTextResult); + return this.fetchObservable$; } private createDataKeyFilter(query: string): (key: DataKey) => boolean { const lowercaseQuery = query.toLowerCase(); - return key => key.name.toLowerCase().indexOf(lowercaseQuery) === 0; + return key => key.name.toLowerCase().startsWith(lowercaseQuery); } textIsNotEmpty(text: string): boolean { diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts index ba8cdaf5d2..b1984f997a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-config.component.ts @@ -54,13 +54,13 @@ import { UtilsService } from '@core/services/utils.service'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { TranslateService } from '@ngx-translate/core'; import { EntityType } from '@shared/models/entity-type.models'; -import { forkJoin, Observable, of, Subscription } from 'rxjs'; +import { Observable, of, Subscription } from 'rxjs'; import { WidgetConfigCallbacks } from '@home/components/widget/widget-config.component.models'; import { EntityAliasDialogComponent, EntityAliasDialogData } from '@home/components/alias/entity-alias-dialog.component'; -import { catchError, map, mergeMap, tap } from 'rxjs/operators'; +import { catchError, mergeMap, tap } from 'rxjs/operators'; import { MatDialog } from '@angular/material/dialog'; import { EntityService } from '@core/http/entity.service'; import { JsonFormComponentData } from '@shared/components/json-form/json-form-component.models'; @@ -792,54 +792,16 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont ); } - private fetchEntityKeys(entityAliasId: string, query: string, dataKeyTypes: Array): Observable> { - return this.aliasController.resolveSingleEntityInfo(entityAliasId).pipe( - mergeMap((entity) => { - if (entity) { - const fetchEntityTasks: Array>> = []; - for (const dataKeyType of dataKeyTypes) { - fetchEntityTasks.push( - this.entityService.getEntityKeys( - {entityType: entity.entityType, id: entity.id}, - query, - dataKeyType, - {ignoreLoading: true, ignoreErrors: true} - ).pipe( - map((keys) => { - const dataKeys: Array = []; - for (const key of keys) { - dataKeys.push({name: key, type: dataKeyType}); - } - return dataKeys; - } - ), - catchError(() => of([])) - )); - } - return forkJoin(fetchEntityTasks).pipe( - map(arrayOfDataKeys => { - const result = new Array(); - arrayOfDataKeys.forEach((dataKeyArray) => { - result.push(...dataKeyArray); - }); - return result; - } - )); - } else if (dataKeyTypes.includes(DataKeyType.alarm)) { - return this.entityService.getEntityKeys(null, query, DataKeyType.alarm).pipe( - map((keys) => { - const dataKeys: Array = []; - for (const key of keys) { - dataKeys.push({name: key, type: DataKeyType.alarm}); - } - return dataKeys; - } - ), - catchError(() => of([])) - ); - } else { - return of([]); - } + private fetchEntityKeys(entityAliasId: string, dataKeyTypes: Array): Observable> { + return this.aliasController.getAliasInfo(entityAliasId).pipe( + mergeMap((aliasInfo) => { + return this.entityService.getEntityKeysByEntityFilter( + aliasInfo.entityFilter, + dataKeyTypes, + {ignoreLoading: true, ignoreErrors: true} + ).pipe( + catchError(() => of([])) + ); }), catchError(() => of([] as Array)) ); diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 8f1d4f417e..300de484c1 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -64,6 +64,12 @@ export interface EntityField { time?: boolean; } +export interface EntitiesKeysByQuery { + attribute: Array; + timeseries: Array; + entityTypes: EntityType[]; +} + export const entityFields: {[fieldName: string]: EntityField} = { createdTime: { keyName: 'createdTime', From be84a0fc202d8ca138aed48bfd14c8c226e996c0 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 21 Dec 2020 16:42:45 +0200 Subject: [PATCH 17/32] Version set to 2.5.6-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/package-lock.json | 14 +++---- msa/js-executor/package.json | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/web-ui/package-lock.json | 2 +- msa/web-ui/package.json | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 +- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- ui/package-lock.json | 43 ++++++---------------- ui/package.json | 2 +- ui/pom.xml | 2 +- 43 files changed, 61 insertions(+), 80 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 1783d9f4c5..02cdfc36e7 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index ee626dac6f..66a9883a14 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index 879e479c3a..38528d8511 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 8b43e5c8b1..9b5584744f 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 62802d141c..c956e6469c 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index e0a3865e08..9421aed1b4 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index b302313baf..eae5af22e1 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 8ccf34961c..5c9129a919 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index a237662b0d..3c45a7000f 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 715cb3d169..9b60bfb470 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index e3579876e4..26008b6d4a 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index e40f3e4009..7531c614e5 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 739aa2b068..e04440b23e 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index fceed3ee0e..603e365243 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 8c1cd17bf4..39475c6329 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index d24f38bc36..226dfa913d 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/package-lock.json b/msa/js-executor/package-lock.json index 80023b25cc..5255cd79d3 100644 --- a/msa/js-executor/package-lock.json +++ b/msa/js-executor/package-lock.json @@ -1,6 +1,6 @@ { "name": "thingsboard-js-executor", - "version": "2.5.5", + "version": "2.5.6", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1826,7 +1826,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -1936,7 +1936,7 @@ }, "got": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { @@ -2275,7 +2275,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, @@ -2917,7 +2917,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -3474,7 +3474,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -3832,7 +3832,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 405d582f04..d56a01bd0b 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "2.5.5", + "version": "2.5.6", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 60ccd9d5bb..c379662359 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index c627dca51a..a7cac82052 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 944521f87e..2213bccd20 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index 349cc36337..ef2d3eaa16 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index 3e956736a1..919ace3232 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index bc8ccc3f1f..7d492eb851 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index b2bc3ff8d9..dc3b23bd26 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index d00683c492..d8064680b8 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/package-lock.json b/msa/web-ui/package-lock.json index b7785ef48b..adcd46ec7b 100644 --- a/msa/web-ui/package-lock.json +++ b/msa/web-ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "thingsboard-web-ui", - "version": "2.5.3", + "version": "2.5.6", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 2eec7556f9..3d182abfc7 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "2.5.5", + "version": "2.5.6", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 660920835b..697363cc1b 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 58cbcf4e6a..266a9bb235 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard netty-mqtt - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 6974497db2..2030a69179 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 061efa390b..4dafeaabae 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 00d445cc3c..98d7054f8c 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 2c1e323165..a9b25c4f88 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 5bb14db250..23faf7707e 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 10bfa3cc5b..763e4a98cc 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index eeea5a378a..9c53882520 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 7540b78507..6255717009 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index 6f4edd87b1..b5294309df 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 59b5b2470b..ca50c573d2 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard transport diff --git a/ui/package-lock.json b/ui/package-lock.json index 709137d524..185fcc140f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "2.5.3", + "version": "2.5.6", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -5238,8 +5238,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5260,14 +5259,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5282,20 +5279,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5412,8 +5406,7 @@ "inherits": { "version": "2.0.4", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5425,7 +5418,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5440,7 +5432,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5448,14 +5439,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.9.0", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5474,7 +5463,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5564,8 +5552,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5577,7 +5564,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5663,8 +5649,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -5700,7 +5685,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5720,7 +5704,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5764,14 +5747,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, diff --git a/ui/package.json b/ui/package.json index cbc4b8c6af..a872387289 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard", "private": true, - "version": "2.5.5", + "version": "2.5.6", "description": "ThingsBoard UI", "licenses": [ { diff --git a/ui/pom.xml b/ui/pom.xml index b27f492c97..f277bb09d8 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.5-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard org.thingsboard From 0de5868bc5886e3c2acc2cc1c56dba8dd0fa9a7b Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 21 Dec 2020 12:36:35 +0200 Subject: [PATCH 18/32] added Caffeine cache for Cassandra ts partitions saving --- .../src/main/resources/thingsboard.yml | 3 +- .../CassandraBaseTimeseriesDao.java | 46 ++++++ .../CassandraPartitionCacheKey.java | 30 ++++ .../CassandraTsPartitionsCache.java | 42 ++++++ .../nosql/CassandraPartitionsCacheTest.java | 132 ++++++++++++++++++ .../test/resources/cassandra-test.properties | 2 + 6 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 4cefe63e54..bf5ca8023d 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -223,8 +223,9 @@ cassandra: read_consistency_level: "${CASSANDRA_READ_CONSISTENCY_LEVEL:ONE}" write_consistency_level: "${CASSANDRA_WRITE_CONSISTENCY_LEVEL:ONE}" default_fetch_size: "${CASSANDRA_DEFAULT_FETCH_SIZE:2000}" - # Specify partitioning size for timestamp key-value storage. Example: MINUTES, HOURS, DAYS, MONTHS,INDEFINITE + # Specify partitioning size for timestamp key-value storage. Example: MINUTES, HOURS, DAYS, MONTHS, INDEFINITE ts_key_value_partitioning: "${TS_KV_PARTITIONING:MONTHS}" + ts_key_value_partitions_max_cache_size: "${TS_KV_PARTITIONS_MAX_CACHE_SIZE:100000}" ts_key_value_ttl: "${TS_KV_TTL:0}" events_ttl: "${TS_EVENTS_TTL:0}" # Specify TTL of debug log in seconds. The current value corresponds to one week diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index b96462e350..d39c6c5afb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -29,6 +29,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.SettableFuture; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -66,6 +67,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -88,12 +90,17 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem public static final String DESC_ORDER = "DESC"; private static List FIXED_PARTITION = Arrays.asList(new Long[]{0L}); + private CassandraTsPartitionsCache cassandraTsPartitionsCache; + @Autowired private Environment environment; @Value("${cassandra.query.ts_key_value_partitioning}") private String partitioning; + @Value("${cassandra.query.ts_key_value_partitions_max_cache_size}") + private long partitionsCacheSize; + @Value("${cassandra.query.ts_key_value_ttl}") private long systemTtl; @@ -126,6 +133,9 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem Optional partition = NoSqlTsPartitionDate.parse(partitioning); if (partition.isPresent()) { tsFormat = partition.get(); + if (!isFixedPartitioning() && partitionsCacheSize > 0) { + cassandraTsPartitionsCache = new CassandraTsPartitionsCache(partitionsCacheSize); + } } else { log.warn("Incorrect configuration of partitioning {}", partitioning); throw new RuntimeException("Failed to parse partitioning property: " + partitioning + "!"); @@ -390,6 +400,42 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem } ttl = computeTtl(ttl); long partition = toPartitionTs(tsKvEntryTs); + if (cassandraTsPartitionsCache == null) { + return doSavePartition(tenantId, entityId, key, ttl, partition); + } else { + CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); + CompletableFuture hasFuture = cassandraTsPartitionsCache.has(partitionSearchKey); + SettableFuture listenableFuture = SettableFuture.create(); + if (hasFuture == null) { + return processDoSavePartition(tenantId, entityId, key, partition, partitionSearchKey, ttl); + } else { + hasFuture.whenComplete((result, throwable) -> { + if (throwable != null) { + listenableFuture.setException(throwable); + } else { + listenableFuture.set(result); + } + }); + long finalTtl = ttl; + return Futures.transformAsync(listenableFuture, result -> { + if (result) { + return Futures.immediateFuture(null); + } else { + return processDoSavePartition(tenantId, entityId, key, partition, partitionSearchKey, finalTtl); + } + }, readResultsProcessingExecutor); + } + } + } + + private ListenableFuture processDoSavePartition(TenantId tenantId, EntityId entityId, String key, long partition, CassandraPartitionCacheKey partitionSearchKey, long ttl) { + return Futures.transformAsync(doSavePartition(tenantId, entityId, key, ttl, partition), input -> { + cassandraTsPartitionsCache.put(partitionSearchKey); + return Futures.immediateFuture(input); + }, readResultsProcessingExecutor); + } + + private ListenableFuture doSavePartition(TenantId tenantId, EntityId entityId, String key, long ttl, long partition) { log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); BoundStatement stmt = (ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt()).bind(); stmt = stmt.setString(0, entityId.getEntityType().name()) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java new file mode 100644 index 0000000000..791ce84113 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed 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.thingsboard.server.dao.timeseries; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; + +@Data +@AllArgsConstructor +public class CassandraPartitionCacheKey { + + private EntityId entityId; + private String key; + private long partition; + +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java new file mode 100644 index 0000000000..b467b5446f --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed 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.thingsboard.server.dao.timeseries; + +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; + +import java.util.concurrent.CompletableFuture; + +public class CassandraTsPartitionsCache { + + private AsyncLoadingCache partitionsCache; + + public CassandraTsPartitionsCache(long maxCacheSize) { + this.partitionsCache = Caffeine.newBuilder() + .maximumSize(maxCacheSize) + .buildAsync(key -> { + throw new IllegalStateException("'get' methods calls are not supported!"); + }); + } + + public CompletableFuture has(CassandraPartitionCacheKey key) { + return partitionsCache.getIfPresent(key); + } + + public void put(CassandraPartitionCacheKey key) { + partitionsCache.put(key, CompletableFuture.completedFuture(true)); + } +} \ No newline at end of file diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java new file mode 100644 index 0000000000..82c0e0d6d2 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -0,0 +1,132 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed 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.thingsboard.server.dao.nosql; + +import com.datastax.driver.core.BoundStatement; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.CodecRegistry; +import com.datastax.driver.core.Configuration; +import com.datastax.driver.core.ConsistencyLevel; +import com.datastax.driver.core.PreparedStatement; +import com.datastax.driver.core.ResultSetFuture; +import com.datastax.driver.core.Session; +import com.datastax.driver.core.Statement; +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.core.env.Environment; +import org.springframework.test.util.ReflectionTestUtils; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.cassandra.CassandraCluster; +import org.thingsboard.server.dao.timeseries.CassandraBaseTimeseriesDao; + +import java.util.UUID; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class CassandraPartitionsCacheTest { + + private CassandraBaseTimeseriesDao cassandraBaseTimeseriesDao; + + @Mock + private Environment environment; + + @Mock + private CassandraBufferedRateExecutor rateLimiter; + + @Mock + private CassandraCluster cluster; + + @Mock + private Session session; + + @Mock + private Cluster sessionCluster; + + @Mock + private Configuration configuration; + + @Mock + private PreparedStatement preparedStatement; + + @Mock + private BoundStatement boundStatement; + + @Before + public void setUp() { + when(cluster.getDefaultReadConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); + when(cluster.getDefaultWriteConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); + when(cluster.getSession()).thenReturn(session); + when(session.getCluster()).thenReturn(sessionCluster); + when(sessionCluster.getConfiguration()).thenReturn(configuration); + when(configuration.getCodecRegistry()).thenReturn(CodecRegistry.DEFAULT_INSTANCE); + when(session.prepare(anyString())).thenReturn(preparedStatement); + when(preparedStatement.bind()).thenReturn(boundStatement); + when(boundStatement.setString(anyInt(), anyString())).thenReturn(boundStatement); + when(boundStatement.setUUID(anyInt(), any(UUID.class))).thenReturn(boundStatement); + when(boundStatement.setLong(anyInt(), anyLong())).thenReturn(boundStatement); + when(boundStatement.setInt(anyInt(), anyInt())).thenReturn(boundStatement); + + cassandraBaseTimeseriesDao = spy(new CassandraBaseTimeseriesDao()); + + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "partitioning", "MONTHS"); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "partitionsCacheSize", 100000); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "systemTtl", 0); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "setNullValuesEnabled", false); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "environment", environment); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "rateLimiter", rateLimiter); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "cluster", cluster); + + doReturn(Futures.immediateFuture(null)).when(cassandraBaseTimeseriesDao).getFuture(any(ResultSetFuture.class), any()); + + } + + @Test + public void testPartitionSave() throws Exception { + + cassandraBaseTimeseriesDao.init(); + + + UUID id = UUID.randomUUID(); + TenantId tenantId = new TenantId(id); + long tsKvEntryTs = System.currentTimeMillis(); + + for (int i = 0; i < 50000; i++) { + cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); + } + + for (int i = 0; i < 60000; i++) { + cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); + } + + verify(cassandraBaseTimeseriesDao, times(60000)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); + + + } + +} \ No newline at end of file diff --git a/dao/src/test/resources/cassandra-test.properties b/dao/src/test/resources/cassandra-test.properties index 51f34a08d6..2bf57b190f 100644 --- a/dao/src/test/resources/cassandra-test.properties +++ b/dao/src/test/resources/cassandra-test.properties @@ -46,6 +46,8 @@ cassandra.query.default_fetch_size=2000 cassandra.query.ts_key_value_partitioning=HOURS +cassandra.query.ts_key_value_partitions_max_cache_size=100000 + cassandra.query.ts_key_value_ttl=0 cassandra.query.debug_events_ttl=604800 From aede1af6f947444144b3b1f64a0681bccbdab57e Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 21 Dec 2020 14:50:07 +0200 Subject: [PATCH 19/32] improvements after review --- .../CassandraBaseTimeseriesDao.java | 20 ++++++++----------- .../nosql/CassandraPartitionsCacheTest.java | 7 ------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index d39c6c5afb..7d834a8eea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -405,33 +405,29 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem } else { CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); CompletableFuture hasFuture = cassandraTsPartitionsCache.has(partitionSearchKey); - SettableFuture listenableFuture = SettableFuture.create(); + SettableFuture listenableFuture = SettableFuture.create(); if (hasFuture == null) { return processDoSavePartition(tenantId, entityId, key, partition, partitionSearchKey, ttl); } else { + long finalTtl = ttl; hasFuture.whenComplete((result, throwable) -> { if (throwable != null) { listenableFuture.setException(throwable); + } else if (result) { + listenableFuture.set(null); } else { - listenableFuture.set(result); + listenableFuture.setFuture(processDoSavePartition(tenantId, entityId, key, partition, partitionSearchKey, finalTtl)); } }); - long finalTtl = ttl; - return Futures.transformAsync(listenableFuture, result -> { - if (result) { - return Futures.immediateFuture(null); - } else { - return processDoSavePartition(tenantId, entityId, key, partition, partitionSearchKey, finalTtl); - } - }, readResultsProcessingExecutor); + return listenableFuture; } } } private ListenableFuture processDoSavePartition(TenantId tenantId, EntityId entityId, String key, long partition, CassandraPartitionCacheKey partitionSearchKey, long ttl) { - return Futures.transformAsync(doSavePartition(tenantId, entityId, key, ttl, partition), input -> { + return Futures.transform(doSavePartition(tenantId, entityId, key, ttl, partition), input -> { cassandraTsPartitionsCache.put(partitionSearchKey); - return Futures.immediateFuture(input); + return input; }, readResultsProcessingExecutor); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java index 82c0e0d6d2..a67d84964a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -103,15 +103,12 @@ public class CassandraPartitionsCacheTest { ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "cluster", cluster); doReturn(Futures.immediateFuture(null)).when(cassandraBaseTimeseriesDao).getFuture(any(ResultSetFuture.class), any()); - } @Test public void testPartitionSave() throws Exception { - cassandraBaseTimeseriesDao.init(); - UUID id = UUID.randomUUID(); TenantId tenantId = new TenantId(id); long tsKvEntryTs = System.currentTimeMillis(); @@ -119,14 +116,10 @@ public class CassandraPartitionsCacheTest { for (int i = 0; i < 50000; i++) { cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); } - for (int i = 0; i < 60000; i++) { cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); } verify(cassandraBaseTimeseriesDao, times(60000)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); - - } - } \ No newline at end of file From 724df48f7911561ae1c6dc41d4f7fbe0c81d9be1 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 21 Dec 2020 15:06:15 +0200 Subject: [PATCH 20/32] added default value for .yml parameter & rename params names --- .../CassandraBaseTimeseriesDao.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index 7d834a8eea..a9671cad6e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -98,7 +98,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem @Value("${cassandra.query.ts_key_value_partitioning}") private String partitioning; - @Value("${cassandra.query.ts_key_value_partitions_max_cache_size}") + @Value("${cassandra.query.ts_key_value_partitions_max_cache_size:100000}") private long partitionsCacheSize; @Value("${cassandra.query.ts_key_value_ttl}") @@ -404,27 +404,27 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem return doSavePartition(tenantId, entityId, key, ttl, partition); } else { CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); - CompletableFuture hasFuture = cassandraTsPartitionsCache.has(partitionSearchKey); - SettableFuture listenableFuture = SettableFuture.create(); - if (hasFuture == null) { - return processDoSavePartition(tenantId, entityId, key, partition, partitionSearchKey, ttl); + CompletableFuture hasInCacheFuture = cassandraTsPartitionsCache.has(partitionSearchKey); + SettableFuture futureResult = SettableFuture.create(); + if (hasInCacheFuture == null) { + return doSavePartitionWithCache(tenantId, entityId, key, partition, partitionSearchKey, ttl); } else { long finalTtl = ttl; - hasFuture.whenComplete((result, throwable) -> { + hasInCacheFuture.whenComplete((result, throwable) -> { if (throwable != null) { - listenableFuture.setException(throwable); + futureResult.setException(throwable); } else if (result) { - listenableFuture.set(null); + futureResult.set(null); } else { - listenableFuture.setFuture(processDoSavePartition(tenantId, entityId, key, partition, partitionSearchKey, finalTtl)); + futureResult.setFuture(doSavePartitionWithCache(tenantId, entityId, key, partition, partitionSearchKey, finalTtl)); } }); - return listenableFuture; + return futureResult; } } } - private ListenableFuture processDoSavePartition(TenantId tenantId, EntityId entityId, String key, long partition, CassandraPartitionCacheKey partitionSearchKey, long ttl) { + private ListenableFuture doSavePartitionWithCache(TenantId tenantId, EntityId entityId, String key, long partition, CassandraPartitionCacheKey partitionSearchKey, long ttl) { return Futures.transform(doSavePartition(tenantId, entityId, key, ttl, partition), input -> { cassandraTsPartitionsCache.put(partitionSearchKey); return input; From 0a2255d0557f8881bc0f6d95bb6a085762fa2989 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 21 Dec 2020 15:46:16 +0200 Subject: [PATCH 21/32] move SettableFuture.create() to the else block --- .../server/dao/timeseries/CassandraBaseTimeseriesDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index a9671cad6e..46f8b4a5cb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -405,11 +405,11 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem } else { CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); CompletableFuture hasInCacheFuture = cassandraTsPartitionsCache.has(partitionSearchKey); - SettableFuture futureResult = SettableFuture.create(); if (hasInCacheFuture == null) { return doSavePartitionWithCache(tenantId, entityId, key, partition, partitionSearchKey, ttl); } else { long finalTtl = ttl; + SettableFuture futureResult = SettableFuture.create(); hasInCacheFuture.whenComplete((result, throwable) -> { if (throwable != null) { futureResult.setException(throwable); From 2ea3b18738e95e646b6220fb898781d53d9f2e8b Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 21 Dec 2020 17:05:12 +0200 Subject: [PATCH 22/32] partitions cache improvements --- .../CassandraBaseTimeseriesDao.java | 41 ++++++++++--------- .../CassandraTsPartitionsCache.java | 4 +- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index 46f8b4a5cb..7bcae3b740 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -404,31 +404,32 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem return doSavePartition(tenantId, entityId, key, ttl, partition); } else { CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); - CompletableFuture hasInCacheFuture = cassandraTsPartitionsCache.has(partitionSearchKey); - if (hasInCacheFuture == null) { - return doSavePartitionWithCache(tenantId, entityId, key, partition, partitionSearchKey, ttl); + if (!cassandraTsPartitionsCache.has(partitionSearchKey)) { + ListenableFuture result = doSavePartition(tenantId, entityId, key, ttl, partition); + Futures.addCallback(result, new CacheCallback<>(partitionSearchKey), MoreExecutors.directExecutor()); + return result; } else { - long finalTtl = ttl; - SettableFuture futureResult = SettableFuture.create(); - hasInCacheFuture.whenComplete((result, throwable) -> { - if (throwable != null) { - futureResult.setException(throwable); - } else if (result) { - futureResult.set(null); - } else { - futureResult.setFuture(doSavePartitionWithCache(tenantId, entityId, key, partition, partitionSearchKey, finalTtl)); - } - }); - return futureResult; + return Futures.immediateFuture(null); } } } - private ListenableFuture doSavePartitionWithCache(TenantId tenantId, EntityId entityId, String key, long partition, CassandraPartitionCacheKey partitionSearchKey, long ttl) { - return Futures.transform(doSavePartition(tenantId, entityId, key, ttl, partition), input -> { - cassandraTsPartitionsCache.put(partitionSearchKey); - return input; - }, readResultsProcessingExecutor); + private class CacheCallback implements FutureCallback { + private final CassandraPartitionCacheKey key; + + private CacheCallback(CassandraPartitionCacheKey key) { + this.key = key; + } + + @Override + public void onSuccess(Void result) { + cassandraTsPartitionsCache.put(key); + } + + @Override + public void onFailure(Throwable t) { + + } } private ListenableFuture doSavePartition(TenantId tenantId, EntityId entityId, String key, long ttl, long partition) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java index b467b5446f..bafc00c872 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java @@ -32,8 +32,8 @@ public class CassandraTsPartitionsCache { }); } - public CompletableFuture has(CassandraPartitionCacheKey key) { - return partitionsCache.getIfPresent(key); + public boolean has(CassandraPartitionCacheKey key) { + return partitionsCache.getIfPresent(key) != null; } public void put(CassandraPartitionCacheKey key) { From e516cd31dc411acf84b38c22211120b84ee97aef Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 21 Dec 2020 12:36:35 +0200 Subject: [PATCH 23/32] added Caffeine cache for Cassandra ts partitions saving --- .../src/main/resources/thingsboard.yml | 3 +- .../CassandraBaseTimeseriesDao.java | 104 ++++++++++++----- .../CassandraPartitionCacheKey.java | 30 +++++ .../CassandraTsPartitionsCache.java | 42 +++++++ .../nosql/CassandraPartitionsCacheTest.java | 106 ++++++++++++++++++ .../test/resources/cassandra-test.properties | 2 + 6 files changed, 259 insertions(+), 28 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java create mode 100644 dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 791b032352..4a7c58e4db 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -192,8 +192,9 @@ cassandra: read_consistency_level: "${CASSANDRA_READ_CONSISTENCY_LEVEL:ONE}" write_consistency_level: "${CASSANDRA_WRITE_CONSISTENCY_LEVEL:ONE}" default_fetch_size: "${CASSANDRA_DEFAULT_FETCH_SIZE:2000}" - # Specify partitioning size for timestamp key-value storage. Example: MINUTES, HOURS, DAYS, MONTHS,INDEFINITE + # Specify partitioning size for timestamp key-value storage. Example: MINUTES, HOURS, DAYS, MONTHS, INDEFINITE ts_key_value_partitioning: "${TS_KV_PARTITIONING:MONTHS}" + ts_key_value_partitions_max_cache_size: "${TS_KV_PARTITIONS_MAX_CACHE_SIZE:100000}" ts_key_value_ttl: "${TS_KV_TTL:0}" events_ttl: "${TS_EVENTS_TTL:0}" # Specify TTL of debug log in seconds. The current value corresponds to one week diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index b9d8c62833..e4d22e7fef 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -79,12 +79,17 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD protected static List FIXED_PARTITION = Arrays.asList(new Long[]{0L}); + private CassandraTsPartitionsCache cassandraTsPartitionsCache; + @Autowired private Environment environment; @Value("${cassandra.query.ts_key_value_partitioning}") private String partitioning; + @Value("${cassandra.query.ts_key_value_partitions_max_cache_size:100000}") + private long partitionsCacheSize; + @Value("${cassandra.query.ts_key_value_ttl}") private long systemTtl; @@ -111,13 +116,16 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD super.startExecutor(); if (!isInstall()) { getFetchStmt(Aggregation.NONE, DESC_ORDER); - } - Optional partition = NoSqlTsPartitionDate.parse(partitioning); - if (partition.isPresent()) { - tsFormat = partition.get(); - } else { - log.warn("Incorrect configuration of partitioning {}", partitioning); - throw new RuntimeException("Failed to parse partitioning property: " + partitioning + "!"); + Optional partition = NoSqlTsPartitionDate.parse(partitioning); + if (partition.isPresent()) { + tsFormat = partition.get(); + if (!isFixedPartitioning() && partitionsCacheSize > 0) { + cassandraTsPartitionsCache = new CassandraTsPartitionsCache(partitionsCacheSize); + } + } else { + log.warn("Incorrect configuration of partitioning {}", partitioning); + throw new RuntimeException("Failed to parse partitioning property: " + partitioning + "!"); + } } } @@ -168,26 +176,6 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD return Futures.transform(Futures.allAsList(futures), result -> dataPointDays, MoreExecutors.directExecutor()); } - @Override - public ListenableFuture savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) { - if (isFixedPartitioning()) { - return Futures.immediateFuture(null); - } - ttl = computeTtl(ttl); - long partition = toPartitionTs(tsKvEntryTs); - log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); - BoundStatementBuilder stmtBuilder = new BoundStatementBuilder((ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt()).bind()); - stmtBuilder.setString(0, entityId.getEntityType().name()) - .setUuid(1, entityId.getId()) - .setLong(2, partition) - .setString(3, key); - if (ttl > 0) { - stmtBuilder.setInt(4, (int) ttl); - } - BoundStatement stmt = stmtBuilder.build(); - return getFuture(executeAsyncWrite(tenantId, stmt), rs -> 0); - } - @Override public ListenableFuture remove(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { long minPartition = toPartitionTs(query.getStartTs()); @@ -461,6 +449,68 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null); } + @Override + public ListenableFuture savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) { + if (isFixedPartitioning()) { + return Futures.immediateFuture(null); + } + ttl = computeTtl(ttl); + long partition = toPartitionTs(tsKvEntryTs); + if (cassandraTsPartitionsCache == null) { + return doSavePartition(tenantId, entityId, key, ttl, partition); + } else { + CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); + if (!cassandraTsPartitionsCache.has(partitionSearchKey)) { + ListenableFuture result = doSavePartition(tenantId, entityId, key, ttl, partition); + Futures.addCallback(result, new CacheCallback<>(partitionSearchKey), MoreExecutors.directExecutor()); + return result; + } else { + return Futures.immediateFuture(0); + } + } + } + + private ListenableFuture doSavePartition(TenantId tenantId, EntityId entityId, String key, long ttl, long partition) { + log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); + PreparedStatement preparedStatement = ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt(); + BoundStatement stmt = preparedStatement.bind(); + stmt.setString(0, entityId.getEntityType().name()); + stmt.setUuid(1, entityId.getId()); + stmt.setLong(2, partition); + stmt.setString(3, key); + if (ttl > 0) { + stmt.setInt(4, (int) ttl); + } +// BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(bind); +// stmtBuilder.setString(0, entityId.getEntityType().name()) +// .setUuid(1, entityId.getId()) +// .setLong(2, partition) +// .setString(3, key); +// if (ttl > 0) { +// stmtBuilder.setInt(4, (int) ttl); +// } +// BoundStatement stmt = stmtBuilder.build(); + return getFuture(executeAsyncWrite(tenantId, stmt), rs -> 0); + } + + private class CacheCallback implements FutureCallback { + private final CassandraPartitionCacheKey key; + + private CacheCallback(CassandraPartitionCacheKey key) { + this.key = key; + } + + @Override + public void onSuccess(Void result) { + cassandraTsPartitionsCache.put(key); + } + + @Override + public void onFailure(Throwable t) { + + } + } + private long computeTtl(long ttl) { if (systemTtl > 0) { if (ttl == 0) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java new file mode 100644 index 0000000000..791ce84113 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraPartitionCacheKey.java @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed 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.thingsboard.server.dao.timeseries; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.thingsboard.server.common.data.id.EntityId; + +@Data +@AllArgsConstructor +public class CassandraPartitionCacheKey { + + private EntityId entityId; + private String key; + private long partition; + +} \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java new file mode 100644 index 0000000000..c167fb28cb --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraTsPartitionsCache.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed 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.thingsboard.server.dao.timeseries; + +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; + +import java.util.concurrent.CompletableFuture; + +public class CassandraTsPartitionsCache { + + private AsyncLoadingCache partitionsCache; + + public CassandraTsPartitionsCache(long maxCacheSize) { + this.partitionsCache = Caffeine.newBuilder() + .maximumSize(maxCacheSize) + .buildAsync(key -> { + throw new IllegalStateException("'get' methods calls are not supported!"); + }); + } + + public boolean has(CassandraPartitionCacheKey key) { + return partitionsCache.getIfPresent(key) != null; + } + + public void put(CassandraPartitionCacheKey key) { + partitionsCache.put(key, CompletableFuture.completedFuture(true)); + } +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java new file mode 100644 index 0000000000..4a607d0f03 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -0,0 +1,106 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed 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.thingsboard.server.dao.nosql; + +import com.datastax.oss.driver.api.core.ConsistencyLevel; +import com.datastax.oss.driver.api.core.cql.BoundStatement; +import com.datastax.oss.driver.api.core.cql.PreparedStatement; +import com.datastax.oss.driver.api.core.cql.Statement; +import com.google.common.util.concurrent.Futures; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.core.env.Environment; +import org.springframework.test.util.ReflectionTestUtils; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.cassandra.CassandraCluster; +import org.thingsboard.server.dao.cassandra.guava.GuavaSession; +import org.thingsboard.server.dao.timeseries.CassandraBaseTimeseriesDao; + +import java.util.UUID; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class CassandraPartitionsCacheTest { + + private CassandraBaseTimeseriesDao cassandraBaseTimeseriesDao; + + @Mock + private Environment environment; + + @Mock + private CassandraBufferedRateExecutor rateLimiter; + + @Mock + private CassandraCluster cluster; + + @Mock + private GuavaSession session; + + @Mock + private PreparedStatement preparedStatement; + + @Mock + private BoundStatement boundStatement; + + @Before + public void setUp() throws Exception { + when(cluster.getDefaultReadConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); + when(cluster.getDefaultWriteConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); + when(cluster.getSession()).thenReturn(session); + when(session.prepare(anyString())).thenReturn(preparedStatement); + when(preparedStatement.bind()).thenReturn(boundStatement); + + cassandraBaseTimeseriesDao = spy(new CassandraBaseTimeseriesDao()); + + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "partitioning", "MONTHS"); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "partitionsCacheSize", 100000); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "systemTtl", 0); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "setNullValuesEnabled", false); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "environment", environment); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "rateLimiter", rateLimiter); + ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "cluster", cluster); + + doReturn(Futures.immediateFuture(null)).when(cassandraBaseTimeseriesDao).getFuture(any(TbResultSetFuture.class), any()); + } + + @Test + public void testPartitionSave() throws Exception { + cassandraBaseTimeseriesDao.init(); + + UUID id = UUID.randomUUID(); + TenantId tenantId = new TenantId(id); + long tsKvEntryTs = System.currentTimeMillis(); + + for (int i = 0; i < 50000; i++) { + cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); + } + + for (int i = 0; i < 60000; i++) { + cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); + } + verify(cassandraBaseTimeseriesDao, times(60000)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); + } +} \ No newline at end of file diff --git a/dao/src/test/resources/cassandra-test.properties b/dao/src/test/resources/cassandra-test.properties index 43a78abac4..4b3ea0a74d 100644 --- a/dao/src/test/resources/cassandra-test.properties +++ b/dao/src/test/resources/cassandra-test.properties @@ -54,6 +54,8 @@ cassandra.query.default_fetch_size=2000 cassandra.query.ts_key_value_partitioning=HOURS +cassandra.query.ts_key_value_partitions_max_cache_size=100000 + cassandra.query.ts_key_value_ttl=0 cassandra.query.debug_events_ttl=604800 From 24a31d61349e6a3e32c71fc149711822202ee281 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Mon, 21 Dec 2020 21:43:09 +0200 Subject: [PATCH 24/32] update code --- .../CassandraBaseTimeseriesDao.java | 65 ++++++++----------- .../nosql/CassandraPartitionsCacheTest.java | 19 +++--- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index e4d22e7fef..acd140c0b6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -176,6 +176,27 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD return Futures.transform(Futures.allAsList(futures), result -> dataPointDays, MoreExecutors.directExecutor()); } + @Override + public ListenableFuture savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) { + if (isFixedPartitioning()) { + return Futures.immediateFuture(null); + } + ttl = computeTtl(ttl); + long partition = toPartitionTs(tsKvEntryTs); + if (cassandraTsPartitionsCache == null) { + return doSavePartition(tenantId, entityId, key, ttl, partition); + } else { + CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); + if (!cassandraTsPartitionsCache.has(partitionSearchKey)) { + ListenableFuture result = doSavePartition(tenantId, entityId, key, ttl, partition); + Futures.addCallback(result, new CacheCallback<>(partitionSearchKey), MoreExecutors.directExecutor()); + return result; + } else { + return Futures.immediateFuture(0); + } + } + } + @Override public ListenableFuture remove(TenantId tenantId, EntityId entityId, DeleteTsKvQuery query) { long minPartition = toPartitionTs(query.getStartTs()); @@ -449,47 +470,17 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null); } - @Override - public ListenableFuture savePartition(TenantId tenantId, EntityId entityId, long tsKvEntryTs, String key, long ttl) { - if (isFixedPartitioning()) { - return Futures.immediateFuture(null); - } - ttl = computeTtl(ttl); - long partition = toPartitionTs(tsKvEntryTs); - if (cassandraTsPartitionsCache == null) { - return doSavePartition(tenantId, entityId, key, ttl, partition); - } else { - CassandraPartitionCacheKey partitionSearchKey = new CassandraPartitionCacheKey(entityId, key, partition); - if (!cassandraTsPartitionsCache.has(partitionSearchKey)) { - ListenableFuture result = doSavePartition(tenantId, entityId, key, ttl, partition); - Futures.addCallback(result, new CacheCallback<>(partitionSearchKey), MoreExecutors.directExecutor()); - return result; - } else { - return Futures.immediateFuture(0); - } - } - } - private ListenableFuture doSavePartition(TenantId tenantId, EntityId entityId, String key, long ttl, long partition) { log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); - PreparedStatement preparedStatement = ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt(); - BoundStatement stmt = preparedStatement.bind(); - stmt.setString(0, entityId.getEntityType().name()); - stmt.setUuid(1, entityId.getId()); - stmt.setLong(2, partition); - stmt.setString(3, key); + BoundStatementBuilder stmtBuilder = new BoundStatementBuilder((ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt()).bind()); + stmtBuilder.setString(0, entityId.getEntityType().name()) + .setUuid(1, entityId.getId()) + .setLong(2, partition) + .setString(3, key); if (ttl > 0) { - stmt.setInt(4, (int) ttl); + stmtBuilder.setInt(4, (int) ttl); } -// BoundStatementBuilder stmtBuilder = new BoundStatementBuilder(bind); -// stmtBuilder.setString(0, entityId.getEntityType().name()) -// .setUuid(1, entityId.getId()) -// .setLong(2, partition) -// .setString(3, key); -// if (ttl > 0) { -// stmtBuilder.setInt(4, (int) ttl); -// } -// BoundStatement stmt = stmtBuilder.build(); + BoundStatement stmt = stmtBuilder.build(); return getFuture(executeAsyncWrite(tenantId, stmt), rs -> 0); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java index 4a607d0f03..9646917ff7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -21,6 +21,7 @@ import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.google.common.util.concurrent.Futures; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -86,6 +87,7 @@ public class CassandraPartitionsCacheTest { doReturn(Futures.immediateFuture(null)).when(cassandraBaseTimeseriesDao).getFuture(any(TbResultSetFuture.class), any()); } + @Ignore @Test public void testPartitionSave() throws Exception { cassandraBaseTimeseriesDao.init(); @@ -94,13 +96,14 @@ public class CassandraPartitionsCacheTest { TenantId tenantId = new TenantId(id); long tsKvEntryTs = System.currentTimeMillis(); - for (int i = 0; i < 50000; i++) { - cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); - } - - for (int i = 0; i < 60000; i++) { - cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); - } - verify(cassandraBaseTimeseriesDao, times(60000)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); +// for (int i = 0; i < 50000; i++) { +// cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); +// } +// +// for (int i = 0; i < 60000; i++) { +// cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); +// } + cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test", 0); + verify(cassandraBaseTimeseriesDao, times(1)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); } } \ No newline at end of file From 637ad6cac5144ce205d0c9003b1a74813e045a96 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 22 Dec 2020 17:34:23 +0200 Subject: [PATCH 25/32] remove boundStatementBuilder from doSavePartition method --- .../CassandraBaseTimeseriesDao.java | 8 +-- .../nosql/CassandraPartitionsCacheTest.java | 53 ++++++++++--------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index acd140c0b6..db5f8f8684 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -472,15 +472,15 @@ public class CassandraBaseTimeseriesDao extends AbstractCassandraBaseTimeseriesD private ListenableFuture doSavePartition(TenantId tenantId, EntityId entityId, String key, long ttl, long partition) { log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key); - BoundStatementBuilder stmtBuilder = new BoundStatementBuilder((ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt()).bind()); - stmtBuilder.setString(0, entityId.getEntityType().name()) + PreparedStatement preparedStatement = ttl == 0 ? getPartitionInsertStmt() : getPartitionInsertTtlStmt(); + BoundStatement stmt = preparedStatement.bind(); + stmt = stmt.setString(0, entityId.getEntityType().name()) .setUuid(1, entityId.getId()) .setLong(2, partition) .setString(3, key); if (ttl > 0) { - stmtBuilder.setInt(4, (int) ttl); + stmt = stmt.setInt(4, (int) ttl); } - BoundStatement stmt = stmtBuilder.build(); return getFuture(executeAsyncWrite(tenantId, stmt), rs -> 0); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java index 9646917ff7..9a00692cb2 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -21,10 +21,10 @@ import com.datastax.oss.driver.api.core.cql.PreparedStatement; import com.datastax.oss.driver.api.core.cql.Statement; import com.google.common.util.concurrent.Futures; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.core.env.Environment; import org.springframework.test.util.ReflectionTestUtils; @@ -36,9 +36,9 @@ import org.thingsboard.server.dao.timeseries.CassandraBaseTimeseriesDao; import java.util.UUID; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -46,36 +46,29 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class CassandraPartitionsCacheTest { + @Spy private CassandraBaseTimeseriesDao cassandraBaseTimeseriesDao; @Mock - private Environment environment; + private PreparedStatement preparedStatement; @Mock - private CassandraBufferedRateExecutor rateLimiter; + private BoundStatement boundStatement; @Mock - private CassandraCluster cluster; + private Environment environment; @Mock - private GuavaSession session; + private CassandraBufferedRateExecutor rateLimiter; @Mock - private PreparedStatement preparedStatement; + private CassandraCluster cluster; @Mock - private BoundStatement boundStatement; + private GuavaSession session; @Before public void setUp() throws Exception { - when(cluster.getDefaultReadConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); - when(cluster.getDefaultWriteConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); - when(cluster.getSession()).thenReturn(session); - when(session.prepare(anyString())).thenReturn(preparedStatement); - when(preparedStatement.bind()).thenReturn(boundStatement); - - cassandraBaseTimeseriesDao = spy(new CassandraBaseTimeseriesDao()); - ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "partitioning", "MONTHS"); ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "partitionsCacheSize", 100000); ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "systemTtl", 0); @@ -84,10 +77,20 @@ public class CassandraPartitionsCacheTest { ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "rateLimiter", rateLimiter); ReflectionTestUtils.setField(cassandraBaseTimeseriesDao, "cluster", cluster); + when(cluster.getDefaultReadConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); + when(cluster.getDefaultWriteConsistencyLevel()).thenReturn(ConsistencyLevel.ONE); + when(cluster.getSession()).thenReturn(session); + when(session.prepare(anyString())).thenReturn(preparedStatement); + + when(preparedStatement.bind()).thenReturn(boundStatement); + + when(boundStatement.setString(anyInt(), anyString())).thenReturn(boundStatement); + when(boundStatement.setUuid(anyInt(), any(UUID.class))).thenReturn(boundStatement); + when(boundStatement.setLong(anyInt(), any(Long.class))).thenReturn(boundStatement); + doReturn(Futures.immediateFuture(null)).when(cassandraBaseTimeseriesDao).getFuture(any(TbResultSetFuture.class), any()); } - @Ignore @Test public void testPartitionSave() throws Exception { cassandraBaseTimeseriesDao.init(); @@ -96,14 +99,12 @@ public class CassandraPartitionsCacheTest { TenantId tenantId = new TenantId(id); long tsKvEntryTs = System.currentTimeMillis(); -// for (int i = 0; i < 50000; i++) { -// cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); -// } -// -// for (int i = 0; i < 60000; i++) { -// cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); -// } - cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test", 0); - verify(cassandraBaseTimeseriesDao, times(1)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); + for (int i = 0; i < 50000; i++) { + cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); + } + for (int i = 0; i < 60000; i++) { + cassandraBaseTimeseriesDao.savePartition(tenantId, tenantId, tsKvEntryTs, "test" + i, 0); + } + verify(cassandraBaseTimeseriesDao, times(60000)).executeAsyncWrite(any(TenantId.class), any(Statement.class)); } } \ No newline at end of file From bff16ddafd650f5f1117fd0a73131ee5e07bc133 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 22 Dec 2020 18:02:38 +0200 Subject: [PATCH 26/32] Mqtt flag sessionPresent depends on flag isCleanSession --- .../transport/mqtt/MqttTransportHandler.java | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index abb8f629f1..7f45577536 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -357,7 +357,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement log.info("[{}] Processing connect msg for client: {}!", sessionId, msg.payload().clientIdentifier()); X509Certificate cert; if (sslHandler != null && (cert = getX509Certificate()) != null) { - processX509CertConnect(ctx, cert); + processX509CertConnect(ctx, cert, msg); } else { processAuthTokenConnect(ctx, msg); } @@ -367,27 +367,27 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement String userName = msg.payload().userName(); log.info("[{}] Processing connect msg for client with user name: {}!", sessionId, userName); if (StringUtils.isEmpty(userName)) { - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD)); + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, msg)); ctx.close(); } else { transportService.process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(userName).build(), new TransportServiceCallback() { @Override - public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) { - onValidateDeviceResponse(msg, ctx); + public void onSuccess(ValidateDeviceCredentialsResponseMsg responseMsg) { + onValidateDeviceResponse(responseMsg, ctx, msg); } @Override public void onError(Throwable e) { log.trace("[{}] Failed to process credentials: {}", address, userName, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE)); + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, msg)); ctx.close(); } }); } } - private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate cert) { + private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate cert, MqttConnectMessage msg) { try { if(!context.isSkipValidityCheckForClientCert()){ cert.checkValidity(); @@ -397,19 +397,19 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement transportService.process(ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(), new TransportServiceCallback() { @Override - public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) { - onValidateDeviceResponse(msg, ctx); + public void onSuccess(ValidateDeviceCredentialsResponseMsg responseMsg) { + onValidateDeviceResponse(responseMsg, ctx, msg); } @Override public void onError(Throwable e) { log.trace("[{}] Failed to process credentials: {}", address, sha3Hash, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE)); + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, msg)); ctx.close(); } }); } catch (Exception e) { - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED)); + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, msg)); ctx.close(); } } @@ -433,11 +433,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement doDisconnect(); } - private MqttConnAckMessage createMqttConnAckMsg(MqttConnectReturnCode returnCode) { + private MqttConnAckMessage createMqttConnAckMsg(MqttConnectReturnCode returnCode, MqttConnectMessage msg) { MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(CONNACK, false, AT_MOST_ONCE, false, 0); MqttConnAckVariableHeader mqttConnAckVariableHeader = - new MqttConnAckVariableHeader(returnCode, true); + new MqttConnAckVariableHeader(returnCode, !msg.variableHeader().isCleanSession()); return new MqttConnAckMessage(mqttFixedHeader, mqttConnAckVariableHeader); } @@ -513,36 +513,36 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } - private void onValidateDeviceResponse(ValidateDeviceCredentialsResponseMsg msg, ChannelHandlerContext ctx) { - if (!msg.hasDeviceInfo()) { - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED)); + private void onValidateDeviceResponse(ValidateDeviceCredentialsResponseMsg responseMsg, ChannelHandlerContext ctx, MqttConnectMessage msg) { + if (!responseMsg.hasDeviceInfo()) { + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, msg)); ctx.close(); } else { - deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo()); + deviceSessionCtx.setDeviceInfo(responseMsg.getDeviceInfo()); sessionInfo = SessionInfoProto.newBuilder() .setNodeId(context.getNodeId()) .setSessionIdMSB(sessionId.getMostSignificantBits()) .setSessionIdLSB(sessionId.getLeastSignificantBits()) - .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) - .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) - .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) - .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) - .setDeviceName(msg.getDeviceInfo().getDeviceName()) - .setDeviceType(msg.getDeviceInfo().getDeviceType()) + .setDeviceIdMSB(responseMsg.getDeviceInfo().getDeviceIdMSB()) + .setDeviceIdLSB(responseMsg.getDeviceInfo().getDeviceIdLSB()) + .setTenantIdMSB(responseMsg.getDeviceInfo().getTenantIdMSB()) + .setTenantIdLSB(responseMsg.getDeviceInfo().getTenantIdLSB()) + .setDeviceName(responseMsg.getDeviceInfo().getDeviceName()) + .setDeviceType(responseMsg.getDeviceInfo().getDeviceType()) .build(); transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), new TransportServiceCallback() { @Override - public void onSuccess(Void msg) { + public void onSuccess(Void response) { transportService.registerAsyncSession(sessionInfo, MqttTransportHandler.this); checkGatewaySession(); - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED)); + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, msg)); log.info("[{}] Client connected!", sessionId); } @Override public void onError(Throwable e) { log.warn("[{}] Failed to submit session event", sessionId, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE)); + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, msg)); ctx.close(); } }); From fb8ddbda584393dd1abe8a59ec68120ec3949bc6 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 23 Dec 2020 11:46:05 +0200 Subject: [PATCH 27/32] changed doReturn for cassandraBaseTimeseriesDao.getFuture in tests --- .../server/dao/nosql/CassandraPartitionsCacheTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java index 9a00692cb2..f19165a557 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/nosql/CassandraPartitionsCacheTest.java @@ -88,7 +88,7 @@ public class CassandraPartitionsCacheTest { when(boundStatement.setUuid(anyInt(), any(UUID.class))).thenReturn(boundStatement); when(boundStatement.setLong(anyInt(), any(Long.class))).thenReturn(boundStatement); - doReturn(Futures.immediateFuture(null)).when(cassandraBaseTimeseriesDao).getFuture(any(TbResultSetFuture.class), any()); + doReturn(Futures.immediateFuture(0)).when(cassandraBaseTimeseriesDao).getFuture(any(TbResultSetFuture.class), any()); } @Test From 16d82e77fc5000a19d30797ef195ac30b2cf406a Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 23 Dec 2020 16:54:14 +0200 Subject: [PATCH 28/32] refactored --- .../transport/mqtt/MqttTransportHandler.java | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 7f45577536..bfd32eb751 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -363,31 +363,31 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } - private void processAuthTokenConnect(ChannelHandlerContext ctx, MqttConnectMessage msg) { - String userName = msg.payload().userName(); + private void processAuthTokenConnect(ChannelHandlerContext ctx, MqttConnectMessage connectMessage) { + String userName = connectMessage.payload().userName(); log.info("[{}] Processing connect msg for client with user name: {}!", sessionId, userName); if (StringUtils.isEmpty(userName)) { - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, msg)); + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD, connectMessage)); ctx.close(); } else { transportService.process(ValidateDeviceTokenRequestMsg.newBuilder().setToken(userName).build(), new TransportServiceCallback() { @Override - public void onSuccess(ValidateDeviceCredentialsResponseMsg responseMsg) { - onValidateDeviceResponse(responseMsg, ctx, msg); + public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) { + onValidateDeviceResponse(msg, ctx, connectMessage); } @Override public void onError(Throwable e) { log.trace("[{}] Failed to process credentials: {}", address, userName, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, msg)); + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); ctx.close(); } }); } } - private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate cert, MqttConnectMessage msg) { + private void processX509CertConnect(ChannelHandlerContext ctx, X509Certificate cert, MqttConnectMessage connectMessage) { try { if(!context.isSkipValidityCheckForClientCert()){ cert.checkValidity(); @@ -397,19 +397,19 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement transportService.process(ValidateDeviceX509CertRequestMsg.newBuilder().setHash(sha3Hash).build(), new TransportServiceCallback() { @Override - public void onSuccess(ValidateDeviceCredentialsResponseMsg responseMsg) { - onValidateDeviceResponse(responseMsg, ctx, msg); + public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) { + onValidateDeviceResponse(msg, ctx, connectMessage); } @Override public void onError(Throwable e) { log.trace("[{}] Failed to process credentials: {}", address, sha3Hash, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, msg)); + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); ctx.close(); } }); } catch (Exception e) { - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, msg)); + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, connectMessage)); ctx.close(); } } @@ -513,36 +513,36 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } - private void onValidateDeviceResponse(ValidateDeviceCredentialsResponseMsg responseMsg, ChannelHandlerContext ctx, MqttConnectMessage msg) { - if (!responseMsg.hasDeviceInfo()) { - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, msg)); + private void onValidateDeviceResponse(ValidateDeviceCredentialsResponseMsg msg, ChannelHandlerContext ctx, MqttConnectMessage connectMessage) { + if (!msg.hasDeviceInfo()) { + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, connectMessage)); ctx.close(); } else { - deviceSessionCtx.setDeviceInfo(responseMsg.getDeviceInfo()); + deviceSessionCtx.setDeviceInfo(msg.getDeviceInfo()); sessionInfo = SessionInfoProto.newBuilder() .setNodeId(context.getNodeId()) .setSessionIdMSB(sessionId.getMostSignificantBits()) .setSessionIdLSB(sessionId.getLeastSignificantBits()) - .setDeviceIdMSB(responseMsg.getDeviceInfo().getDeviceIdMSB()) - .setDeviceIdLSB(responseMsg.getDeviceInfo().getDeviceIdLSB()) - .setTenantIdMSB(responseMsg.getDeviceInfo().getTenantIdMSB()) - .setTenantIdLSB(responseMsg.getDeviceInfo().getTenantIdLSB()) - .setDeviceName(responseMsg.getDeviceInfo().getDeviceName()) - .setDeviceType(responseMsg.getDeviceInfo().getDeviceType()) + .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) + .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) + .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) + .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB()) + .setDeviceName(msg.getDeviceInfo().getDeviceName()) + .setDeviceType(msg.getDeviceInfo().getDeviceType()) .build(); transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), new TransportServiceCallback() { @Override public void onSuccess(Void response) { transportService.registerAsyncSession(sessionInfo, MqttTransportHandler.this); checkGatewaySession(); - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, msg)); + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, connectMessage)); log.info("[{}] Client connected!", sessionId); } @Override public void onError(Throwable e) { log.warn("[{}] Failed to submit session event", sessionId, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, msg)); + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); ctx.close(); } }); From fd3208cf827e22c185542abdc0dc7208b9089c5b Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Wed, 23 Dec 2020 17:14:19 +0200 Subject: [PATCH 29/32] 2nd part of additions to fix after review --- .../components/widget/lib/maps/leaflet-map.ts | 26 +++++------ .../trip-animation.component.ts | 43 ++++++++----------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 43c954aeed..5430aa2e69 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -608,30 +608,30 @@ export default abstract class LeafletMap { return polygon; } - updatePoints(pointsData: FormattedData[][], getTooltip: (point: FormattedData[], setTooltip?: boolean) => string) { - for(let i = 0; i < pointsData.length; i++) { - let pointsList = pointsData[i]; - if(i === 0) { - if (this.points) { - this.map.removeLayer(this.points); - } - this.points = new FeatureGroup(); + updatePoints(pointsData: FormattedData[][], getTooltip: (point: FormattedData) => string) { + if(pointsData.length) { + if (this.points) { + this.map.removeLayer(this.points); } + this.points = new FeatureGroup(); + } + for(let i = 0; i < pointsData.length; i++) { + const pointsList = pointsData[i]; pointsList.filter(pdata => !!this.convertPosition(pdata)).forEach(data => { const point = L.circleMarker(this.convertPosition(data), { color: this.options.pointColor, radius: this.options.pointSize }); if (!this.options.pointTooltipOnRightPanel) { - point.on('click', () => getTooltip([data])); + point.on('click', () => getTooltip(data)); } else { - createTooltip(point, this.options, data.$datasource, getTooltip([data], false)); + createTooltip(point, this.options, data.$datasource, getTooltip(data)); } this.points.addLayer(point); }); - if(i === (pointsData.length - 1)) { - this.map.addLayer(this.points); - } + } + if(pointsData.length) { + this.map.addLayer(this.points); } } diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 5872c9023e..8de3269bb0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -166,8 +166,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy currentPosition[j] = this.calculateLastPoints(this.interpolatedTimeData[j], time); } } - this.calcLabel(currentPosition); - this.calcTooltip(currentPosition, true); + this.calcLabel(); + this.calcMainTooltip(currentPosition); if (this.mapWidget && this.mapWidget.map && this.mapWidget.map.map) { const formattedInterpolatedTimeData = this.interpolatedTimeData.map(ds => _.values(ds)); this.mapWidget.map.updatePolylines(formattedInterpolatedTimeData, true); @@ -221,33 +221,26 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy } } - calcTooltip = (points?: FormattedData[], isMainTooltip: boolean = false): string => { - let tooltipText; - if(isMainTooltip) { - this.mainTooltips = [] - } + calcTooltip = (point: FormattedData): string => { + const data = point ? point : this.activeTrip; + const tooltipPattern: string = this.settings.useTooltipFunction ? + safeExecute(this.settings.tooltipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern; + return parseWithTranslation.parseTemplate(tooltipPattern, data, true); + } + + private calcMainTooltip(points: FormattedData[]): void { + const tooltips = []; for (let point of points) { - const data = point ? point : this.activeTrip; - const tooltipPattern: string = this.settings.useTooltipFunction ? - safeExecute(this.settings.tooltipFunction, [data, this.historicalData, point.dsIndex]) : this.settings.tooltipPattern; - tooltipText = parseWithTranslation.parseTemplate(tooltipPattern, data, true); - if(isMainTooltip) { - this.mainTooltips.push(this.sanitizer.sanitize(SecurityContext.HTML, tooltipText)); - } + tooltips.push(this.sanitizer.sanitize(SecurityContext.HTML, this.calcTooltip(point))); } - this.cd.detectChanges(); - return tooltipText; + this.mainTooltips = tooltips; } - calcLabel(formattedDataArr: FormattedData[]) { - let labelToSet = ''; - for (let formattedData of formattedDataArr) { - const labelText: string = this.settings.useLabelFunction ? - safeExecute(this.settings.labelFunction, [formattedData, this.historicalData, formattedData.dsIndex]) : this.settings.label; - const label = (parseWithTranslation.parseTemplate(labelText, formattedData, true)); - labelToSet = labelToSet.length ? labelToSet + ',' + label : label; - } - this.label = labelToSet; + calcLabel() { + const data = this.activeTrip; + const labelText: string = this.settings.useLabelFunction ? + safeExecute(this.settings.labelFunction, [data, this.historicalData, data.dsIndex]) : this.settings.label; + this.label = (parseWithTranslation.parseTemplate(labelText, data, true)); } interpolateArray(originData: FormattedData[]) { From b19bcdfe9a3b0eae6409654a4a7a92597767b8b1 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 23 Dec 2020 17:31:08 +0200 Subject: [PATCH 30/32] UI: Improvement time rendering profiles seated too many parameters --- .../alarm/device-profile-alarm.component.html | 164 +++++++++--------- .../profile/device-profile.component.html | 38 ++-- .../tenant-profile-data.component.html | 10 +- 3 files changed, 113 insertions(+), 99 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html index cec0f48259..79fa9b7383 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html @@ -33,87 +33,91 @@ -
- - - {{'device-profile.alarm-type' | translate}} - - - {{ 'device-profile.alarm-type-required' | translate }} - - - {{ 'device-profile.alarm-type-unique' | translate }} - - -
- - - -
-
device-profile.advanced-settings
-
-
-
- - {{ 'device-profile.propagate-alarm' | translate }} - -
- - device-profile.alarm-rule-relation-types-list - - - {{key}} - close - - - - + +
+ + + {{'device-profile.alarm-type' | translate}} + + + {{ 'device-profile.alarm-type-required' | translate }} + + + {{ 'device-profile.alarm-type-unique' | translate }} + -
-
-
-
device-profile.create-alarm-rules
- - -
device-profile.clear-alarm-rule
-
-
- - -
-
-
- device-profile.no-clear-alarm-rule -
-
- + + + +
+
device-profile.advanced-settings
+
+
+
+ + + {{ 'device-profile.propagate-alarm' | translate }} + +
+ + device-profile.alarm-rule-relation-types-list + + + {{key}} + close + + + + + +
+
+
+
+
device-profile.create-alarm-rules
+ + +
device-profile.clear-alarm-rule
+
+
+ + +
+ +
+
+ device-profile.no-clear-alarm-rule +
+
+ +
-
+ diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html index 4cba236d2a..bb3d6e7e43 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html @@ -91,10 +91,12 @@
device-profile.profile-configuration
- - + + + + @@ -102,10 +104,12 @@
device-profile.transport-configuration
- - + + + +
@@ -115,10 +119,12 @@ entityForm.get('profileData.alarms').value.length : 0} }}
- - + + + + @@ -126,9 +132,11 @@
device-profile.device-provisioning
- - + + + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html index 3d853940f4..ae7a9540db 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-data.component.html @@ -22,9 +22,11 @@
tenant-profile.profile-configuration
- - + + + + From bfee3016259e14004f626cae51b9fc2943377c26 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 23 Dec 2020 17:47:58 +0200 Subject: [PATCH 31/32] Set ver to 2.5.6-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- ui-ngx/pom.xml | 2 +- 37 files changed, 38 insertions(+), 38 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 8a12fe05bb..828fcc2efd 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 9dea3c57a3..66a9883a14 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index d50399525e..fb5720eb9b 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index b2dd156acb..3edbcdb87d 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index bcff40ce4d..8e43c70911 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 5ceae3ea57..9421aed1b4 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index 54cd24f66d..eae5af22e1 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 8cf70c7498..5c9129a919 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index e775286bdd..3c45a7000f 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index ab60e6d4eb..9b60bfb470 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 8b043b8c2e..26008b6d4a 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 22b17989c9..7531c614e5 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index d61963053e..df2a577851 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index 474db1270e..603e365243 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 907ddb7150..05eb2a2f96 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 339b60741f..a0e865c7c9 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 692b371275..96c01b98d7 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index cfdf6ed79f..a7cac82052 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index ad700779a9..2213bccd20 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index d1901a3e33..ef2d3eaa16 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index ad09511f36..919ace3232 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index 97196bb879..7d492eb851 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 79a26aeef3..dc3b23bd26 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 5a8b79d9d9..d8064680b8 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 2902ea1c85..5678845000 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index e917ce23f7..266a9bb235 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard netty-mqtt - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 257328b550..425d26736a 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 89f6b33a02..5cdc05438b 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 43bd3859af..98d7054f8c 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 448b5f8760..2e868380a4 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 9fb02ec1f0..748593b1e8 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index b3fce1373f..2744bdfeeb 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 94cb8e88a9..9c53882520 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 59cfef95f0..6255717009 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index b2ba041e0b..b5294309df 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index d477fc7de2..ca50c573d2 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard transport diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index 0420401dbe..3b945801e1 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.2.1-SNAPSHOT + 2.5.6-SNAPSHOT thingsboard org.thingsboard From 6814c21ee921336c78654552f9aca048fb97b514 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 23 Dec 2020 18:24:42 +0200 Subject: [PATCH 32/32] restore ver 3.2.1-SNAPSHOT --- application/pom.xml | 2 +- common/actor/pom.xml | 2 +- common/dao-api/pom.xml | 2 +- common/data/pom.xml | 2 +- common/message/pom.xml | 2 +- common/pom.xml | 2 +- common/queue/pom.xml | 2 +- common/stats/pom.xml | 2 +- common/transport/coap/pom.xml | 2 +- common/transport/http/pom.xml | 2 +- common/transport/mqtt/pom.xml | 2 +- common/transport/pom.xml | 2 +- common/transport/transport-api/pom.xml | 2 +- common/util/pom.xml | 2 +- dao/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/pom.xml | 2 +- msa/pom.xml | 2 +- msa/tb-node/pom.xml | 2 +- msa/tb/pom.xml | 2 +- msa/transport/coap/pom.xml | 2 +- msa/transport/http/pom.xml | 2 +- msa/transport/mqtt/pom.xml | 2 +- msa/transport/pom.xml | 2 +- msa/web-ui/pom.xml | 2 +- netty-mqtt/pom.xml | 4 ++-- pom.xml | 2 +- rest-client/pom.xml | 2 +- rule-engine/pom.xml | 2 +- rule-engine/rule-engine-api/pom.xml | 2 +- rule-engine/rule-engine-components/pom.xml | 2 +- tools/pom.xml | 2 +- transport/coap/pom.xml | 2 +- transport/http/pom.xml | 2 +- transport/mqtt/pom.xml | 2 +- transport/pom.xml | 2 +- ui-ngx/pom.xml | 2 +- 37 files changed, 38 insertions(+), 38 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 828fcc2efd..8a12fe05bb 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 66a9883a14..9dea3c57a3 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index fb5720eb9b..d50399525e 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index 3edbcdb87d..b2dd156acb 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 8e43c70911..bcff40ce4d 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 9421aed1b4..5ceae3ea57 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index eae5af22e1..54cd24f66d 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 5c9129a919..8cf70c7498 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index 3c45a7000f..e775286bdd 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 9b60bfb470..ab60e6d4eb 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 26008b6d4a..8b043b8c2e 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 7531c614e5..22b17989c9 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index df2a577851..d61963053e 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index 603e365243..474db1270e 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 05eb2a2f96..907ddb7150 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard dao diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index a0e865c7c9..339b60741f 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 96c01b98d7..692b371275 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index a7cac82052..cfdf6ed79f 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 2213bccd20..ad700779a9 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index ef2d3eaa16..d1901a3e33 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index 919ace3232..ad09511f36 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index 7d492eb851..97196bb879 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index dc3b23bd26..79a26aeef3 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index d8064680b8..5a8b79d9d9 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 5678845000..2902ea1c85 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 266a9bb235..e917ce23f7 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard netty-mqtt - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 425d26736a..257328b550 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 5cdc05438b..89f6b33a02 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index 98d7054f8c..43bd3859af 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 2e868380a4..448b5f8760 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 748593b1e8..9fb02ec1f0 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index 2744bdfeeb..b3fce1373f 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 9c53882520..94cb8e88a9 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 6255717009..59cfef95f0 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index b5294309df..b2ba041e0b 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index ca50c573d2..d477fc7de2 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard transport diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index 3b945801e1..0420401dbe 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.5.6-SNAPSHOT + 3.2.1-SNAPSHOT thingsboard org.thingsboard