Commit 712a14ec22f75ac4623626f5b1ed3a4471f337c7
Merge remote-tracking branch 'origin/develop/3.3-edge' into develop/3.3-edge
Showing
100 changed files
with
1170 additions
and
391 deletions
Too many changes to show.
To preserve performance only 100 of 376 files are displayed.
... | ... | @@ -15,11 +15,10 @@ |
15 | 15 | # |
16 | 16 | |
17 | 17 | export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@ -Dinstall.data_dir=@pkg.installFolder@/data" |
18 | -export JAVA_OPTS="$JAVA_OPTS -Xloggc:@pkg.logFolder@/gc.log -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:+PrintGCDateStamps" | |
19 | -export JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10" | |
20 | -export JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" | |
21 | -export JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=10000 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+CMSParallelInitialMarkEnabled" | |
22 | -export JAVA_OPTS="$JAVA_OPTS -XX:+CMSEdenChunksRecordAlways -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly" | |
18 | +export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=@pkg.logFolder@/gc.log:time,uptime,level,tags:filecount=10,filesize=10M" | |
19 | +export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError" | |
20 | +export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark" | |
21 | +export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10" | |
23 | 22 | export LOG_FILENAME=${pkg.name}.out |
24 | 23 | export LOADER_PATH=${pkg.installFolder}/conf,${pkg.installFolder}/extensions |
25 | 24 | export SQL_DATA_FOLDER=${pkg.installFolder}/data/sql | ... | ... |
... | ... | @@ -26,22 +26,6 @@ |
26 | 26 | } |
27 | 27 | }, |
28 | 28 | { |
29 | - "alias": "basic_timeseries", | |
30 | - "name": "Timeseries - Flot", | |
31 | - "descriptor": { | |
32 | - "type": "timeseries", | |
33 | - "sizeX": 8, | |
34 | - "sizeY": 5, | |
35 | - "resources": [], | |
36 | - "templateHtml": "", | |
37 | - "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", | |
38 | - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
39 | - "settingsSchema": "{}", | |
40 | - "dataKeySettingsSchema": "{}", | |
41 | - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Timeseries - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" | |
42 | - } | |
43 | - }, | |
44 | - { | |
45 | 29 | "alias": "doughnut_chart_js", |
46 | 30 | "name": "Doughnut - Chart.js", |
47 | 31 | "descriptor": { |
... | ... | @@ -71,7 +55,7 @@ |
71 | 55 | "resources": [], |
72 | 56 | "templateHtml": "", |
73 | 57 | "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.pie-label {\n font-size: 12px;\n font-family: 'Roboto';\n font-weight: bold;\n text-align: center;\n padding: 2px;\n color: white;\n}\n", |
74 | - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'pie'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.pieSettingsSchema();\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.pieDatakeySettingsSchema();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\nself.actionSources = function() {\n return {\n 'sliceClick': {\n name: 'widget-action.pie-slice-click',\n multiple: false\n }\n };\n}\n", | |
58 | + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'pie'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.pieSettingsSchema();\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.pieDatakeySettingsSchema();\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\nself.actionSources = function() {\n return {\n 'sliceClick': {\n name: 'widget-action.pie-slice-click',\n multiple: false\n }\n };\n}\n", | |
75 | 59 | "settingsSchema": "{}\n", |
76 | 60 | "dataKeySettingsSchema": "{}\n", |
77 | 61 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.6114638304362894,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.9955906536344441,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.9430835931647599,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"radius\":1,\"fontColor\":\"#545454\",\"fontSize\":10,\"decimals\":1,\"legend\":{\"show\":true,\"position\":\"nw\",\"labelBoxBorderColor\":\"#CCCCCC\",\"backgroundColor\":\"#F0F0F0\",\"backgroundOpacity\":0.85},\"innerRadius\":0,\"showLabels\":true,\"showPercentages\":true,\"stroke\":{\"width\":5},\"tilt\":1,\"animatedPie\":false},\"title\":\"Pie - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400}}" |
... | ... | @@ -138,8 +122,8 @@ |
138 | 122 | } |
139 | 123 | }, |
140 | 124 | { |
141 | - "alias": "timeseries_bars_flot", | |
142 | - "name": "Timeseries Bars - Flot", | |
125 | + "alias": "state_chart", | |
126 | + "name": "State Chart", | |
143 | 127 | "descriptor": { |
144 | 128 | "type": "timeseries", |
145 | 129 | "sizeX": 8, |
... | ... | @@ -147,15 +131,15 @@ |
147 | 131 | "resources": [], |
148 | 132 | "templateHtml": "", |
149 | 133 | "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", |
150 | - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('bar');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false, 'bar');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
134 | + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
151 | 135 | "settingsSchema": "{}", |
152 | 136 | "dataKeySettingsSchema": "{}", |
153 | - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":true,\"tooltipIndividual\":false,\"defaultBarWidth\":600},\"title\":\"Timeseries Bars - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}" | |
137 | + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" | |
154 | 138 | } |
155 | 139 | }, |
156 | 140 | { |
157 | - "alias": "state_chart", | |
158 | - "name": "State Chart", | |
141 | + "alias": "basic_timeseries", | |
142 | + "name": "Timeseries - Flot", | |
159 | 143 | "descriptor": { |
160 | 144 | "type": "timeseries", |
161 | 145 | "sizeX": 8, |
... | ... | @@ -163,11 +147,27 @@ |
163 | 147 | "resources": [], |
164 | 148 | "templateHtml": "", |
165 | 149 | "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", |
166 | - "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'state'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true\n };\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.onMobileModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
150 | + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('graph');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true, 'graph');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
167 | 151 | "settingsSchema": "{}", |
168 | 152 | "dataKeySettingsSchema": "{}", |
169 | - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" | |
153 | + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Timeseries - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" | |
154 | + } | |
155 | + }, | |
156 | + { | |
157 | + "alias": "timeseries_bars_flot", | |
158 | + "name": "Timeseries Bars - Flot", | |
159 | + "descriptor": { | |
160 | + "type": "timeseries", | |
161 | + "sizeX": 8, | |
162 | + "sizeY": 5, | |
163 | + "resources": [], | |
164 | + "templateHtml": "", | |
165 | + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", | |
166 | + "controllerScript": "self.onInit = function() {\n self.ctx.flot = new TbFlot(self.ctx, 'bar'); \n}\n\nself.onDataUpdated = function() {\n self.ctx.flot.update();\n}\n\nself.onResize = function() {\n self.ctx.flot.resize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.flot.checkMouseEvents();\n}\n\nself.getSettingsSchema = function() {\n return TbFlot.settingsSchema('bar');\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false, 'bar');\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
167 | + "settingsSchema": "{}", | |
168 | + "dataKeySettingsSchema": "{}", | |
169 | + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":true,\"tooltipIndividual\":false,\"defaultBarWidth\":600},\"title\":\"Timeseries Bars - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{}}" | |
170 | 170 | } |
171 | 171 | } |
172 | 172 | ] |
173 | -} | |
173 | +} | |
\ No newline at end of file | ... | ... |
1 | +{ | |
2 | + "widgetsBundle": { | |
3 | + "alias": "navigation_widgets", | |
4 | + "title": "Navigation widgets", | |
5 | + "image": null | |
6 | + }, | |
7 | + "widgetTypes": [ | |
8 | + { | |
9 | + "alias": "navigation_cards", | |
10 | + "name": "Navigation cards", | |
11 | + "descriptor": { | |
12 | + "type": "static", | |
13 | + "sizeX": 7, | |
14 | + "sizeY": 6, | |
15 | + "resources": [], | |
16 | + "templateHtml": "<tb-navigation-cards-widget [ctx]=\"ctx\"></tb-navigation-cards-widget>", | |
17 | + "templateCss": "/*#widget-container {\n overflow-y: auto;\n box-sizing: content-box !important;\n cursor: auto;\n}*/\n\n#widget-container #container {\n overflow-y: auto;\n box-sizing: content-box;\n cursor: auto;\n}", | |
18 | + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.navigationCardsWidget.resize();\n}\n\nself.onResize = function() {\n self.ctx.$scope.navigationCardsWidget.resize();\n}\n\nself.onDestroy = function() {\n}\n", | |
19 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"filterType\": {\n \"title\": \"Filter type\",\n \"type\": \"string\",\n \"default\": \"all\"\n },\n \"filter\": {\n \"title\": \"Items\",\n \"type\": \"array\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"filterType\",\n \"type\": \"radios\",\n \"direction\": \"row\",\n \"titleMap\": [\n {\n \"value\": \"all\",\n \"name\": \"All items\"\n },\n {\n \"value\": \"include\",\n \"name\": \"Include items\"\n },\n {\n \"value\": \"exclude\",\n \"name\": \"Exclude items\"\n }\n ]\n },\n {\n \"key\": \"filter\",\n \"type\": \"rc-select\",\n \"condition\": \"model.filterType !== 'all'\",\n \"tags\": true,\n \"placeholder\": \"Enter urls to filter\",\n \"items\": [{\"value\": \"/devices\", \"label\": \"/devices\"}, {\"value\": \"/assets\", \"label\": \"/assets\"}, {\"value\": \"/deviceProfies\", \"label\": \"/deviceProfies\"}]\n }\n ]\n}\n", | |
20 | + "dataKeySettingsSchema": "{}\n", | |
21 | + "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(255,255,255,0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"filterType\":\"all\"},\"title\":\"Navigation cards\",\"dropShadow\":false,\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" | |
22 | + } | |
23 | + }, | |
24 | + { | |
25 | + "alias": "navigation_card", | |
26 | + "name": "Navigation card", | |
27 | + "descriptor": { | |
28 | + "type": "static", | |
29 | + "sizeX": 2.5, | |
30 | + "sizeY": 2, | |
31 | + "resources": [], | |
32 | + "templateHtml": "<tb-navigation-card-widget [ctx]=\"ctx\"></tb-navigation-card-widget>", | |
33 | + "templateCss": "", | |
34 | + "controllerScript": "self.onInit = function() {\n\n}\n\n\nself.onDestroy = function() {\n}\n", | |
35 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"name\": {\n \"title\": \"Title\",\n \"type\": \"string\",\n \"default\": \"{i18n:device.devices}\"\n },\n \"icon\": {\n \"title\": \"icon\",\n \"type\": \"string\",\n \"default\": \"devices_other\"\n },\n \"path\": {\n \"title\": \"Navigation path\",\n \"type\": \"string\",\n \"default\": \"/devices\"\n }\n },\n \"required\": [\"name\", \"icon\", \"path\"]\n },\n \"form\": [\n \"name\",\n {\n \"key\": \"icon\",\n \"type\": \"icon\"\n },\n \"path\"\n ]\n}\n", | |
36 | + "dataKeySettingsSchema": "{}\n", | |
37 | + "defaultConfig": "{\"datasources\":[{\"type\":\"static\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(255,255,255,0)\",\"color\":\"rgba(255,255,255,0.87)\",\"padding\":\"8px\",\"settings\":{\"name\":\"{i18n:device.devices}\",\"icon\":\"devices_other\",\"path\":\"/devices\"},\"title\":\"Navigation card\",\"dropShadow\":false,\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}" | |
38 | + } | |
39 | + } | |
40 | + ] | |
41 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -141,12 +141,12 @@ public class AppActor extends ContextAwareActor { |
141 | 141 | |
142 | 142 | private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) { |
143 | 143 | if (TenantId.SYS_TENANT_ID.equals(msg.getTenantId())) { |
144 | - msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!")); | |
144 | + msg.getMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!")); | |
145 | 145 | } else { |
146 | 146 | if (!deletedTenants.contains(msg.getTenantId())) { |
147 | 147 | getOrCreateTenantActor(msg.getTenantId()).tell(msg); |
148 | 148 | } else { |
149 | - msg.getTbMsg().getCallback().onSuccess(); | |
149 | + msg.getMsg().getCallback().onSuccess(); | |
150 | 150 | } |
151 | 151 | } |
152 | 152 | } | ... | ... |
... | ... | @@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; |
19 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | 20 | import io.netty.channel.EventLoopGroup; |
21 | 21 | import lombok.extern.slf4j.Slf4j; |
22 | -import org.springframework.data.redis.core.RedisTemplate; | |
23 | 22 | import org.springframework.util.StringUtils; |
24 | 23 | import org.thingsboard.common.util.ListeningExecutor; |
25 | 24 | import org.thingsboard.rule.engine.api.MailService; |
... | ... | @@ -92,10 +91,12 @@ class DefaultTbContext implements TbContext { |
92 | 91 | public final static ObjectMapper mapper = new ObjectMapper(); |
93 | 92 | |
94 | 93 | private final ActorSystemContext mainCtx; |
94 | + private final String ruleChainName; | |
95 | 95 | private final RuleNodeCtx nodeCtx; |
96 | 96 | |
97 | - public DefaultTbContext(ActorSystemContext mainCtx, RuleNodeCtx nodeCtx) { | |
97 | + public DefaultTbContext(ActorSystemContext mainCtx, String ruleChainName, RuleNodeCtx nodeCtx) { | |
98 | 98 | this.mainCtx = mainCtx; |
99 | + this.ruleChainName = ruleChainName; | |
99 | 100 | this.nodeCtx = nodeCtx; |
100 | 101 | } |
101 | 102 | |
... | ... | @@ -119,13 +120,13 @@ class DefaultTbContext implements TbContext { |
119 | 120 | relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th)); |
120 | 121 | } |
121 | 122 | msg.getCallback().onProcessingEnd(nodeCtx.getSelf().getId()); |
122 | - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg, th != null ? th.getMessage() : null)); | |
123 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), relationTypes, msg, th != null ? th.getMessage() : null)); | |
123 | 124 | } |
124 | 125 | |
125 | 126 | @Override |
126 | 127 | public void tellSelf(TbMsg msg, long delayMs) { |
127 | 128 | //TODO: add persistence layer |
128 | - scheduleMsgWithDelay(new RuleNodeToSelfMsg(msg), delayMs, nodeCtx.getSelfActor()); | |
129 | + scheduleMsgWithDelay(new RuleNodeToSelfMsg(this, msg), delayMs, nodeCtx.getSelfActor()); | |
129 | 130 | } |
130 | 131 | |
131 | 132 | @Override |
... | ... | @@ -256,7 +257,8 @@ class DefaultTbContext implements TbContext { |
256 | 257 | } else { |
257 | 258 | failureMessage = null; |
258 | 259 | } |
259 | - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), | |
260 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getRuleChainId(), | |
261 | + nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), | |
260 | 262 | msg, failureMessage)); |
261 | 263 | } |
262 | 264 | |
... | ... | @@ -309,6 +311,16 @@ class DefaultTbContext implements TbContext { |
309 | 311 | } |
310 | 312 | |
311 | 313 | @Override |
314 | + public RuleNode getSelf() { | |
315 | + return nodeCtx.getSelf(); | |
316 | + } | |
317 | + | |
318 | + @Override | |
319 | + public String getRuleChainName() { | |
320 | + return ruleChainName; | |
321 | + } | |
322 | + | |
323 | + @Override | |
312 | 324 | public TenantId getTenantId() { |
313 | 325 | return nodeCtx.getTenantId(); |
314 | 326 | } |
... | ... | @@ -493,11 +505,6 @@ class DefaultTbContext implements TbContext { |
493 | 505 | } |
494 | 506 | |
495 | 507 | @Override |
496 | - public RedisTemplate<String, Object> getRedisTemplate() { | |
497 | - return mainCtx.getRedisTemplate(); | |
498 | - } | |
499 | - | |
500 | - @Override | |
501 | 508 | public PageData<RuleNodeState> findRuleNodeStates(PageLink pageLink) { |
502 | 509 | if (log.isDebugEnabled()) { |
503 | 510 | log.debug("[{}][{}] Fetch Rule Node States.", getTenantId(), getSelfId()); | ... | ... |
... | ... | @@ -23,7 +23,6 @@ import org.thingsboard.server.actors.TbActorRef; |
23 | 23 | import org.thingsboard.server.actors.TbEntityActorId; |
24 | 24 | import org.thingsboard.server.actors.service.DefaultActorService; |
25 | 25 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
26 | -import org.thingsboard.server.common.data.ApiUsageRecordKey; | |
27 | 26 | import org.thingsboard.server.common.data.EntityType; |
28 | 27 | import org.thingsboard.server.common.data.id.EntityId; |
29 | 28 | import org.thingsboard.server.common.data.id.RuleChainId; |
... | ... | @@ -37,6 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType; |
37 | 36 | import org.thingsboard.server.common.data.rule.RuleNode; |
38 | 37 | import org.thingsboard.server.common.msg.TbMsg; |
39 | 38 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
39 | +import org.thingsboard.server.common.msg.plugin.RuleNodeUpdatedMsg; | |
40 | 40 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
41 | 41 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
42 | 42 | import org.thingsboard.server.common.msg.queue.RuleEngineException; |
... | ... | @@ -133,7 +133,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
133 | 133 | } else { |
134 | 134 | log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); |
135 | 135 | existing.setSelf(ruleNode); |
136 | - existing.getSelfActor().tellWithHighPriority(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED)); | |
136 | + existing.getSelfActor().tellWithHighPriority(new RuleNodeUpdatedMsg(tenantId, existing.getSelf().getId())); | |
137 | 137 | } |
138 | 138 | } |
139 | 139 | |
... | ... | @@ -198,11 +198,11 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
198 | 198 | } |
199 | 199 | |
200 | 200 | void onQueueToRuleEngineMsg(QueueToRuleEngineMsg envelope) { |
201 | - TbMsg msg = envelope.getTbMsg(); | |
201 | + TbMsg msg = envelope.getMsg(); | |
202 | 202 | log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, msg.getId(), msg); |
203 | 203 | if (envelope.getRelationTypes() == null || envelope.getRelationTypes().isEmpty()) { |
204 | 204 | try { |
205 | - checkActive(envelope.getTbMsg()); | |
205 | + checkActive(envelope.getMsg()); | |
206 | 206 | RuleNodeId targetId = msg.getRuleNodeId(); |
207 | 207 | RuleNodeCtx targetCtx; |
208 | 208 | if (targetId == null) { |
... | ... | @@ -219,12 +219,12 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
219 | 219 | msg.getCallback().onSuccess(); |
220 | 220 | } |
221 | 221 | } catch (RuleNodeException rne) { |
222 | - envelope.getTbMsg().getCallback().onFailure(rne); | |
222 | + envelope.getMsg().getCallback().onFailure(rne); | |
223 | 223 | } catch (Exception e) { |
224 | - envelope.getTbMsg().getCallback().onFailure(new RuleEngineException(e.getMessage())); | |
224 | + envelope.getMsg().getCallback().onFailure(new RuleEngineException(e.getMessage())); | |
225 | 225 | } |
226 | 226 | } else { |
227 | - onTellNext(envelope.getTbMsg(), envelope.getTbMsg().getRuleNodeId(), envelope.getRelationTypes(), envelope.getFailureMessage()); | |
227 | + onTellNext(envelope.getMsg(), envelope.getMsg().getRuleNodeId(), envelope.getRelationTypes(), envelope.getFailureMessage()); | |
228 | 228 | } |
229 | 229 | } |
230 | 230 | |
... | ... | @@ -336,7 +336,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
336 | 336 | |
337 | 337 | private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) { |
338 | 338 | if (nodeCtx != null) { |
339 | - nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg, fromRelationType)); | |
339 | + nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, ruleChainName, nodeCtx), msg, fromRelationType)); | |
340 | 340 | } else { |
341 | 341 | log.error("[{}][{}] RuleNodeCtx is empty", entityId, ruleChainName); |
342 | 342 | msg.getCallback().onFailure(new RuleEngineException("Rule Node CTX is empty")); | ... | ... |
... | ... | @@ -15,24 +15,44 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import lombok.Data; | |
18 | +import lombok.EqualsAndHashCode; | |
19 | +import lombok.Getter; | |
20 | +import lombok.ToString; | |
19 | 21 | import org.thingsboard.server.common.data.id.RuleChainId; |
20 | 22 | import org.thingsboard.server.common.msg.MsgType; |
21 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
23 | +import org.thingsboard.server.common.msg.TbActorStopReason; | |
22 | 24 | import org.thingsboard.server.common.msg.TbMsg; |
25 | +import org.thingsboard.server.common.msg.TbRuleEngineActorMsg; | |
23 | 26 | import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; |
27 | +import org.thingsboard.server.common.msg.queue.RuleEngineException; | |
24 | 28 | |
25 | 29 | /** |
26 | 30 | * Created by ashvayka on 19.03.18. |
27 | 31 | */ |
28 | -@Data | |
29 | -public final class RuleChainToRuleChainMsg implements TbActorMsg, RuleChainAwareMsg { | |
32 | +@EqualsAndHashCode(callSuper = true) | |
33 | +@ToString | |
34 | +public final class RuleChainToRuleChainMsg extends TbRuleEngineActorMsg implements RuleChainAwareMsg { | |
30 | 35 | |
36 | + @Getter | |
31 | 37 | private final RuleChainId target; |
38 | + @Getter | |
32 | 39 | private final RuleChainId source; |
33 | - private final TbMsg msg; | |
40 | + @Getter | |
34 | 41 | private final String fromRelationType; |
35 | 42 | |
43 | + public RuleChainToRuleChainMsg(RuleChainId target, RuleChainId source, TbMsg tbMsg, String fromRelationType) { | |
44 | + super(tbMsg); | |
45 | + this.target = target; | |
46 | + this.source = source; | |
47 | + this.fromRelationType = fromRelationType; | |
48 | + } | |
49 | + | |
50 | + @Override | |
51 | + public void onTbActorStopped(TbActorStopReason reason) { | |
52 | + String message = reason == TbActorStopReason.STOPPED ? String.format("Rule chain [%s] stopped", target.getId()) : String.format("Failed to initialize rule chain [%s]!", target.getId()); | |
53 | + msg.getCallback().onFailure(new RuleEngineException(message)); | |
54 | + } | |
55 | + | |
36 | 56 | @Override |
37 | 57 | public RuleChainId getRuleChainId() { |
38 | 58 | return target; | ... | ... |
... | ... | @@ -15,22 +15,28 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import lombok.Data; | |
18 | +import lombok.EqualsAndHashCode; | |
19 | +import lombok.Getter; | |
20 | +import lombok.ToString; | |
19 | 21 | import org.thingsboard.rule.engine.api.TbContext; |
20 | 22 | import org.thingsboard.server.common.msg.MsgType; |
21 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
22 | 23 | import org.thingsboard.server.common.msg.TbMsg; |
23 | 24 | |
24 | 25 | /** |
25 | 26 | * Created by ashvayka on 19.03.18. |
26 | 27 | */ |
27 | -@Data | |
28 | -final class RuleChainToRuleNodeMsg implements TbActorMsg { | |
28 | +@EqualsAndHashCode(callSuper = true) | |
29 | +@ToString | |
30 | +final class RuleChainToRuleNodeMsg extends TbToRuleNodeActorMsg { | |
29 | 31 | |
30 | - private final TbContext ctx; | |
31 | - private final TbMsg msg; | |
32 | + @Getter | |
32 | 33 | private final String fromRelationType; |
33 | 34 | |
35 | + public RuleChainToRuleNodeMsg(TbContext ctx, TbMsg tbMsg, String fromRelationType) { | |
36 | + super(ctx, tbMsg); | |
37 | + this.fromRelationType = fromRelationType; | |
38 | + } | |
39 | + | |
34 | 40 | @Override |
35 | 41 | public MsgType getMsgType() { |
36 | 42 | return MsgType.RULE_CHAIN_TO_RULE_MSG; | ... | ... |
... | ... | @@ -26,7 +26,6 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; |
26 | 26 | import org.thingsboard.server.common.data.id.RuleChainId; |
27 | 27 | import org.thingsboard.server.common.data.id.RuleNodeId; |
28 | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | -import org.thingsboard.server.common.data.rule.RuleChain; | |
30 | 29 | import org.thingsboard.server.common.msg.TbActorMsg; |
31 | 30 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
32 | 31 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
... | ... | @@ -54,14 +53,12 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa |
54 | 53 | protected boolean doProcess(TbActorMsg msg) { |
55 | 54 | switch (msg.getMsgType()) { |
56 | 55 | case COMPONENT_LIFE_CYCLE_MSG: |
56 | + case RULE_NODE_UPDATED_MSG: | |
57 | 57 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
58 | 58 | break; |
59 | 59 | case RULE_CHAIN_TO_RULE_MSG: |
60 | 60 | onRuleChainToRuleNodeMsg((RuleChainToRuleNodeMsg) msg); |
61 | 61 | break; |
62 | - case RULE_TO_SELF_ERROR_MSG: | |
63 | - onRuleNodeToSelfErrorMsg((RuleNodeToSelfErrorMsg) msg); | |
64 | - break; | |
65 | 62 | case RULE_TO_SELF_MSG: |
66 | 63 | onRuleNodeToSelfMsg((RuleNodeToSelfMsg) msg); |
67 | 64 | break; |
... | ... | @@ -101,10 +98,6 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa |
101 | 98 | } |
102 | 99 | } |
103 | 100 | |
104 | - private void onRuleNodeToSelfErrorMsg(RuleNodeToSelfErrorMsg msg) { | |
105 | - logAndPersist("onRuleMsg", ActorSystemContext.toException(msg.getError())); | |
106 | - } | |
107 | - | |
108 | 101 | public static class ActorCreator extends ContextBasedCreator { |
109 | 102 | |
110 | 103 | private final TenantId tenantId; | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
... | ... | @@ -20,14 +20,13 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
20 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | 21 | import org.thingsboard.server.actors.TbActorCtx; |
22 | 22 | import org.thingsboard.server.actors.TbActorRef; |
23 | +import org.thingsboard.server.actors.TbRuleNodeUpdateException; | |
23 | 24 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
24 | 25 | import org.thingsboard.server.common.data.ApiUsageRecordKey; |
25 | -import org.thingsboard.server.common.data.TenantProfile; | |
26 | 26 | import org.thingsboard.server.common.data.id.RuleNodeId; |
27 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
28 | 28 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
29 | 29 | import org.thingsboard.server.common.data.rule.RuleNode; |
30 | -import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration; | |
31 | 30 | import org.thingsboard.server.common.msg.TbMsg; |
32 | 31 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
33 | 32 | import org.thingsboard.server.common.msg.queue.RuleNodeException; |
... | ... | @@ -54,7 +53,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
54 | 53 | this.ruleChainName = ruleChainName; |
55 | 54 | this.self = self; |
56 | 55 | this.ruleNode = systemContext.getRuleChainService().findRuleNodeById(tenantId, entityId); |
57 | - this.defaultCtx = new DefaultTbContext(systemContext, new RuleNodeCtx(tenantId, parent, self, ruleNode)); | |
56 | + this.defaultCtx = new DefaultTbContext(systemContext, ruleChainName, new RuleNodeCtx(tenantId, parent, self, ruleNode)); | |
58 | 57 | this.info = new RuleNodeInfo(ruleNodeId, ruleChainName, ruleNode != null ? ruleNode.getName() : "Unknown"); |
59 | 58 | } |
60 | 59 | |
... | ... | @@ -78,7 +77,11 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
78 | 77 | if (tbNode != null) { |
79 | 78 | tbNode.destroy(); |
80 | 79 | } |
81 | - start(context); | |
80 | + try { | |
81 | + start(context); | |
82 | + } catch (Exception e) { | |
83 | + throw new TbRuleNodeUpdateException("Failed to update rule node", e); | |
84 | + } | |
82 | 85 | } |
83 | 86 | } |
84 | 87 | |
... | ... | @@ -147,7 +150,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
147 | 150 | TbNode tbNode = null; |
148 | 151 | if (ruleNode != null) { |
149 | 152 | Class<?> componentClazz = Class.forName(ruleNode.getType()); |
150 | - tbNode = (TbNode) (componentClazz.newInstance()); | |
153 | + tbNode = (TbNode) (componentClazz.getDeclaredConstructor().newInstance()); | |
151 | 154 | tbNode.init(defaultCtx, new TbNodeConfiguration(ruleNode.getConfiguration())); |
152 | 155 | } |
153 | 156 | return tbNode; | ... | ... |
... | ... | @@ -15,11 +15,16 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import lombok.Data; | |
18 | +import lombok.EqualsAndHashCode; | |
19 | +import lombok.Getter; | |
20 | +import lombok.ToString; | |
21 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
19 | 22 | import org.thingsboard.server.common.data.id.RuleNodeId; |
20 | 23 | import org.thingsboard.server.common.msg.MsgType; |
21 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
24 | +import org.thingsboard.server.common.msg.TbActorStopReason; | |
22 | 25 | import org.thingsboard.server.common.msg.TbMsg; |
26 | +import org.thingsboard.server.common.msg.TbRuleEngineActorMsg; | |
27 | +import org.thingsboard.server.common.msg.queue.RuleEngineException; | |
23 | 28 | |
24 | 29 | import java.io.Serializable; |
25 | 30 | import java.util.Set; |
... | ... | @@ -27,15 +32,34 @@ import java.util.Set; |
27 | 32 | /** |
28 | 33 | * Created by ashvayka on 19.03.18. |
29 | 34 | */ |
30 | -@Data | |
31 | -class RuleNodeToRuleChainTellNextMsg implements TbActorMsg, Serializable { | |
35 | +@EqualsAndHashCode(callSuper = true) | |
36 | +@ToString | |
37 | +class RuleNodeToRuleChainTellNextMsg extends TbRuleEngineActorMsg implements Serializable { | |
32 | 38 | |
33 | 39 | private static final long serialVersionUID = 4577026446412871820L; |
40 | + @Getter | |
41 | + private final RuleChainId ruleChainId; | |
42 | + @Getter | |
34 | 43 | private final RuleNodeId originator; |
44 | + @Getter | |
35 | 45 | private final Set<String> relationTypes; |
36 | - private final TbMsg msg; | |
46 | + @Getter | |
37 | 47 | private final String failureMessage; |
38 | 48 | |
49 | + public RuleNodeToRuleChainTellNextMsg(RuleChainId ruleChainId, RuleNodeId originator, Set<String> relationTypes, TbMsg tbMsg, String failureMessage) { | |
50 | + super(tbMsg); | |
51 | + this.ruleChainId = ruleChainId; | |
52 | + this.originator = originator; | |
53 | + this.relationTypes = relationTypes; | |
54 | + this.failureMessage = failureMessage; | |
55 | + } | |
56 | + | |
57 | + @Override | |
58 | + public void onTbActorStopped(TbActorStopReason reason) { | |
59 | + String message = reason == TbActorStopReason.STOPPED ? String.format("Rule chain [%s] stopped", ruleChainId.getId()) : String.format("Failed to initialize rule chain [%s]!", ruleChainId.getId()); | |
60 | + msg.getCallback().onFailure(new RuleEngineException(message)); | |
61 | + } | |
62 | + | |
39 | 63 | @Override |
40 | 64 | public MsgType getMsgType() { |
41 | 65 | return MsgType.RULE_TO_RULE_CHAIN_TELL_NEXT_MSG; | ... | ... |
... | ... | @@ -15,18 +15,25 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import lombok.Data; | |
18 | +import lombok.EqualsAndHashCode; | |
19 | +import lombok.ToString; | |
20 | +import org.thingsboard.rule.engine.api.TbContext; | |
19 | 21 | import org.thingsboard.server.common.msg.MsgType; |
20 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
22 | +import org.thingsboard.server.common.msg.TbActorStopReason; | |
21 | 23 | import org.thingsboard.server.common.msg.TbMsg; |
24 | +import org.thingsboard.server.common.msg.TbRuleEngineActorMsg; | |
25 | +import org.thingsboard.server.common.msg.queue.RuleNodeException; | |
22 | 26 | |
23 | 27 | /** |
24 | 28 | * Created by ashvayka on 19.03.18. |
25 | 29 | */ |
26 | -@Data | |
27 | -final class RuleNodeToSelfMsg implements TbActorMsg { | |
30 | +@EqualsAndHashCode(callSuper = true) | |
31 | +@ToString | |
32 | +final class RuleNodeToSelfMsg extends TbToRuleNodeActorMsg { | |
28 | 33 | |
29 | - private final TbMsg msg; | |
34 | + public RuleNodeToSelfMsg(TbContext ctx, TbMsg tbMsg) { | |
35 | + super(ctx, tbMsg); | |
36 | + } | |
30 | 37 | |
31 | 38 | @Override |
32 | 39 | public MsgType getMsgType() { | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/TbToRuleNodeActorMsg.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import lombok.EqualsAndHashCode; | |
19 | +import lombok.Getter; | |
20 | +import org.thingsboard.rule.engine.api.TbContext; | |
21 | +import org.thingsboard.server.common.msg.TbActorStopReason; | |
22 | +import org.thingsboard.server.common.msg.TbMsg; | |
23 | +import org.thingsboard.server.common.msg.TbRuleEngineActorMsg; | |
24 | +import org.thingsboard.server.common.msg.queue.RuleNodeException; | |
25 | + | |
26 | +@EqualsAndHashCode(callSuper = true) | |
27 | +public abstract class TbToRuleNodeActorMsg extends TbRuleEngineActorMsg { | |
28 | + | |
29 | + @Getter | |
30 | + private final TbContext ctx; | |
31 | + | |
32 | + public TbToRuleNodeActorMsg(TbContext ctx, TbMsg tbMsg) { | |
33 | + super(tbMsg); | |
34 | + this.ctx = ctx; | |
35 | + } | |
36 | + | |
37 | + @Override | |
38 | + public void onTbActorStopped(TbActorStopReason reason) { | |
39 | + String message = reason == TbActorStopReason.STOPPED ? "Rule node stopped" : "Failed to initialize rule node!"; | |
40 | + msg.getCallback().onFailure(new RuleNodeException(message, ctx.getRuleChainName(), ctx.getSelf())); | |
41 | + } | |
42 | +} | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import org.thingsboard.server.actors.ActorSystemContext; |
20 | 20 | import org.thingsboard.server.actors.TbActor; |
21 | 21 | import org.thingsboard.server.actors.TbActorCtx; |
22 | 22 | import org.thingsboard.server.actors.TbActorException; |
23 | +import org.thingsboard.server.actors.TbRuleNodeUpdateException; | |
23 | 24 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
24 | 25 | import org.thingsboard.server.actors.stats.StatsPersistMsg; |
25 | 26 | import org.thingsboard.server.common.data.id.EntityId; |
... | ... | @@ -123,6 +124,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
123 | 124 | } catch (Exception e) { |
124 | 125 | logAndPersist("onLifecycleMsg", e, true); |
125 | 126 | logLifecycleEvent(msg.getEvent(), e); |
127 | + if (e instanceof TbRuleNodeUpdateException) { | |
128 | + throw (TbRuleNodeUpdateException) e; | |
129 | + } | |
126 | 130 | } |
127 | 131 | } |
128 | 132 | ... | ... |
... | ... | @@ -34,6 +34,7 @@ import org.thingsboard.server.actors.app.AppInitMsg; |
34 | 34 | import org.thingsboard.server.actors.stats.StatsActor; |
35 | 35 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
36 | 36 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; |
37 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
37 | 38 | |
38 | 39 | import javax.annotation.PostConstruct; |
39 | 40 | import javax.annotation.PreDestroy; |
... | ... | @@ -43,7 +44,7 @@ import java.util.concurrent.ScheduledExecutorService; |
43 | 44 | |
44 | 45 | @Service |
45 | 46 | @Slf4j |
46 | -public class DefaultActorService implements ActorService { | |
47 | +public class DefaultActorService extends TbApplicationEventListener<PartitionChangeEvent> implements ActorService { | |
47 | 48 | |
48 | 49 | public static final String APP_DISPATCHER_NAME = "app-dispatcher"; |
49 | 50 | public static final String TENANT_DISPATCHER_NAME = "tenant-dispatcher"; |
... | ... | @@ -120,10 +121,10 @@ public class DefaultActorService implements ActorService { |
120 | 121 | appActor.tellWithHighPriority(new AppInitMsg()); |
121 | 122 | } |
122 | 123 | |
123 | - @EventListener(PartitionChangeEvent.class) | |
124 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
124 | + @Override | |
125 | + protected void onTbApplicationEvent(PartitionChangeEvent event) { | |
125 | 126 | log.info("Received partition change event."); |
126 | - this.appActor.tellWithHighPriority(new PartitionChangeMsg(partitionChangeEvent.getServiceQueueKey(), partitionChangeEvent.getPartitions())); | |
127 | + this.appActor.tellWithHighPriority(new PartitionChangeMsg(event.getServiceQueueKey(), event.getPartitions())); | |
127 | 128 | } |
128 | 129 | |
129 | 130 | @PreDestroy | ... | ... |
... | ... | @@ -28,10 +28,10 @@ import org.thingsboard.server.common.msg.TbActorMsg; |
28 | 28 | @ToString |
29 | 29 | public final class StatsPersistMsg implements TbActorMsg { |
30 | 30 | |
31 | - private long messagesProcessed; | |
32 | - private long errorsOccurred; | |
33 | - private TenantId tenantId; | |
34 | - private EntityId entityId; | |
31 | + private final long messagesProcessed; | |
32 | + private final long errorsOccurred; | |
33 | + private final TenantId tenantId; | |
34 | + private final EntityId entityId; | |
35 | 35 | |
36 | 36 | @Override |
37 | 37 | public MsgType getMsgType() { | ... | ... |
... | ... | @@ -18,7 +18,7 @@ package org.thingsboard.server.actors.stats; |
18 | 18 | import org.thingsboard.server.common.msg.MsgType; |
19 | 19 | import org.thingsboard.server.common.msg.TbActorMsg; |
20 | 20 | |
21 | -public final class StatsPersistTick implements TbActorMsg{ | |
21 | +public final class StatsPersistTick implements TbActorMsg { | |
22 | 22 | @Override |
23 | 23 | public MsgType getMsgType() { |
24 | 24 | return MsgType.STATS_PERSIST_TICK_MSG; | ... | ... |
... | ... | @@ -125,7 +125,7 @@ public class TenantActor extends RuleChainManagerActor { |
125 | 125 | log.info("[{}] Processing missing Tenant msg: {}", tenantId, msg); |
126 | 126 | if (msg.getMsgType().equals(MsgType.QUEUE_TO_RULE_ENGINE_MSG)) { |
127 | 127 | QueueToRuleEngineMsg queueMsg = (QueueToRuleEngineMsg) msg; |
128 | - queueMsg.getTbMsg().getCallback().onSuccess(); | |
128 | + queueMsg.getMsg().getCallback().onSuccess(); | |
129 | 129 | } else if (msg.getMsgType().equals(MsgType.TRANSPORT_TO_DEVICE_ACTOR_MSG)) { |
130 | 130 | TransportToDeviceActorMsgWrapper transportMsg = (TransportToDeviceActorMsgWrapper) msg; |
131 | 131 | transportMsg.getCallback().onSuccess(); |
... | ... | @@ -188,7 +188,7 @@ public class TenantActor extends RuleChainManagerActor { |
188 | 188 | log.warn("RECEIVED INVALID MESSAGE: {}", msg); |
189 | 189 | return; |
190 | 190 | } |
191 | - TbMsg tbMsg = msg.getTbMsg(); | |
191 | + TbMsg tbMsg = msg.getMsg(); | |
192 | 192 | if (apiUsageState.isReExecEnabled()) { |
193 | 193 | if (tbMsg.getRuleChainId() == null) { |
194 | 194 | if (getRootChainActor() != null) { | ... | ... |
... | ... | @@ -91,6 +91,7 @@ public class CustomOAuth2AuthorizationRequestResolver implements OAuth2Authoriza |
91 | 91 | return action; |
92 | 92 | } |
93 | 93 | |
94 | + @SuppressWarnings("deprecation") | |
94 | 95 | private OAuth2AuthorizationRequest resolve(HttpServletRequest request, String registrationId, String redirectUriAction) { |
95 | 96 | if (registrationId == null) { |
96 | 97 | return null; | ... | ... |
... | ... | @@ -127,7 +127,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
127 | 127 | } |
128 | 128 | |
129 | 129 | protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception { |
130 | - List<String> pathsToSkip = new ArrayList(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); | |
130 | + List<String> pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS)); | |
131 | 131 | pathsToSkip.addAll(Arrays.asList(WS_TOKEN_BASED_AUTH_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT, |
132 | 132 | PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT)); |
133 | 133 | SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT); | ... | ... |
... | ... | @@ -152,6 +152,9 @@ public abstract class BaseController { |
152 | 152 | public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; |
153 | 153 | public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!"; |
154 | 154 | |
155 | + protected static final String DEFAULT_DASHBOARD = "defaultDashboardId"; | |
156 | + protected static final String HOME_DASHBOARD = "homeDashboardId"; | |
157 | + | |
155 | 158 | private static final ObjectMapper json = new ObjectMapper(); |
156 | 159 | |
157 | 160 | @Autowired |
... | ... | @@ -719,6 +722,7 @@ public abstract class BaseController { |
719 | 722 | return ruleNode; |
720 | 723 | } |
721 | 724 | |
725 | + @SuppressWarnings("unchecked") | |
722 | 726 | protected <I extends EntityId> I emptyId(EntityType entityType) { |
723 | 727 | return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); |
724 | 728 | } |
... | ... | @@ -849,8 +853,9 @@ public abstract class BaseController { |
849 | 853 | entityNode = json.createObjectNode(); |
850 | 854 | if (actionType == ActionType.ATTRIBUTES_UPDATED) { |
851 | 855 | String scope = extractParameter(String.class, 0, additionalInfo); |
856 | + @SuppressWarnings("unchecked") | |
852 | 857 | List<AttributeKvEntry> attributes = extractParameter(List.class, 1, additionalInfo); |
853 | - metaData.putValue("scope", scope); | |
858 | + metaData.putValue(DataConstants.SCOPE, scope); | |
854 | 859 | if (attributes != null) { |
855 | 860 | for (AttributeKvEntry attr : attributes) { |
856 | 861 | addKvEntry(entityNode, attr); |
... | ... | @@ -858,16 +863,19 @@ public abstract class BaseController { |
858 | 863 | } |
859 | 864 | } else if (actionType == ActionType.ATTRIBUTES_DELETED) { |
860 | 865 | String scope = extractParameter(String.class, 0, additionalInfo); |
866 | + @SuppressWarnings("unchecked") | |
861 | 867 | List<String> keys = extractParameter(List.class, 1, additionalInfo); |
862 | - metaData.putValue("scope", scope); | |
868 | + metaData.putValue(DataConstants.SCOPE, scope); | |
863 | 869 | ArrayNode attrsArrayNode = entityNode.putArray("attributes"); |
864 | 870 | if (keys != null) { |
865 | 871 | keys.forEach(attrsArrayNode::add); |
866 | 872 | } |
867 | 873 | } else if (actionType == ActionType.TIMESERIES_UPDATED) { |
874 | + @SuppressWarnings("unchecked") | |
868 | 875 | List<TsKvEntry> timeseries = extractParameter(List.class, 0, additionalInfo); |
869 | 876 | addTimeseries(entityNode, timeseries); |
870 | 877 | } else if (actionType == ActionType.TIMESERIES_DELETED) { |
878 | + @SuppressWarnings("unchecked") | |
871 | 879 | List<String> keys = extractParameter(List.class, 0, additionalInfo); |
872 | 880 | if (keys != null) { |
873 | 881 | ArrayNode timeseriesArrayNode = entityNode.putArray("timeseries"); |
... | ... | @@ -1030,4 +1038,14 @@ public abstract class BaseController { |
1030 | 1038 | } |
1031 | 1039 | } |
1032 | 1040 | } |
1041 | + | |
1042 | + protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException { | |
1043 | + String dashboardId = additionalInfo.has(requiredFields) ? additionalInfo.get(requiredFields).asText() : null; | |
1044 | + if(dashboardId != null && !dashboardId.equals("null")) { | |
1045 | + if(dashboardService.findDashboardById(getTenantId(), new DashboardId(UUID.fromString(dashboardId))) == null) { | |
1046 | + additionalInfo.remove(requiredFields); | |
1047 | + } | |
1048 | + } | |
1049 | + } | |
1050 | + | |
1033 | 1051 | } | ... | ... |
... | ... | @@ -59,7 +59,11 @@ public class CustomerController extends BaseController { |
59 | 59 | checkParameter(CUSTOMER_ID, strCustomerId); |
60 | 60 | try { |
61 | 61 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
62 | - return checkCustomerId(customerId, Operation.READ); | |
62 | + Customer customer = checkCustomerId(customerId, Operation.READ); | |
63 | + if(!customer.getAdditionalInfo().isNull()) { | |
64 | + processDashboardIdFromAdditionalInfo((ObjectNode) customer.getAdditionalInfo(), HOME_DASHBOARD); | |
65 | + } | |
66 | + return customer; | |
63 | 67 | } catch (Exception e) { |
64 | 68 | throw handleException(e); |
65 | 69 | } | ... | ... |
... | ... | @@ -15,6 +15,8 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
18 | 20 | import org.springframework.beans.factory.annotation.Value; |
19 | 21 | import org.springframework.http.HttpStatus; |
20 | 22 | import org.springframework.security.access.prepost.PreAuthorize; |
... | ... | @@ -30,7 +32,11 @@ import org.thingsboard.server.common.data.Customer; |
30 | 32 | import org.thingsboard.server.common.data.Dashboard; |
31 | 33 | import org.thingsboard.server.common.data.DashboardInfo; |
32 | 34 | import org.thingsboard.server.common.data.EntityType; |
35 | +import org.thingsboard.server.common.data.HomeDashboard; | |
36 | +import org.thingsboard.server.common.data.HomeDashboardInfo; | |
33 | 37 | import org.thingsboard.server.common.data.ShortCustomerInfo; |
38 | +import org.thingsboard.server.common.data.Tenant; | |
39 | +import org.thingsboard.server.common.data.User; | |
34 | 40 | import org.thingsboard.server.common.data.audit.ActionType; |
35 | 41 | import org.thingsboard.server.common.data.edge.Edge; |
36 | 42 | import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
... | ... | @@ -42,7 +48,9 @@ import org.thingsboard.server.common.data.id.TenantId; |
42 | 48 | import org.thingsboard.server.common.data.page.PageData; |
43 | 49 | import org.thingsboard.server.common.data.page.PageLink; |
44 | 50 | import org.thingsboard.server.common.data.page.TimePageLink; |
51 | +import org.thingsboard.server.dao.util.mapping.JacksonUtil; | |
45 | 52 | import org.thingsboard.server.queue.util.TbCoreComponent; |
53 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
46 | 54 | import org.thingsboard.server.service.security.permission.Operation; |
47 | 55 | import org.thingsboard.server.service.security.permission.Resource; |
48 | 56 | |
... | ... | @@ -58,6 +66,9 @@ public class DashboardController extends BaseController { |
58 | 66 | |
59 | 67 | public static final String DASHBOARD_ID = "dashboardId"; |
60 | 68 | |
69 | + private static final String HOME_DASHBOARD_ID = "homeDashboardId"; | |
70 | + private static final String HOME_DASHBOARD_HIDE_TOOLBAR = "homeDashboardHideToolbar"; | |
71 | + | |
61 | 72 | @Value("${dashboard.max_datapoints_limit}") |
62 | 73 | private long maxDatapointsLimit; |
63 | 74 | |
... | ... | @@ -491,6 +502,102 @@ public class DashboardController extends BaseController { |
491 | 502 | } |
492 | 503 | } |
493 | 504 | |
505 | + @PreAuthorize("isAuthenticated()") | |
506 | + @RequestMapping(value = "/dashboard/home", method = RequestMethod.GET) | |
507 | + @ResponseBody | |
508 | + public HomeDashboard getHomeDashboard() throws ThingsboardException { | |
509 | + try { | |
510 | + SecurityUser securityUser = getCurrentUser(); | |
511 | + if (securityUser.isSystemAdmin()) { | |
512 | + return null; | |
513 | + } | |
514 | + User user = userService.findUserById(securityUser.getTenantId(), securityUser.getId()); | |
515 | + JsonNode additionalInfo = user.getAdditionalInfo(); | |
516 | + HomeDashboard homeDashboard; | |
517 | + homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo); | |
518 | + if (homeDashboard == null) { | |
519 | + if (securityUser.isCustomerUser()) { | |
520 | + Customer customer = customerService.findCustomerById(securityUser.getTenantId(), securityUser.getCustomerId()); | |
521 | + additionalInfo = customer.getAdditionalInfo(); | |
522 | + homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo); | |
523 | + } | |
524 | + if (homeDashboard == null) { | |
525 | + Tenant tenant = tenantService.findTenantById(securityUser.getTenantId()); | |
526 | + additionalInfo = tenant.getAdditionalInfo(); | |
527 | + homeDashboard = extractHomeDashboardFromAdditionalInfo(additionalInfo); | |
528 | + } | |
529 | + } | |
530 | + return homeDashboard; | |
531 | + } catch (Exception e) { | |
532 | + throw handleException(e); | |
533 | + } | |
534 | + } | |
535 | + | |
536 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
537 | + @RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.GET) | |
538 | + @ResponseBody | |
539 | + public HomeDashboardInfo getTenantHomeDashboardInfo() throws ThingsboardException { | |
540 | + try { | |
541 | + Tenant tenant = tenantService.findTenantById(getTenantId()); | |
542 | + JsonNode additionalInfo = tenant.getAdditionalInfo(); | |
543 | + DashboardId dashboardId = null; | |
544 | + boolean hideDashboardToolbar = true; | |
545 | + if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID) && !additionalInfo.get(HOME_DASHBOARD_ID).isNull()) { | |
546 | + String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText(); | |
547 | + dashboardId = new DashboardId(toUUID(strDashboardId)); | |
548 | + if (additionalInfo.has(HOME_DASHBOARD_HIDE_TOOLBAR)) { | |
549 | + hideDashboardToolbar = additionalInfo.get(HOME_DASHBOARD_HIDE_TOOLBAR).asBoolean(); | |
550 | + } | |
551 | + } | |
552 | + return new HomeDashboardInfo(dashboardId, hideDashboardToolbar); | |
553 | + } catch (Exception e) { | |
554 | + throw handleException(e); | |
555 | + } | |
556 | + } | |
557 | + | |
558 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
559 | + @RequestMapping(value = "/tenant/dashboard/home/info", method = RequestMethod.POST) | |
560 | + @ResponseStatus(value = HttpStatus.OK) | |
561 | + public void setTenantHomeDashboardInfo(@RequestBody HomeDashboardInfo homeDashboardInfo) throws ThingsboardException { | |
562 | + try { | |
563 | + if (homeDashboardInfo.getDashboardId() != null) { | |
564 | + checkDashboardId(homeDashboardInfo.getDashboardId(), Operation.READ); | |
565 | + } | |
566 | + Tenant tenant = tenantService.findTenantById(getTenantId()); | |
567 | + JsonNode additionalInfo = tenant.getAdditionalInfo(); | |
568 | + if (additionalInfo == null || !(additionalInfo instanceof ObjectNode)) { | |
569 | + additionalInfo = JacksonUtil.OBJECT_MAPPER.createObjectNode(); | |
570 | + } | |
571 | + if (homeDashboardInfo.getDashboardId() != null) { | |
572 | + ((ObjectNode) additionalInfo).put(HOME_DASHBOARD_ID, homeDashboardInfo.getDashboardId().getId().toString()); | |
573 | + ((ObjectNode) additionalInfo).put(HOME_DASHBOARD_HIDE_TOOLBAR, homeDashboardInfo.isHideDashboardToolbar()); | |
574 | + } else { | |
575 | + ((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_ID); | |
576 | + ((ObjectNode) additionalInfo).remove(HOME_DASHBOARD_HIDE_TOOLBAR); | |
577 | + } | |
578 | + tenant.setAdditionalInfo(additionalInfo); | |
579 | + tenantService.saveTenant(tenant); | |
580 | + } catch (Exception e) { | |
581 | + throw handleException(e); | |
582 | + } | |
583 | + } | |
584 | + | |
585 | + private HomeDashboard extractHomeDashboardFromAdditionalInfo(JsonNode additionalInfo) { | |
586 | + try { | |
587 | + if (additionalInfo != null && additionalInfo.has(HOME_DASHBOARD_ID) && !additionalInfo.get(HOME_DASHBOARD_ID).isNull()) { | |
588 | + String strDashboardId = additionalInfo.get(HOME_DASHBOARD_ID).asText(); | |
589 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | |
590 | + Dashboard dashboard = checkDashboardId(dashboardId, Operation.READ); | |
591 | + boolean hideDashboardToolbar = true; | |
592 | + if (additionalInfo.has(HOME_DASHBOARD_HIDE_TOOLBAR)) { | |
593 | + hideDashboardToolbar = additionalInfo.get(HOME_DASHBOARD_HIDE_TOOLBAR).asBoolean(); | |
594 | + } | |
595 | + return new HomeDashboard(dashboard, hideDashboardToolbar); | |
596 | + } | |
597 | + } catch (Exception e) {} | |
598 | + return null; | |
599 | + } | |
600 | + | |
494 | 601 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
495 | 602 | @RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.POST) |
496 | 603 | @ResponseBody | ... | ... |
... | ... | @@ -73,7 +73,7 @@ import java.util.List; |
73 | 73 | import java.util.concurrent.ExecutionException; |
74 | 74 | import java.util.stream.Collectors; |
75 | 75 | |
76 | -import static org.apache.commons.lang.StringUtils.isBlank; | |
76 | +import static org.apache.commons.lang3.StringUtils.isBlank; | |
77 | 77 | import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; |
78 | 78 | import static org.thingsboard.server.controller.EdgeController.EDGE_ID; |
79 | 79 | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
18 | 19 | import lombok.extern.slf4j.Slf4j; |
19 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
20 | 21 | import org.springframework.http.HttpStatus; |
... | ... | @@ -59,7 +60,11 @@ public class TenantController extends BaseController { |
59 | 60 | checkParameter("tenantId", strTenantId); |
60 | 61 | try { |
61 | 62 | TenantId tenantId = new TenantId(toUUID(strTenantId)); |
62 | - return checkTenantId(tenantId, Operation.READ); | |
63 | + Tenant tenant = checkTenantId(tenantId, Operation.READ); | |
64 | + if(!tenant.getAdditionalInfo().isNull()) { | |
65 | + processDashboardIdFromAdditionalInfo((ObjectNode) tenant.getAdditionalInfo(), HOME_DASHBOARD); | |
66 | + } | |
67 | + return tenant; | |
63 | 68 | } catch (Exception e) { |
64 | 69 | throw handleException(e); |
65 | 70 | } | ... | ... |
... | ... | @@ -92,7 +92,12 @@ public class UserController extends BaseController { |
92 | 92 | checkParameter(USER_ID, strUserId); |
93 | 93 | try { |
94 | 94 | UserId userId = new UserId(toUUID(strUserId)); |
95 | - return checkUserId(userId, Operation.READ); | |
95 | + User user = checkUserId(userId, Operation.READ); | |
96 | + if(!user.getAdditionalInfo().isNull()) { | |
97 | + processDashboardIdFromAdditionalInfo((ObjectNode) user.getAdditionalInfo(), DEFAULT_DASHBOARD); | |
98 | + processDashboardIdFromAdditionalInfo((ObjectNode) user.getAdditionalInfo(), HOME_DASHBOARD); | |
99 | + } | |
100 | + return user; | |
96 | 101 | } catch (Exception e) { |
97 | 102 | throw handleException(e); |
98 | 103 | } |
... | ... | @@ -339,4 +344,5 @@ public class UserController extends BaseController { |
339 | 344 | throw handleException(e); |
340 | 345 | } |
341 | 346 | } |
347 | + | |
342 | 348 | } | ... | ... |
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
... | ... | @@ -54,6 +54,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; |
54 | 54 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
55 | 55 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; |
56 | 56 | import org.thingsboard.server.queue.discovery.PartitionService; |
57 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
57 | 58 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; |
58 | 59 | import org.thingsboard.server.service.queue.TbClusterService; |
59 | 60 | import org.thingsboard.server.service.telemetry.InternalTelemetryService; |
... | ... | @@ -78,7 +79,7 @@ import java.util.stream.Collectors; |
78 | 79 | |
79 | 80 | @Slf4j |
80 | 81 | @Service |
81 | -public class DefaultTbApiUsageStateService implements TbApiUsageStateService { | |
82 | +public class DefaultTbApiUsageStateService extends TbApplicationEventListener<PartitionChangeEvent> implements TbApiUsageStateService { | |
82 | 83 | |
83 | 84 | public static final String HOURLY = "Hourly"; |
84 | 85 | public static final FutureCallback<Integer> VOID_CALLBACK = new FutureCallback<Integer>() { |
... | ... | @@ -188,7 +189,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { |
188 | 189 | } |
189 | 190 | |
190 | 191 | @Override |
191 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
192 | + protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
192 | 193 | if (partitionChangeEvent.getServiceType().equals(ServiceType.TB_CORE)) { |
193 | 194 | myTenantStates.entrySet().removeIf(entry -> !partitionService.resolve(ServiceType.TB_CORE, entry.getKey(), entry.getKey()).isMyPartition()); |
194 | 195 | otherTenantStates.entrySet().removeIf(entry -> partitionService.resolve(ServiceType.TB_CORE, entry.getKey(), entry.getKey()).isMyPartition()); | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.Value; |
24 | 24 | import org.springframework.beans.factory.config.BeanDefinition; |
25 | 25 | import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; |
26 | 26 | import org.springframework.core.env.Environment; |
27 | +import org.springframework.core.env.Profiles; | |
27 | 28 | import org.springframework.core.type.filter.AnnotationTypeFilter; |
28 | 29 | import org.springframework.stereotype.Service; |
29 | 30 | import org.thingsboard.rule.engine.api.NodeConfiguration; |
... | ... | @@ -71,7 +72,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
71 | 72 | private ObjectMapper mapper = new ObjectMapper(); |
72 | 73 | |
73 | 74 | private boolean isInstall() { |
74 | - return environment.acceptsProfiles("install"); | |
75 | + return environment.acceptsProfiles(Profiles.of("install")); | |
75 | 76 | } |
76 | 77 | |
77 | 78 | @PostConstruct |
... | ... | @@ -200,7 +201,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
200 | 201 | nodeDefinition.setRelationTypes(getRelationTypesWithFailureRelation(nodeAnnotation)); |
201 | 202 | nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); |
202 | 203 | Class<? extends NodeConfiguration> configClazz = nodeAnnotation.configClazz(); |
203 | - NodeConfiguration config = configClazz.newInstance(); | |
204 | + NodeConfiguration config = configClazz.getDeclaredConstructor().newInstance(); | |
204 | 205 | NodeConfiguration defaultConfiguration = config.defaultConfiguration(); |
205 | 206 | nodeDefinition.setDefaultConfiguration(mapper.valueToTree(defaultConfiguration)); |
206 | 207 | nodeDefinition.setUiResources(nodeAnnotation.uiResources()); | ... | ... |
... | ... | @@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; |
20 | 20 | import com.fasterxml.jackson.databind.node.ObjectNode; |
21 | 21 | import com.google.common.util.concurrent.ListenableFuture; |
22 | 22 | import lombok.extern.slf4j.Slf4j; |
23 | -import org.apache.commons.lang.RandomStringUtils; | |
23 | +import org.apache.commons.lang3.RandomStringUtils; | |
24 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 25 | import org.springframework.stereotype.Service; |
26 | 26 | import org.springframework.util.StringUtils; | ... | ... |
... | ... | @@ -22,8 +22,8 @@ import com.google.common.util.concurrent.Futures; |
22 | 22 | import com.google.common.util.concurrent.ListenableFuture; |
23 | 23 | import com.google.common.util.concurrent.SettableFuture; |
24 | 24 | import lombok.extern.slf4j.Slf4j; |
25 | -import org.apache.commons.lang.RandomStringUtils; | |
26 | -import org.apache.commons.lang.StringUtils; | |
25 | +import org.apache.commons.lang3.RandomStringUtils; | |
26 | +import org.apache.commons.lang3.StringUtils; | |
27 | 27 | import org.checkerframework.checker.nullness.qual.Nullable; |
28 | 28 | import org.springframework.stereotype.Component; |
29 | 29 | import org.thingsboard.rule.engine.api.RpcError; |
... | ... | @@ -99,7 +99,6 @@ public class DeviceProcessor extends BaseProcessor { |
99 | 99 | ObjectNode body = mapper.createObjectNode(); |
100 | 100 | body.put("conflictName", deviceName); |
101 | 101 | saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, device.getId(), body); |
102 | - deviceService.assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId()); | |
103 | 102 | } |
104 | 103 | futureToSet.set(null); |
105 | 104 | } |
... | ... | @@ -115,7 +114,6 @@ public class DeviceProcessor extends BaseProcessor { |
115 | 114 | log.info("[{}] Creating new device and replacing device entity on the edge [{}]", tenantId, deviceUpdateMsg); |
116 | 115 | device = createDevice(tenantId, edge, deviceUpdateMsg, deviceUpdateMsg.getName()); |
117 | 116 | saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, device.getId(), null); |
118 | - deviceService.assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId()); | |
119 | 117 | } |
120 | 118 | break; |
121 | 119 | case ENTITY_UPDATED_RPC_MESSAGE: |
... | ... | @@ -201,6 +199,7 @@ public class DeviceProcessor extends BaseProcessor { |
201 | 199 | createRelationFromEdge(tenantId, edge.getId(), device.getId()); |
202 | 200 | deviceStateService.onDeviceAdded(device); |
203 | 201 | pushDeviceCreatedEventToRuleEngine(tenantId, edge, device); |
202 | + deviceService.assignDeviceToEdge(edge.getTenantId(), device.getId(), edge.getId()); | |
204 | 203 | } finally { |
205 | 204 | deviceCreationLock.unlock(); |
206 | 205 | } | ... | ... |
... | ... | @@ -21,10 +21,9 @@ import com.google.common.util.concurrent.ListenableFuture; |
21 | 21 | import com.google.common.util.concurrent.SettableFuture; |
22 | 22 | import com.google.gson.Gson; |
23 | 23 | import com.google.gson.JsonObject; |
24 | -import groovy.lang.Tuple; | |
25 | 24 | import lombok.extern.slf4j.Slf4j; |
26 | -import org.javatuples.Pair; | |
27 | -import org.passay.Rule; | |
25 | +import org.apache.commons.lang3.tuple.ImmutablePair; | |
26 | +import org.apache.commons.lang3.tuple.Pair; | |
28 | 27 | import org.springframework.stereotype.Component; |
29 | 28 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
30 | 29 | import org.thingsboard.server.common.data.DataConstants; |
... | ... | @@ -37,7 +36,6 @@ import org.thingsboard.server.common.data.id.AssetId; |
37 | 36 | import org.thingsboard.server.common.data.id.CustomerId; |
38 | 37 | import org.thingsboard.server.common.data.id.DashboardId; |
39 | 38 | import org.thingsboard.server.common.data.id.DeviceId; |
40 | -import org.thingsboard.server.common.data.id.DeviceProfileId; | |
41 | 39 | import org.thingsboard.server.common.data.id.EntityId; |
42 | 40 | import org.thingsboard.server.common.data.id.EntityViewId; |
43 | 41 | import org.thingsboard.server.common.data.id.RuleChainId; |
... | ... | @@ -45,7 +43,6 @@ import org.thingsboard.server.common.data.id.TenantId; |
45 | 43 | import org.thingsboard.server.common.data.id.UserId; |
46 | 44 | import org.thingsboard.server.common.data.kv.AttributeKey; |
47 | 45 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
48 | -import org.thingsboard.server.common.data.rule.RuleChain; | |
49 | 46 | import org.thingsboard.server.common.msg.TbMsg; |
50 | 47 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
51 | 48 | import org.thingsboard.server.common.msg.queue.ServiceQueue; |
... | ... | @@ -145,9 +142,9 @@ public class TelemetryProcessor extends BaseProcessor { |
145 | 142 | String defaultQueueName = deviceProfile.getDefaultQueueName(); |
146 | 143 | queueName = defaultQueueName != null ? defaultQueueName : ServiceQueue.MAIN; |
147 | 144 | } |
148 | - return new Pair<>(queueName, ruleChainId); | |
145 | + return new ImmutablePair<>(queueName, ruleChainId); | |
149 | 146 | } else { |
150 | - return new Pair<>(ServiceQueue.MAIN, null); | |
147 | + return new ImmutablePair<>(ServiceQueue.MAIN, null); | |
151 | 148 | } |
152 | 149 | } |
153 | 150 | |
... | ... | @@ -157,8 +154,8 @@ public class TelemetryProcessor extends BaseProcessor { |
157 | 154 | JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); |
158 | 155 | metaData.putValue("ts", tsKv.getTs() + ""); |
159 | 156 | Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); |
160 | - String queueName = defaultQueueAndRuleChain.getValue0(); | |
161 | - RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue1(); | |
157 | + String queueName = defaultQueueAndRuleChain.getKey(); | |
158 | + RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); | |
162 | 159 | TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, metaData, gson.toJson(json), ruleChainId, null); |
163 | 160 | tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { |
164 | 161 | @Override |
... | ... | @@ -180,8 +177,8 @@ public class TelemetryProcessor extends BaseProcessor { |
180 | 177 | SettableFuture<Void> futureToSet = SettableFuture.create(); |
181 | 178 | JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); |
182 | 179 | Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); |
183 | - String queueName = defaultQueueAndRuleChain.getValue0(); | |
184 | - RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue1(); | |
180 | + String queueName = defaultQueueAndRuleChain.getKey(); | |
181 | + RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); | |
185 | 182 | TbMsg tbMsg = TbMsg.newMsg(queueName, SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json), ruleChainId, null); |
186 | 183 | tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { |
187 | 184 | @Override |
... | ... | @@ -207,8 +204,8 @@ public class TelemetryProcessor extends BaseProcessor { |
207 | 204 | @Override |
208 | 205 | public void onSuccess(@Nullable List<Void> voids) { |
209 | 206 | Pair<String, RuleChainId> defaultQueueAndRuleChain = getDefaultQueueNameAndRuleChainId(tenantId, entityId); |
210 | - String queueName = defaultQueueAndRuleChain.getValue0(); | |
211 | - RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue1(); | |
207 | + String queueName = defaultQueueAndRuleChain.getKey(); | |
208 | + RuleChainId ruleChainId = defaultQueueAndRuleChain.getValue(); | |
212 | 209 | TbMsg tbMsg = TbMsg.newMsg(queueName, DataConstants.ATTRIBUTES_UPDATED, entityId, metaData, gson.toJson(json), ruleChainId, null); |
213 | 210 | tbClusterService.pushMsgToRuleEngine(tenantId, tbMsg.getOriginator(), tbMsg, new TbQueueCallback() { |
214 | 211 | @Override | ... | ... |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -198,7 +198,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
198 | 198 | generalSettings.setKey("general"); |
199 | 199 | ObjectNode node = objectMapper.createObjectNode(); |
200 | 200 | node.put("baseUrl", "http://localhost:8080"); |
201 | - node.put("prohibitDifferentUrl", true); | |
201 | + node.put("prohibitDifferentUrl", false); | |
202 | 202 | generalSettings.setJsonValue(node); |
203 | 203 | adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, generalSettings); |
204 | 204 | |
... | ... | @@ -439,6 +439,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
439 | 439 | this.deleteSystemWidgetBundle("input_widgets"); |
440 | 440 | this.deleteSystemWidgetBundle("date"); |
441 | 441 | this.deleteSystemWidgetBundle("entity_admin_widgets"); |
442 | + this.deleteSystemWidgetBundle("navigation_widgets"); | |
442 | 443 | this.deleteSystemWidgetBundle("edge_widgets"); |
443 | 444 | installScripts.loadSystemWidgets(); |
444 | 445 | } | ... | ... |
... | ... | @@ -15,11 +15,20 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.install; |
17 | 17 | |
18 | +import lombok.extern.slf4j.Slf4j; | |
18 | 19 | import org.springframework.context.annotation.Profile; |
19 | 20 | import org.springframework.stereotype.Service; |
20 | 21 | import org.thingsboard.server.dao.util.HsqlDao; |
21 | 22 | |
23 | +import java.nio.charset.Charset; | |
24 | +import java.nio.file.Files; | |
25 | +import java.nio.file.Path; | |
26 | +import java.nio.file.Paths; | |
27 | +import java.sql.Connection; | |
28 | +import java.sql.DriverManager; | |
29 | + | |
22 | 30 | @Service |
31 | +@Slf4j | |
23 | 32 | @HsqlDao |
24 | 33 | @Profile("install") |
25 | 34 | public class HsqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaService |
... | ... | @@ -27,5 +36,21 @@ public class HsqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaSe |
27 | 36 | protected HsqlEntityDatabaseSchemaService() { |
28 | 37 | super("schema-entities-hsql.sql", "schema-entities-idx.sql"); |
29 | 38 | } |
39 | + | |
40 | + private final String schemaTypesSql = "schema-types-hsql.sql"; | |
41 | + | |
42 | + @Override | |
43 | + public void createDatabaseSchema(boolean createIndexes) throws Exception { | |
44 | + | |
45 | + log.info("Installing SQL DataBase types part: " + schemaTypesSql); | |
46 | + | |
47 | + Path schemaFile = Paths.get(installScripts.getDataDir(), SQL_DIR, schemaTypesSql); | |
48 | + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | |
49 | + String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8")); | |
50 | + conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to load initial thingsboard database schema | |
51 | + } | |
52 | + | |
53 | + super.createDatabaseSchema(createIndexes); | |
54 | + } | |
30 | 55 | } |
31 | 56 | ... | ... |
... | ... | @@ -30,7 +30,7 @@ import java.sql.SQLException; |
30 | 30 | @Slf4j |
31 | 31 | public abstract class SqlAbstractDatabaseSchemaService implements DatabaseSchemaService { |
32 | 32 | |
33 | - private static final String SQL_DIR = "sql"; | |
33 | + protected static final String SQL_DIR = "sql"; | |
34 | 34 | |
35 | 35 | @Value("${spring.datasource.url}") |
36 | 36 | protected String dbUrl; |
... | ... | @@ -42,7 +42,7 @@ public abstract class SqlAbstractDatabaseSchemaService implements DatabaseSchema |
42 | 42 | protected String dbPassword; |
43 | 43 | |
44 | 44 | @Autowired |
45 | - private InstallScripts installScripts; | |
45 | + protected InstallScripts installScripts; | |
46 | 46 | |
47 | 47 | private final String schemaSql; |
48 | 48 | private final String schemaIdxSql; | ... | ... |
... | ... | @@ -145,17 +145,17 @@ public class CassandraDbHelper { |
145 | 145 | if (row.isNull(index)) { |
146 | 146 | return null; |
147 | 147 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.DOUBLE) { |
148 | - str = new Double(row.getDouble(index)).toString(); | |
148 | + str = Double.valueOf(row.getDouble(index)).toString(); | |
149 | 149 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.INT) { |
150 | - str = new Integer(row.getInt(index)).toString(); | |
150 | + str = Integer.valueOf(row.getInt(index)).toString(); | |
151 | 151 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.BIGINT) { |
152 | - str = new Long(row.getLong(index)).toString(); | |
152 | + str = Long.valueOf(row.getLong(index)).toString(); | |
153 | 153 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.UUID) { |
154 | 154 | str = row.getUuid(index).toString(); |
155 | 155 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMEUUID) { |
156 | 156 | str = row.getUuid(index).toString(); |
157 | 157 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.FLOAT) { |
158 | - str = new Float(row.getFloat(index)).toString(); | |
158 | + str = Float.valueOf(row.getFloat(index)).toString(); | |
159 | 159 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMESTAMP) { |
160 | 160 | str = ""+row.getInstant(index).toEpochMilli(); |
161 | 161 | } else if (type.getProtocolCode() == ProtocolConstants.DataType.BOOLEAN) { | ... | ... |
... | ... | @@ -153,7 +153,8 @@ public class CassandraToSqlColumn { |
153 | 153 | sqlInsertStatement.setBoolean(this.sqlIndex, Boolean.parseBoolean(value)); |
154 | 154 | break; |
155 | 155 | case ENUM_TO_INT: |
156 | - Enum enumVal = Enum.valueOf(this.enumClass, value); | |
156 | + @SuppressWarnings("unchecked") | |
157 | + Enum<?> enumVal = Enum.valueOf(this.enumClass, value); | |
157 | 158 | int intValue = enumVal.ordinal(); |
158 | 159 | sqlInsertStatement.setInt(this.sqlIndex, intValue); |
159 | 160 | break; | ... | ... |
... | ... | @@ -50,7 +50,8 @@ import java.util.List; |
50 | 50 | import java.util.concurrent.ExecutionException; |
51 | 51 | import java.util.stream.Collectors; |
52 | 52 | |
53 | -import static org.apache.commons.lang.StringUtils.isBlank; | |
53 | +import static org.apache.commons.lang3.StringUtils.isBlank; | |
54 | +import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper; | |
54 | 55 | |
55 | 56 | @Service |
56 | 57 | @Profile("install") | ... | ... |
... | ... | @@ -169,11 +169,11 @@ public class LwM2MModelsRepository { |
169 | 169 | * PageNumber = 1, PageSize = List<LwM2mObject>.size() |
170 | 170 | */ |
171 | 171 | public PageData<LwM2mObject> findLwm2mListObjects(PageLink pageLink) { |
172 | - PageImpl page = new PageImpl(getLwm2mObjects(getObjectIdFromTextSearch(pageLink.getTextSearch()), | |
172 | + PageImpl<LwM2mObject> page = new PageImpl<>(getLwm2mObjects(getObjectIdFromTextSearch(pageLink.getTextSearch()), | |
173 | 173 | pageLink.getTextSearch(), |
174 | 174 | pageLink.getSortOrder().getProperty(), |
175 | 175 | pageLink.getSortOrder().getDirection().name())); |
176 | - PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); | |
176 | + PageData<LwM2mObject> pageData = new PageData<>(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext()); | |
177 | 177 | return pageData; |
178 | 178 | } |
179 | 179 | |
... | ... | @@ -217,23 +217,19 @@ public class LwM2MModelsRepository { |
217 | 217 | switch (mode) { |
218 | 218 | case NO_SEC: |
219 | 219 | bsServ.setHost(contextBootStrap.getBootstrapHost()); |
220 | - bsServ.setPort(contextBootStrap.getBootstrapPortNoSecPsk()); | |
220 | + bsServ.setPort(contextBootStrap.getBootstrapPortNoSec()); | |
221 | 221 | bsServ.setServerPublicKey(""); |
222 | 222 | break; |
223 | 223 | case PSK: |
224 | - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); | |
225 | - bsServ.setPort(contextBootStrap.getBootstrapSecurePortPsk()); | |
224 | + bsServ.setHost(contextBootStrap.getBootstrapHostSecurity()); | |
225 | + bsServ.setPort(contextBootStrap.getBootstrapPortSecurity()); | |
226 | 226 | bsServ.setServerPublicKey(""); |
227 | 227 | break; |
228 | 228 | case RPK: |
229 | - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); | |
230 | - bsServ.setPort(contextBootStrap.getBootstrapSecurePortRpk()); | |
231 | - bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); | |
232 | - break; | |
233 | 229 | case X509: |
234 | - bsServ.setHost(contextBootStrap.getBootstrapSecureHost()); | |
235 | - bsServ.setPort(contextBootStrap.getBootstrapSecurePortX509()); | |
236 | - bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias())); | |
230 | + bsServ.setHost(contextBootStrap.getBootstrapHostSecurity()); | |
231 | + bsServ.setPort(contextBootStrap.getBootstrapPortSecurity()); | |
232 | + bsServ.setServerPublicKey(getPublicKey (contextBootStrap.getBootstrapAlias(), this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY())); | |
237 | 233 | break; |
238 | 234 | default: |
239 | 235 | break; |
... | ... | @@ -243,23 +239,19 @@ public class LwM2MModelsRepository { |
243 | 239 | switch (mode) { |
244 | 240 | case NO_SEC: |
245 | 241 | bsServ.setHost(contextServer.getServerHost()); |
246 | - bsServ.setPort(contextServer.getServerPortNoSecPsk()); | |
242 | + bsServ.setPort(contextServer.getServerPortNoSec()); | |
247 | 243 | bsServ.setServerPublicKey(""); |
248 | 244 | break; |
249 | 245 | case PSK: |
250 | - bsServ.setHost(contextServer.getServerSecureHost()); | |
251 | - bsServ.setPort(contextServer.getServerPortPsk()); | |
246 | + bsServ.setHost(contextServer.getServerHostSecurity()); | |
247 | + bsServ.setPort(contextServer.getServerPortSecurity()); | |
252 | 248 | bsServ.setServerPublicKey(""); |
253 | 249 | break; |
254 | 250 | case RPK: |
255 | - bsServ.setHost(contextServer.getServerSecureHost()); | |
256 | - bsServ.setPort(contextServer.getServerPortRpk()); | |
257 | - bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); | |
258 | - break; | |
259 | 251 | case X509: |
260 | - bsServ.setHost(contextServer.getServerSecureHost()); | |
261 | - bsServ.setPort(contextServer.getServerPortX509()); | |
262 | - bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias())); | |
252 | + bsServ.setHost(contextServer.getServerHostSecurity()); | |
253 | + bsServ.setPort(contextServer.getServerPortSecurity()); | |
254 | + bsServ.setServerPublicKey(getPublicKey (contextServer.getServerAlias(), this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY())); | |
263 | 255 | break; |
264 | 256 | default: |
265 | 257 | break; |
... | ... | @@ -268,6 +260,11 @@ public class LwM2MModelsRepository { |
268 | 260 | return bsServ; |
269 | 261 | } |
270 | 262 | |
263 | + private String getPublicKey (String alias, String publicServerX, String publicServerY) { | |
264 | + String publicKey = getServerPublicKeyX509(alias); | |
265 | + return publicKey != null ? publicKey : getRPKPublicKey(publicServerX, publicServerY); | |
266 | + } | |
267 | + | |
271 | 268 | /** |
272 | 269 | * @param alias |
273 | 270 | * @return PublicKey format HexString or null | ... | ... |
... | ... | @@ -206,7 +206,7 @@ public class DefaultEntityQueryService implements EntityQueryService { |
206 | 206 | addItemsToArrayNode(json.putArray("entityTypes"), types); |
207 | 207 | addItemsToArrayNode(json.putArray("timeseries"), timeseriesKeys); |
208 | 208 | addItemsToArrayNode(json.putArray("attribute"), attributesKeys); |
209 | - response.setResult(new ResponseEntity(json, HttpStatus.OK)); | |
209 | + response.setResult(new ResponseEntity<>(json, HttpStatus.OK)); | |
210 | 210 | } |
211 | 211 | |
212 | 212 | private void replyWithEmptyResponse(DeferredResult<ResponseEntity> response) { | ... | ... |
... | ... | @@ -156,12 +156,12 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore |
156 | 156 | } |
157 | 157 | |
158 | 158 | @Override |
159 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
160 | - if (partitionChangeEvent.getServiceType().equals(getServiceType())) { | |
161 | - log.info("Subscribing to partitions: {}", partitionChangeEvent.getPartitions()); | |
162 | - this.mainConsumer.subscribe(partitionChangeEvent.getPartitions()); | |
159 | + protected void onTbApplicationEvent(PartitionChangeEvent event) { | |
160 | + if (event.getServiceType().equals(getServiceType())) { | |
161 | + log.info("Subscribing to partitions: {}", event.getPartitions()); | |
162 | + this.mainConsumer.subscribe(event.getPartitions()); | |
163 | 163 | this.usageStatsConsumer.subscribe( |
164 | - partitionChangeEvent | |
164 | + event | |
165 | 165 | .getPartitions() |
166 | 166 | .stream() |
167 | 167 | .map(tpi -> tpi.newByTopic(usageStatsConsumer.getTopic())) | ... | ... |
... | ... | @@ -140,11 +140,11 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< |
140 | 140 | } |
141 | 141 | |
142 | 142 | @Override |
143 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
144 | - if (partitionChangeEvent.getServiceType().equals(getServiceType())) { | |
145 | - ServiceQueue serviceQueue = partitionChangeEvent.getServiceQueueKey().getServiceQueue(); | |
146 | - log.info("[{}] Subscribing to partitions: {}", serviceQueue.getQueue(), partitionChangeEvent.getPartitions()); | |
147 | - consumers.get(serviceQueue.getQueue()).subscribe(partitionChangeEvent.getPartitions()); | |
143 | + protected void onTbApplicationEvent(PartitionChangeEvent event) { | |
144 | + if (event.getServiceType().equals(getServiceType())) { | |
145 | + ServiceQueue serviceQueue = event.getServiceQueueKey().getServiceQueue(); | |
146 | + log.info("[{}] Subscribing to partitions: {}", serviceQueue.getQueue(), event.getPartitions()); | |
147 | + consumers.get(serviceQueue.getQueue()).subscribe(event.getPartitions()); | |
148 | 148 | } |
149 | 149 | } |
150 | 150 | |
... | ... | @@ -181,7 +181,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< |
181 | 181 | new TbMsgPackCallback(id, tenantId, ctx, stats.getTimer(tenantId, SUCCESSFUL_STATUS), stats.getTimer(tenantId, FAILED_STATUS)) : |
182 | 182 | new TbMsgPackCallback(id, tenantId, ctx); |
183 | 183 | try { |
184 | - if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) { | |
184 | + if (!toRuleEngineMsg.getTbMsg().isEmpty()) { | |
185 | 185 | forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback); |
186 | 186 | } else { |
187 | 187 | callback.onSuccess(); |
... | ... | @@ -209,6 +209,9 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< |
209 | 209 | if (statsEnabled) { |
210 | 210 | stats.log(result, decision.isCommit()); |
211 | 211 | } |
212 | + | |
213 | + ctx.cleanup(); | |
214 | + | |
212 | 215 | if (decision.isCommit()) { |
213 | 216 | submitStrategy.stop(); |
214 | 217 | break; | ... | ... |
... | ... | @@ -147,4 +147,10 @@ public class TbMsgPackProcessingContext { |
147 | 147 | .forEach(info -> log.info("[{}][{}] execution count: {}. {}", queueName, info.getRuleNodeId(), info.getExecutionCount(), info.getLabel())); |
148 | 148 | } |
149 | 149 | } |
150 | + | |
151 | + public void cleanup() { | |
152 | + pendingMap.clear(); | |
153 | + successMap.clear(); | |
154 | + failedMap.clear(); | |
155 | + } | |
150 | 156 | } | ... | ... |
... | ... | @@ -36,6 +36,7 @@ import org.thingsboard.server.queue.TbQueueConsumer; |
36 | 36 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
37 | 37 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; |
38 | 38 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
39 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
39 | 40 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
40 | 41 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
41 | 42 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
... | ... | @@ -56,7 +57,7 @@ import java.util.function.Function; |
56 | 57 | import java.util.stream.Collectors; |
57 | 58 | |
58 | 59 | @Slf4j |
59 | -public abstract class AbstractConsumerService<N extends com.google.protobuf.GeneratedMessageV3> implements ApplicationListener<PartitionChangeEvent> { | |
60 | +public abstract class AbstractConsumerService<N extends com.google.protobuf.GeneratedMessageV3> extends TbApplicationEventListener<PartitionChangeEvent> { | |
60 | 61 | |
61 | 62 | protected volatile ExecutorService consumersExecutor; |
62 | 63 | protected volatile ExecutorService notificationsConsumerExecutor; | ... | ... |
... | ... | @@ -31,6 +31,8 @@ import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
31 | 31 | @RequiredArgsConstructor |
32 | 32 | public class ToDeviceRpcRequestActorMsg implements ToDeviceActorNotificationMsg { |
33 | 33 | |
34 | + private static final long serialVersionUID = -8592877558138716589L; | |
35 | + | |
34 | 36 | @Getter |
35 | 37 | private final String serviceId; |
36 | 38 | @Getter | ... | ... |
... | ... | @@ -21,7 +21,6 @@ import com.google.common.util.concurrent.ListenableFuture; |
21 | 21 | import com.google.common.util.concurrent.MoreExecutors; |
22 | 22 | import delight.nashornsandbox.NashornSandbox; |
23 | 23 | import delight.nashornsandbox.NashornSandboxes; |
24 | -import jdk.nashorn.api.scripting.NashornScriptEngineFactory; | |
25 | 24 | import lombok.Getter; |
26 | 25 | import lombok.extern.slf4j.Slf4j; |
27 | 26 | import org.springframework.beans.factory.annotation.Value; |
... | ... | @@ -33,6 +32,7 @@ import javax.annotation.PostConstruct; |
33 | 32 | import javax.annotation.PreDestroy; |
34 | 33 | import javax.script.Invocable; |
35 | 34 | import javax.script.ScriptEngine; |
35 | +import javax.script.ScriptEngineManager; | |
36 | 36 | import javax.script.ScriptException; |
37 | 37 | import java.util.UUID; |
38 | 38 | import java.util.concurrent.ExecutionException; |
... | ... | @@ -97,8 +97,8 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer |
97 | 97 | sandbox.allowLoadFunctions(true); |
98 | 98 | sandbox.setMaxPreparedStatements(30); |
99 | 99 | } else { |
100 | - NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); | |
101 | - engine = factory.getScriptEngine(new String[]{"--no-java"}); | |
100 | + ScriptEngineManager factory = new ScriptEngineManager(); | |
101 | + engine = factory.getEngineByName("nashorn"); | |
102 | 102 | } |
103 | 103 | } |
104 | 104 | ... | ... |
... | ... | @@ -29,7 +29,7 @@ public class SkipPathRequestMatcher implements RequestMatcher { |
29 | 29 | private RequestMatcher processingMatcher; |
30 | 30 | |
31 | 31 | public SkipPathRequestMatcher(List<String> pathsToSkip, String processingPath) { |
32 | - Assert.notNull(pathsToSkip); | |
32 | + Assert.notNull(pathsToSkip, "List of paths to skip is required."); | |
33 | 33 | List<RequestMatcher> m = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList()); |
34 | 34 | matchers = new OrRequestMatcher(m); |
35 | 35 | processingMatcher = new AntPathRequestMatcher(processingPath); | ... | ... |
... | ... | @@ -100,6 +100,7 @@ public class JwtTokenFactory { |
100 | 100 | Jws<Claims> jwsClaims = rawAccessToken.parseClaims(settings.getTokenSigningKey()); |
101 | 101 | Claims claims = jwsClaims.getBody(); |
102 | 102 | String subject = claims.getSubject(); |
103 | + @SuppressWarnings("unchecked") | |
103 | 104 | List<String> scopes = claims.get(SCOPES, List.class); |
104 | 105 | if (scopes == null || scopes.isEmpty()) { |
105 | 106 | throw new IllegalArgumentException("JWT Token doesn't have any scopes"); |
... | ... | @@ -155,6 +156,7 @@ public class JwtTokenFactory { |
155 | 156 | Jws<Claims> jwsClaims = rawAccessToken.parseClaims(settings.getTokenSigningKey()); |
156 | 157 | Claims claims = jwsClaims.getBody(); |
157 | 158 | String subject = claims.getSubject(); |
159 | + @SuppressWarnings("unchecked") | |
158 | 160 | List<String> scopes = claims.get(SCOPES, List.class); |
159 | 161 | if (scopes == null || scopes.isEmpty()) { |
160 | 162 | throw new IllegalArgumentException("Refresh Token doesn't have any scopes"); | ... | ... |
... | ... | @@ -48,6 +48,7 @@ public class CustomerUserPermissions extends AbstractPermissions { |
48 | 48 | Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY, Operation.RPC_CALL, Operation.CLAIM_DEVICES) { |
49 | 49 | |
50 | 50 | @Override |
51 | + @SuppressWarnings("unchecked") | |
51 | 52 | public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { |
52 | 53 | |
53 | 54 | if (!super.hasPermission(user, operation, entityId, entity)) { |
... | ... | @@ -70,6 +71,7 @@ public class CustomerUserPermissions extends AbstractPermissions { |
70 | 71 | new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) { |
71 | 72 | |
72 | 73 | @Override |
74 | + @SuppressWarnings("unchecked") | |
73 | 75 | public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { |
74 | 76 | if (!super.hasPermission(user, operation, entityId, entity)) { |
75 | 77 | return false; |
... | ... | @@ -120,6 +122,7 @@ public class CustomerUserPermissions extends AbstractPermissions { |
120 | 122 | private static final PermissionChecker widgetsPermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ) { |
121 | 123 | |
122 | 124 | @Override |
125 | + @SuppressWarnings("unchecked") | |
123 | 126 | public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { |
124 | 127 | if (!super.hasPermission(user, operation, entityId, entity)) { |
125 | 128 | return false; | ... | ... |
... | ... | @@ -56,6 +56,7 @@ public class DefaultAccessControlService implements AccessControlService { |
56 | 56 | } |
57 | 57 | |
58 | 58 | @Override |
59 | + @SuppressWarnings("unchecked") | |
59 | 60 | public <I extends EntityId, T extends HasTenantId> void checkPermission(SecurityUser user, Resource resource, |
60 | 61 | Operation operation, I entityId, T entity) throws ThingsboardException { |
61 | 62 | PermissionChecker permissionChecker = getPermissionChecker(user.getAuthority(), resource); | ... | ... |
... | ... | @@ -60,6 +60,7 @@ public class TenantAdminPermissions extends AbstractPermissions { |
60 | 60 | new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) { |
61 | 61 | |
62 | 62 | @Override |
63 | + @SuppressWarnings("unchecked") | |
63 | 64 | public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) { |
64 | 65 | if (!super.hasPermission(user, operation, entityId, entity)) { |
65 | 66 | return false; | ... | ... |
... | ... | @@ -15,8 +15,8 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.security.system; |
17 | 17 | |
18 | +import com.fasterxml.jackson.core.type.TypeReference; | |
18 | 19 | import com.fasterxml.jackson.databind.JsonNode; |
19 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | 20 | import com.fasterxml.jackson.databind.node.ObjectNode; |
21 | 21 | import lombok.extern.slf4j.Slf4j; |
22 | 22 | import org.apache.commons.lang3.StringUtils; |
... | ... | @@ -49,6 +49,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; |
49 | 49 | import org.thingsboard.server.dao.settings.AdminSettingsService; |
50 | 50 | import org.thingsboard.server.dao.user.UserService; |
51 | 51 | import org.thingsboard.server.dao.user.UserServiceImpl; |
52 | +import org.thingsboard.server.dao.util.mapping.JacksonUtil; | |
52 | 53 | import org.thingsboard.server.service.security.exception.UserPasswordExpiredException; |
53 | 54 | import org.thingsboard.server.utils.MiscUtils; |
54 | 55 | |
... | ... | @@ -65,8 +66,6 @@ import static org.thingsboard.server.common.data.CacheConstants.SECURITY_SETTING |
65 | 66 | @Slf4j |
66 | 67 | public class DefaultSystemSecurityService implements SystemSecurityService { |
67 | 68 | |
68 | - private static final ObjectMapper objectMapper = new ObjectMapper(); | |
69 | - | |
70 | 69 | @Autowired |
71 | 70 | private AdminSettingsService adminSettingsService; |
72 | 71 | |
... | ... | @@ -89,7 +88,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { |
89 | 88 | AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, "securitySettings"); |
90 | 89 | if (adminSettings != null) { |
91 | 90 | try { |
92 | - securitySettings = objectMapper.treeToValue(adminSettings.getJsonValue(), SecuritySettings.class); | |
91 | + securitySettings = JacksonUtil.convertValue(adminSettings.getJsonValue(), SecuritySettings.class); | |
93 | 92 | } catch (Exception e) { |
94 | 93 | throw new RuntimeException("Failed to load security settings!", e); |
95 | 94 | } |
... | ... | @@ -109,10 +108,10 @@ public class DefaultSystemSecurityService implements SystemSecurityService { |
109 | 108 | adminSettings = new AdminSettings(); |
110 | 109 | adminSettings.setKey("securitySettings"); |
111 | 110 | } |
112 | - adminSettings.setJsonValue(objectMapper.valueToTree(securitySettings)); | |
111 | + adminSettings.setJsonValue(JacksonUtil.valueToTree(securitySettings)); | |
113 | 112 | AdminSettings savedAdminSettings = adminSettingsService.saveAdminSettings(tenantId, adminSettings); |
114 | 113 | try { |
115 | - return objectMapper.treeToValue(savedAdminSettings.getJsonValue(), SecuritySettings.class); | |
114 | + return JacksonUtil.convertValue(savedAdminSettings.getJsonValue(), SecuritySettings.class); | |
116 | 115 | } catch (Exception e) { |
117 | 116 | throw new RuntimeException("Failed to load security settings!", e); |
118 | 117 | } |
... | ... | @@ -189,7 +188,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService { |
189 | 188 | JsonNode additionalInfo = user.getAdditionalInfo(); |
190 | 189 | if (additionalInfo instanceof ObjectNode && additionalInfo.has(UserServiceImpl.USER_PASSWORD_HISTORY)) { |
191 | 190 | JsonNode userPasswordHistoryJson = additionalInfo.get(UserServiceImpl.USER_PASSWORD_HISTORY); |
192 | - Map<String, String> userPasswordHistoryMap = objectMapper.convertValue(userPasswordHistoryJson, Map.class); | |
191 | + Map<String, String> userPasswordHistoryMap = JacksonUtil.convertValue(userPasswordHistoryJson, new TypeReference<>() {}); | |
193 | 192 | for (Map.Entry<String, String> entry : userPasswordHistoryMap.entrySet()) { |
194 | 193 | if (encoder.matches(password, entry.getValue()) && Long.parseLong(entry.getKey()) > passwordReuseFrequencyTs) { |
195 | 194 | throw new DataValidationException("Password was already used for the last " + passwordPolicy.getPasswordReuseFrequencyDays() + " days"); | ... | ... |
... | ... | @@ -56,9 +56,11 @@ import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
56 | 56 | import org.thingsboard.server.gen.transport.TransportProtos; |
57 | 57 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; |
58 | 58 | import org.thingsboard.server.queue.discovery.PartitionService; |
59 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
59 | 60 | import org.thingsboard.server.queue.util.TbCoreComponent; |
60 | 61 | import org.thingsboard.server.service.queue.TbClusterService; |
61 | 62 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
63 | +import org.thingsboard.server.utils.EventDeduplicationExecutor; | |
62 | 64 | |
63 | 65 | import javax.annotation.Nullable; |
64 | 66 | import javax.annotation.PostConstruct; |
... | ... | @@ -89,7 +91,7 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; |
89 | 91 | @Service |
90 | 92 | @TbCoreComponent |
91 | 93 | @Slf4j |
92 | -public class DefaultDeviceStateService implements DeviceStateService { | |
94 | +public class DefaultDeviceStateService extends TbApplicationEventListener<PartitionChangeEvent> implements DeviceStateService { | |
93 | 95 | |
94 | 96 | public static final String ACTIVITY_STATE = "active"; |
95 | 97 | public static final String LAST_CONNECT_TIME = "lastConnectTime"; |
... | ... | @@ -126,13 +128,13 @@ public class DefaultDeviceStateService implements DeviceStateService { |
126 | 128 | @Getter |
127 | 129 | private int initFetchPackSize; |
128 | 130 | |
129 | - private volatile boolean clusterUpdatePending = false; | |
130 | - | |
131 | 131 | private ListeningScheduledExecutorService queueExecutor; |
132 | 132 | private final ConcurrentMap<TopicPartitionInfo, Set<DeviceId>> partitionedDevices = new ConcurrentHashMap<>(); |
133 | 133 | private final ConcurrentMap<DeviceId, DeviceStateData> deviceStates = new ConcurrentHashMap<>(); |
134 | 134 | private final ConcurrentMap<DeviceId, Long> deviceLastReportedActivity = new ConcurrentHashMap<>(); |
135 | 135 | private final ConcurrentMap<DeviceId, Long> deviceLastSavedActivity = new ConcurrentHashMap<>(); |
136 | + private volatile EventDeduplicationExecutor<Set<TopicPartitionInfo>> deduplicationExecutor; | |
137 | + | |
136 | 138 | |
137 | 139 | public DefaultDeviceStateService(TenantService tenantService, DeviceService deviceService, |
138 | 140 | AttributesService attributesService, TimeseriesService tsService, |
... | ... | @@ -155,6 +157,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
155 | 157 | // Should be always single threaded due to absence of locks. |
156 | 158 | queueExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("device-state"))); |
157 | 159 | queueExecutor.scheduleAtFixedRate(this::updateState, new Random().nextInt(defaultStateCheckIntervalInSec), defaultStateCheckIntervalInSec, TimeUnit.SECONDS); |
160 | + deduplicationExecutor = new EventDeduplicationExecutor<>(DefaultDeviceStateService.class.getSimpleName(), queueExecutor, this::initStateFromDB); | |
158 | 161 | } |
159 | 162 | |
160 | 163 | @PreDestroy |
... | ... | @@ -204,7 +207,6 @@ public class DefaultDeviceStateService implements DeviceStateService { |
204 | 207 | if (!state.isActive()) { |
205 | 208 | state.setActive(true); |
206 | 209 | save(deviceId, ACTIVITY_STATE, state.isActive()); |
207 | - stateData.getMetaData().putValue("scope", SERVER_SCOPE); | |
208 | 210 | pushRuleEngineMessage(stateData, ACTIVITY_EVENT); |
209 | 211 | } |
210 | 212 | } |
... | ... | @@ -292,25 +294,14 @@ public class DefaultDeviceStateService implements DeviceStateService { |
292 | 294 | } |
293 | 295 | } |
294 | 296 | |
295 | - volatile Set<TopicPartitionInfo> pendingPartitions; | |
296 | - | |
297 | 297 | @Override |
298 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
298 | + protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
299 | 299 | if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { |
300 | - synchronized (this) { | |
301 | - pendingPartitions = partitionChangeEvent.getPartitions(); | |
302 | - if (!clusterUpdatePending) { | |
303 | - clusterUpdatePending = true; | |
304 | - queueExecutor.submit(() -> { | |
305 | - clusterUpdatePending = false; | |
306 | - initStateFromDB(); | |
307 | - }); | |
308 | - } | |
309 | - } | |
300 | + deduplicationExecutor.submit(partitionChangeEvent.getPartitions()); | |
310 | 301 | } |
311 | 302 | } |
312 | 303 | |
313 | - private void initStateFromDB() { | |
304 | + private void initStateFromDB(Set<TopicPartitionInfo> pendingPartitions) { | |
314 | 305 | try { |
315 | 306 | log.info("CURRENT PARTITIONS: {}", partitionedDevices.keySet()); |
316 | 307 | log.info("NEW PARTITIONS: {}", pendingPartitions); |
... | ... | @@ -456,7 +447,7 @@ public class DefaultDeviceStateService implements DeviceStateService { |
456 | 447 | } |
457 | 448 | |
458 | 449 | private <T extends KvEntry> Function<List<T>, DeviceStateData> extractDeviceStateData(Device device) { |
459 | - return new Function<List<T>, DeviceStateData>() { | |
450 | + return new Function<>() { | |
460 | 451 | @Nullable |
461 | 452 | @Override |
462 | 453 | public DeviceStateData apply(@Nullable List<T> data) { |
... | ... | @@ -512,7 +503,11 @@ public class DefaultDeviceStateService implements DeviceStateService { |
512 | 503 | } else { |
513 | 504 | data = JacksonUtil.toString(state); |
514 | 505 | } |
515 | - TbMsg tbMsg = TbMsg.newMsg(msgType, stateData.getDeviceId(), stateData.getMetaData().copy(), TbMsgDataType.JSON, data); | |
506 | + TbMsgMetaData md = stateData.getMetaData().copy(); | |
507 | + if(!persistToTelemetry){ | |
508 | + md.putValue(DataConstants.SCOPE, SERVER_SCOPE); | |
509 | + } | |
510 | + TbMsg tbMsg = TbMsg.newMsg(msgType, stateData.getDeviceId(), md, TbMsgDataType.JSON, data); | |
516 | 511 | clusterService.pushMsgToRuleEngine(stateData.getTenantId(), stateData.getDeviceId(), tbMsg, null); |
517 | 512 | } catch (Exception e) { |
518 | 513 | log.warn("[{}] Failed to push inactivity alarm: {}", stateData.getDeviceId(), state, e); | ... | ... |
... | ... | @@ -48,6 +48,7 @@ import org.thingsboard.server.queue.TbQueueProducer; |
48 | 48 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
49 | 49 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; |
50 | 50 | import org.thingsboard.server.queue.discovery.PartitionService; |
51 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
51 | 52 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
52 | 53 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
53 | 54 | import org.thingsboard.server.queue.util.TbCoreComponent; |
... | ... | @@ -76,7 +77,7 @@ import java.util.function.Predicate; |
76 | 77 | @Slf4j |
77 | 78 | @TbCoreComponent |
78 | 79 | @Service |
79 | -public class DefaultSubscriptionManagerService implements SubscriptionManagerService { | |
80 | +public class DefaultSubscriptionManagerService extends TbApplicationEventListener<PartitionChangeEvent> implements SubscriptionManagerService { | |
80 | 81 | |
81 | 82 | @Autowired |
82 | 83 | private AttributesService attrService; |
... | ... | @@ -178,7 +179,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer |
178 | 179 | } |
179 | 180 | |
180 | 181 | @Override |
181 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
182 | + protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
182 | 183 | if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { |
183 | 184 | Set<TopicPartitionInfo> removedPartitions = new HashSet<>(currentPartitions); |
184 | 185 | removedPartitions.removeAll(partitionChangeEvent.getPartitions()); | ... | ... |
... | ... | @@ -302,7 +302,9 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc |
302 | 302 | Map<Integer, TbAbstractDataSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); |
303 | 303 | TbEntityDataSubCtx ctx = new TbEntityDataSubCtx(serviceId, wsService, entityService, localSubscriptionService, |
304 | 304 | attributesService, stats, sessionRef, cmd.getCmdId(), maxEntitiesPerDataSubscription); |
305 | - ctx.setAndResolveQuery(cmd.getQuery()); | |
305 | + if (cmd.getQuery() != null) { | |
306 | + ctx.setAndResolveQuery(cmd.getQuery()); | |
307 | + } | |
306 | 308 | sessionSubs.put(cmd.getCmdId(), ctx); |
307 | 309 | return ctx; |
308 | 310 | } |
... | ... | @@ -316,6 +318,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc |
316 | 318 | return ctx; |
317 | 319 | } |
318 | 320 | |
321 | + @SuppressWarnings("unchecked") | |
319 | 322 | private <T extends TbAbstractDataSubCtx> T getSubCtx(String sessionId, int cmdId) { |
320 | 323 | Map<Integer, TbAbstractDataSubCtx> sessionSubs = subscriptionsBySessionId.get(sessionId); |
321 | 324 | if (sessionSubs != null) { |
... | ... | @@ -473,7 +476,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc |
473 | 476 | public void cancelAllSessionSubscriptions(String sessionId) { |
474 | 477 | Map<Integer, TbAbstractDataSubCtx> sessionSubs = subscriptionsBySessionId.remove(sessionId); |
475 | 478 | if (sessionSubs != null) { |
476 | - sessionSubs.values().stream().filter(sub -> sub instanceof TbEntityDataSubCtx).map(sub -> (TbEntityDataSubCtx) sub).forEach(this::cleanupAndCancel); | |
479 | + sessionSubs.values().forEach(this::cleanupAndCancel); | |
477 | 480 | } |
478 | 481 | } |
479 | 482 | ... | ... |
... | ... | @@ -28,6 +28,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; |
28 | 28 | import org.thingsboard.server.common.msg.queue.ServiceType; |
29 | 29 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
30 | 30 | import org.thingsboard.server.common.msg.queue.TbCallback; |
31 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
31 | 32 | import org.thingsboard.server.queue.util.TbCoreComponent; |
32 | 33 | import org.thingsboard.server.service.queue.TbClusterService; |
33 | 34 | import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; |
... | ... | @@ -62,6 +63,34 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer |
62 | 63 | private SubscriptionManagerService subscriptionManagerService; |
63 | 64 | |
64 | 65 | private ExecutorService subscriptionUpdateExecutor; |
66 | + | |
67 | + private TbApplicationEventListener<PartitionChangeEvent> partitionChangeListener = new TbApplicationEventListener<>() { | |
68 | + @Override | |
69 | + protected void onTbApplicationEvent(PartitionChangeEvent event) { | |
70 | + if (ServiceType.TB_CORE.equals(event.getServiceType())) { | |
71 | + currentPartitions.clear(); | |
72 | + currentPartitions.addAll(event.getPartitions()); | |
73 | + } | |
74 | + } | |
75 | + }; | |
76 | + | |
77 | + private TbApplicationEventListener<ClusterTopologyChangeEvent> clusterTopologyChangeListener = new TbApplicationEventListener<>() { | |
78 | + @Override | |
79 | + protected void onTbApplicationEvent(ClusterTopologyChangeEvent event) { | |
80 | + if (event.getServiceQueueKeys().stream().anyMatch(key -> ServiceType.TB_CORE.equals(key.getServiceType()))) { | |
81 | + /* | |
82 | + * If the cluster topology has changed, we need to push all current subscriptions to SubscriptionManagerService again. | |
83 | + * Otherwise, the SubscriptionManagerService may "forget" those subscriptions in case of restart. | |
84 | + * Although this is resource consuming operation, it is cheaper than sending ping/pong commands periodically | |
85 | + * It is also cheaper then caching the subscriptions by entity id and then lookup of those caches every time we have new telemetry in SubscriptionManagerService. | |
86 | + * Even if we cache locally the list of active subscriptions by entity id, it is still time consuming operation to get them from cache | |
87 | + * Since number of subscriptions is usually much less then number of devices that are pushing data. | |
88 | + */ | |
89 | + subscriptionsBySessionId.values().forEach(map -> map.values() | |
90 | + .forEach(sub -> pushSubscriptionToManagerService(sub, true))); | |
91 | + } | |
92 | + } | |
93 | + }; | |
65 | 94 | |
66 | 95 | @PostConstruct |
67 | 96 | public void initExecutor() { |
... | ... | @@ -77,28 +106,14 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer |
77 | 106 | |
78 | 107 | @Override |
79 | 108 | @EventListener(PartitionChangeEvent.class) |
80 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
81 | - if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { | |
82 | - currentPartitions.clear(); | |
83 | - currentPartitions.addAll(partitionChangeEvent.getPartitions()); | |
84 | - } | |
109 | + public void onApplicationEvent(PartitionChangeEvent event) { | |
110 | + partitionChangeListener.onApplicationEvent(event); | |
85 | 111 | } |
86 | 112 | |
87 | 113 | @Override |
88 | 114 | @EventListener(ClusterTopologyChangeEvent.class) |
89 | 115 | public void onApplicationEvent(ClusterTopologyChangeEvent event) { |
90 | - if (event.getServiceQueueKeys().stream().anyMatch(key -> ServiceType.TB_CORE.equals(key.getServiceType()))) { | |
91 | - /* | |
92 | - * If the cluster topology has changed, we need to push all current subscriptions to SubscriptionManagerService again. | |
93 | - * Otherwise, the SubscriptionManagerService may "forget" those subscriptions in case of restart. | |
94 | - * Although this is resource consuming operation, it is cheaper than sending ping/pong commands periodically | |
95 | - * It is also cheaper then caching the subscriptions by entity id and then lookup of those caches every time we have new telemetry in SubscriptionManagerService. | |
96 | - * Even if we cache locally the list of active subscriptions by entity id, it is still time consuming operation to get them from cache | |
97 | - * Since number of subscriptions is usually much less then number of devices that are pushing data. | |
98 | - */ | |
99 | - subscriptionsBySessionId.values().forEach(map -> map.values() | |
100 | - .forEach(sub -> pushSubscriptionToManagerService(sub, true))); | |
101 | - } | |
116 | + clusterTopologyChangeListener.onApplicationEvent(event); | |
102 | 117 | } |
103 | 118 | |
104 | 119 | //TODO 3.1: replace null callbacks with callbacks from websocket service. |
... | ... | @@ -123,6 +138,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer |
123 | 138 | } |
124 | 139 | |
125 | 140 | @Override |
141 | + @SuppressWarnings("unchecked") | |
126 | 142 | public void onSubscriptionUpdate(String sessionId, TelemetrySubscriptionUpdate update, TbCallback callback) { |
127 | 143 | TbSubscription subscription = subscriptionsBySessionId |
128 | 144 | .getOrDefault(sessionId, Collections.emptyMap()).get(update.getSubscriptionId()); |
... | ... | @@ -143,6 +159,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer |
143 | 159 | } |
144 | 160 | |
145 | 161 | @Override |
162 | + @SuppressWarnings("unchecked") | |
146 | 163 | public void onSubscriptionUpdate(String sessionId, AlarmSubscriptionUpdate update, TbCallback callback) { |
147 | 164 | TbSubscription subscription = subscriptionsBySessionId |
148 | 165 | .getOrDefault(sessionId, Collections.emptyMap()).get(update.getSubscriptionId()); | ... | ... |
... | ... | @@ -107,7 +107,7 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends |
107 | 107 | public void setAndResolveQuery(T query) { |
108 | 108 | dynamicValues.clear(); |
109 | 109 | this.query = query; |
110 | - if (query.getKeyFilters() != null) { | |
110 | + if (query != null && query.getKeyFilters() != null) { | |
111 | 111 | for (KeyFilter filter : query.getKeyFilters()) { |
112 | 112 | registerDynamicValues(filter.getPredicate()); |
113 | 113 | } |
... | ... | @@ -264,6 +264,7 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends |
264 | 264 | }, MoreExecutors.directExecutor()); |
265 | 265 | } |
266 | 266 | |
267 | + @SuppressWarnings("unchecked") | |
267 | 268 | private void updateDynamicValuesByKey(DynamicValueKeySub sub, TsValue tsValue) { |
268 | 269 | DynamicValueKey dvk = sub.getKey(); |
269 | 270 | switch (dvk.getPredicateType()) { |
... | ... | @@ -285,6 +286,7 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends |
285 | 286 | } |
286 | 287 | } |
287 | 288 | |
289 | + @SuppressWarnings("unchecked") | |
288 | 290 | private void registerDynamicValues(KeyFilterPredicate predicate) { |
289 | 291 | switch (predicate.getType()) { |
290 | 292 | case STRING: | ... | ... |
... | ... | @@ -41,6 +41,7 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService; |
41 | 41 | import org.thingsboard.server.gen.transport.TransportProtos; |
42 | 42 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; |
43 | 43 | import org.thingsboard.server.queue.discovery.PartitionService; |
44 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
44 | 45 | import org.thingsboard.server.service.queue.TbClusterService; |
45 | 46 | import org.thingsboard.server.service.subscription.SubscriptionManagerService; |
46 | 47 | import org.thingsboard.server.service.subscription.TbSubscriptionUtils; |
... | ... | @@ -61,7 +62,7 @@ import java.util.function.Consumer; |
61 | 62 | * Created by ashvayka on 27.03.18. |
62 | 63 | */ |
63 | 64 | @Slf4j |
64 | -public abstract class AbstractSubscriptionService implements ApplicationListener<PartitionChangeEvent> { | |
65 | +public abstract class AbstractSubscriptionService extends TbApplicationEventListener<PartitionChangeEvent>{ | |
65 | 66 | |
66 | 67 | protected final Set<TopicPartitionInfo> currentPartitions = ConcurrentHashMap.newKeySet(); |
67 | 68 | |
... | ... | @@ -97,8 +98,7 @@ public abstract class AbstractSubscriptionService implements ApplicationListener |
97 | 98 | } |
98 | 99 | |
99 | 100 | @Override |
100 | - @EventListener(PartitionChangeEvent.class) | |
101 | - public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
101 | + protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { | |
102 | 102 | if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { |
103 | 103 | currentPartitions.clear(); |
104 | 104 | currentPartitions.addAll(partitionChangeEvent.getPartitions()); | ... | ... |
... | ... | @@ -34,6 +34,8 @@ import java.util.UUID; |
34 | 34 | @Data |
35 | 35 | public class TransportToDeviceActorMsgWrapper implements TbActorMsg, DeviceAwareMsg, TenantAwareMsg, Serializable { |
36 | 36 | |
37 | + private static final long serialVersionUID = 7191333353202935941L; | |
38 | + | |
37 | 39 | private final TenantId tenantId; |
38 | 40 | private final DeviceId deviceId; |
39 | 41 | private final TransportToDeviceActorMsg msg; | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.utils; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | + | |
20 | +import java.util.concurrent.Executor; | |
21 | +import java.util.concurrent.ExecutorService; | |
22 | +import java.util.function.Consumer; | |
23 | + | |
24 | +/** | |
25 | + * This class deduplicate executions of the specified function. | |
26 | + * Useful in cluster mode, when you get event about partition change multiple times. | |
27 | + * Assuming that the function execution is expensive, we should execute it immediately when first time event occurs and | |
28 | + * later, once the processing of first event is done, process last pending task. | |
29 | + * | |
30 | + * @param <P> parameters of the function | |
31 | + */ | |
32 | +@Slf4j | |
33 | +public class EventDeduplicationExecutor<P> { | |
34 | + private final String name; | |
35 | + private final ExecutorService executor; | |
36 | + private final Consumer<P> function; | |
37 | + private P pendingTask; | |
38 | + private boolean busy; | |
39 | + | |
40 | + public EventDeduplicationExecutor(String name, ExecutorService executor, Consumer<P> function) { | |
41 | + this.name = name; | |
42 | + this.executor = executor; | |
43 | + this.function = function; | |
44 | + } | |
45 | + | |
46 | + public void submit(P params) { | |
47 | + log.info("[{}] Going to submit: {}", name, params); | |
48 | + synchronized (EventDeduplicationExecutor.this) { | |
49 | + if (!busy) { | |
50 | + busy = true; | |
51 | + pendingTask = null; | |
52 | + try { | |
53 | + log.info("[{}] Submitting task: {}", name, params); | |
54 | + executor.submit(() -> { | |
55 | + try { | |
56 | + log.info("[{}] Executing task: {}", name, params); | |
57 | + function.accept(params); | |
58 | + } catch (Throwable e) { | |
59 | + log.warn("[{}] Failed to process task with parameters: {}", name, params, e); | |
60 | + throw e; | |
61 | + } finally { | |
62 | + unlockAndProcessIfAny(); | |
63 | + } | |
64 | + }); | |
65 | + } catch (Throwable e) { | |
66 | + log.warn("[{}] Failed to submit task with parameters: {}", name, params, e); | |
67 | + unlockAndProcessIfAny(); | |
68 | + throw e; | |
69 | + } | |
70 | + } else { | |
71 | + log.info("[{}] Task is already in progress. {} pending task: {}", name, pendingTask == null ? "adding" : "updating", params); | |
72 | + pendingTask = params; | |
73 | + } | |
74 | + } | |
75 | + } | |
76 | + | |
77 | + private void unlockAndProcessIfAny() { | |
78 | + synchronized (EventDeduplicationExecutor.this) { | |
79 | + busy = false; | |
80 | + if (pendingTask != null) { | |
81 | + submit(pendingTask); | |
82 | + } | |
83 | + } | |
84 | + } | |
85 | +} | ... | ... |
... | ... | @@ -34,6 +34,9 @@ |
34 | 34 | |
35 | 35 | <!-- <logger name="org.thingsboard.server.service.subscription" level="TRACE"/>--> |
36 | 36 | <!-- <logger name="org.thingsboard.server.service.telemetry" level="TRACE"/>--> |
37 | +<!-- <logger name="org.eclipse.californium.scandium.DTLSConnector" level="TRACE" />--> | |
38 | +<!-- <logger name="org.eclipse.californium.scandium.dtls.Handshaker" level="DEBUG" />--> | |
39 | + | |
37 | 40 | <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" /> |
38 | 41 | |
39 | 42 | <logger name="org.thingsboard.server.service.edge" level="INFO" /> |
... | ... | @@ -43,4 +46,4 @@ |
43 | 46 | </root> |
44 | 47 | |
45 | 48 | |
46 | -</configuration> | |
\ No newline at end of file | ||
49 | +</configuration> | ... | ... |
... | ... | @@ -118,6 +118,15 @@ security: |
118 | 118 | githubMapper: |
119 | 119 | emailUrl: "${SECURITY_OAUTH2_GITHUB_MAPPER_EMAIL_URL_KEY:https://api.github.com/user/emails}" |
120 | 120 | |
121 | +# Usage statistics parameters | |
122 | +usage: | |
123 | + stats: | |
124 | + report: | |
125 | + enabled: "${USAGE_STATS_REPORT_ENABLED:true}" | |
126 | + interval: "${USAGE_STATS_REPORT_INTERVAL:10}" | |
127 | + check: | |
128 | + cycle: "${USAGE_STATS_CHECK_CYCLE:60000}" | |
129 | + | |
121 | 130 | # Dashboard parameters |
122 | 131 | dashboard: |
123 | 132 | # Maximum allowed datapoints fetched by widgets |
... | ... | @@ -585,14 +594,14 @@ transport: |
585 | 594 | # model_path_file: "${LWM2M_MODEL_PATH_FILE:./common/transport/lwm2m/src/main/resources/models/}" |
586 | 595 | model_path_file: "${LWM2M_MODEL_PATH_FILE:}" |
587 | 596 | recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" |
588 | - recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:false}" | |
597 | + recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" | |
589 | 598 | request_pool_size: "${LWM2M_REQUEST_POOL_SIZE:100}" |
590 | 599 | request_error_pool_size: "${LWM2M_REQUEST_ERROR_POOL_SIZE:10}" |
591 | 600 | registered_pool_size: "${LWM2M_REGISTERED_POOL_SIZE:10}" |
592 | 601 | update_registered_pool_size: "${LWM2M_UPDATE_REGISTERED_POOL_SIZE:10}" |
593 | 602 | un_registered_pool_size: "${LWM2M_UN_REGISTERED_POOL_SIZE:10}" |
594 | 603 | secure: |
595 | - # Only Certificate_x509: | |
604 | + # Certificate_x509: | |
596 | 605 | # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format |
597 | 606 | # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh |
598 | 607 | key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}" |
... | ... | @@ -601,48 +610,38 @@ transport: |
601 | 610 | key_store_path_file: "${KEY_STORE_PATH_FILE:}" |
602 | 611 | key_store_password: "${LWM2M_KEYSTORE_PASSWORD_SERVER:server_ks_password}" |
603 | 612 | root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}" |
604 | - enable_gen_psk_rpk: "${ENABLE_GEN_PSK_RPK:true}" | |
613 | + enable_gen_new_key_psk_rpk: "${ENABLE_GEN_NEW_KEY_PSK_RPK:false}" | |
605 | 614 | server: |
606 | 615 | id: "${LWM2M_SERVER_ID:123}" |
607 | 616 | bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" |
608 | - bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_PSK:5685}" | |
609 | - bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_RPK:5687}" | |
610 | - bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_X509:5689}" | |
617 | + bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC:5685}" | |
611 | 618 | secure: |
612 | - bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" | |
613 | - start_psk: "${START_SERVER_PSK:true}" | |
614 | - start_rpk: "${START_SERVER_RPK:true}" | |
615 | - start_x509: "${START_SERVER_X509:true}" | |
616 | - bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK:5686}" | |
617 | - bind_port_rpk: "${LWM2M_BIND_PORT_SEC_RPK:5688}" | |
618 | - bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509:5690}" | |
619 | - # Only RPK: Public & Private Key | |
620 | -# create_rpk: "${CREATE_RPK:}" | |
621 | - public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}" | |
622 | - public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}" | |
623 | - private_s: "${LWM2M_SERVER_PRIVATE_S:274671fe40ce937b8a6352cf0a418e8a39e4bf0bb9bf74c910db953c20c73802}" | |
624 | - # Only Certificate_x509: | |
619 | + bind_address_security: "${LWM2M_BIND_ADDRESS_SECURITY:0.0.0.0}" | |
620 | + bind_port_security: "${LWM2M_BIND_PORT_SECURITY:5686}" | |
621 | + # create_rpk: "${CREATE_RPK:}" | |
622 | + # Only for RPK: Public & Private Key. If the keystore file is missing or not working | |
623 | + # - Public Key (Hex): [3059301306072a8648ce3d020106082a8648ce3d0301070342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b] | |
624 | + # - Private Key (Hex): [308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b], | |
625 | + # - Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)] | |
626 | + public_x: "${LWM2M_SERVER_PUBLIC_X:05064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f358}" | |
627 | + public_y: "${LWM2M_SERVER_PUBLIC_Y:5eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" | |
628 | + private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED:308193020100301306072a8648ce3d020106082a8648ce3d030107047930770201010420dc774b309e547ceb48fee547e104ce201a9c48c449dc5414cd04e7f5cf05f67ba00a06082a8648ce3d030107a1440342000405064b9e6762dd8d8b8a52355d7b4d8b9a3d64e6d2ee277d76c248861353f3585eeb1838e4f9e37b31fa347aef5ce3431eb54e0a2506910c5e0298817445721b}" # Only Certificate_x509: | |
625 | 629 | alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}" |
626 | 630 | bootstrap: |
627 | - enable: "${BOOTSTRAP:true}" | |
631 | + enable: "${LWM2M_BOOTSTRAP_ENABLED:true}" | |
628 | 632 | id: "${LWM2M_SERVER_ID:111}" |
629 | 633 | bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" |
630 | - bind_port_no_sec_psk: "${LWM2M_BIND_PORT_NO_SEC_BS:5691}" | |
631 | - bind_port_no_sec_rpk: "${LWM2M_BIND_PORT_NO_SEC_BS:5693}" | |
632 | - bind_port_no_sec_x509: "${LWM2M_BIND_PORT_NO_SEC_BS:5695}" | |
634 | + bind_port_no_sec: "${LWM2M_BIND_PORT_NO_SEC_BS:5687}" | |
633 | 635 | secure: |
634 | - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" | |
635 | - start_psk: "${START_SERVER_PSK_BS:true}" | |
636 | - start_rpk: "${START_SERVER_RPK_BS:true}" | |
637 | - start_x509: "${START_SERVER_X509_BS:true}" | |
638 | - bind_port_psk: "${LWM2M_BIND_PORT_SEC_PSK_BS:5692}" | |
639 | - bind_port_rpk: "${LWM2M_BIND_PORT_SER_RPK_BS:5694}" | |
640 | - bind_port_x509: "${LWM2M_BIND_PORT_SEC_X509_BS:5696}" | |
641 | - # Only RPK: Public & Private Key | |
642 | - public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}" | |
643 | - public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}" | |
644 | - private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}" | |
645 | - # Only Certificate_x509: | |
636 | + bind_address_security: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}" | |
637 | + bind_port_security: "${LWM2M_BIND_PORT_SEC_BS:5688}" | |
638 | + # Only for RPK: Public & Private Key. If the keystore file is missing or not working | |
639 | + # - Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)] | |
640 | + # - Public Key (Hex): [3059301306072a8648ce3d020106082a8648ce3d030107034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34] | |
641 | + # - Private Key (Hex): [308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34], | |
642 | + public_x: "${LWM2M_SERVER_PUBLIC_X_BS:5017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f91}" | |
643 | + public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" | |
644 | + private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" # Only Certificate_x509: | |
646 | 645 | alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}" |
647 | 646 | # Redis |
648 | 647 | redis_url: "${LWM2M_REDIS_URL:''}" |
... | ... | @@ -713,6 +712,10 @@ queue: |
713 | 712 | transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" |
714 | 713 | notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" |
715 | 714 | js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}" |
715 | + consumer-stats: | |
716 | + enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}" | |
717 | + print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" | |
718 | + kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" | |
716 | 719 | aws_sqs: |
717 | 720 | use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" |
718 | 721 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" | ... | ... |
... | ... | @@ -377,6 +377,10 @@ public abstract class AbstractWebTest { |
377 | 377 | return readResponse(doGetAsync(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass); |
378 | 378 | } |
379 | 379 | |
380 | + protected <T> T doGetAsyncTyped(String urlTemplate, TypeReference<T> responseType, Object... urlVariables) throws Exception { | |
381 | + return readResponse(doGetAsync(urlTemplate, urlVariables).andExpect(status().isOk()), responseType); | |
382 | + } | |
383 | + | |
380 | 384 | protected ResultActions doGetAsync(String urlTemplate, Object... urlVariables) throws Exception { |
381 | 385 | MockHttpServletRequestBuilder getRequest; |
382 | 386 | getRequest = get(urlTemplate, urlVariables); | ... | ... |
... | ... | @@ -352,8 +352,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
352 | 352 | |
353 | 353 | Thread.sleep(1000); |
354 | 354 | |
355 | - List<Map<String, Object>> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + | |
356 | - "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); | |
355 | + List<Map<String, Object>> values = doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + | |
356 | + "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); | |
357 | 357 | |
358 | 358 | assertEquals("value1", getValue(values, "caKey1")); |
359 | 359 | assertEquals(true, getValue(values, "caKey2")); |
... | ... | @@ -369,8 +369,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
369 | 369 | Set<String> expectedActualAttributesSet = new HashSet<>(Arrays.asList("caKey1", "caKey2", "caKey3", "caKey4")); |
370 | 370 | assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); |
371 | 371 | |
372 | - List<Map<String, Object>> valueTelemetryOfDevices = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + | |
373 | - "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); | |
372 | + List<Map<String, Object>> valueTelemetryOfDevices = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + | |
373 | + "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); | |
374 | 374 | |
375 | 375 | EntityView view = new EntityView(); |
376 | 376 | view.setEntityId(testDevice.getId()); |
... | ... | @@ -384,8 +384,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
384 | 384 | |
385 | 385 | Thread.sleep(1000); |
386 | 386 | |
387 | - List<Map<String, Object>> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + | |
388 | - "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); | |
387 | + List<Map<String, Object>> values = doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + | |
388 | + "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); | |
389 | 389 | assertEquals(0, values.size()); |
390 | 390 | } |
391 | 391 | |
... | ... | @@ -454,12 +454,12 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
454 | 454 | } |
455 | 455 | |
456 | 456 | private Set<String> getTelemetryKeys(String type, String id) throws Exception { |
457 | - return new HashSet<>(doGetAsync("/api/plugins/telemetry/" + type + "/" + id + "/keys/timeseries", List.class)); | |
457 | + return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + "/keys/timeseries", new TypeReference<>() {})); | |
458 | 458 | } |
459 | 459 | |
460 | 460 | private Map<String, List<Map<String, String>>> getTelemetryValues(String type, String id, Set<String> keys, Long startTs, Long endTs) throws Exception { |
461 | - return doGetAsync("/api/plugins/telemetry/" + type + "/" + id + | |
462 | - "/values/timeseries?keys=" + String.join(",", keys) + "&startTs=" + startTs + "&endTs=" + endTs, Map.class); | |
461 | + return doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + | |
462 | + "/values/timeseries?keys=" + String.join(",", keys) + "&startTs=" + startTs + "&endTs=" + endTs, new TypeReference<>() {}); | |
463 | 463 | } |
464 | 464 | |
465 | 465 | private Set<String> getAttributesByKeys(String stringKV) throws Exception { |
... | ... | @@ -484,7 +484,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
484 | 484 | client.publish("v1/devices/me/attributes", message); |
485 | 485 | Thread.sleep(1000); |
486 | 486 | client.disconnect(); |
487 | - return new HashSet<>(doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class)); | |
487 | + return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", new TypeReference<>() {})); | |
488 | 488 | } |
489 | 489 | |
490 | 490 | private Object getValue(List<Map<String, Object>> values, String stringValue) { | ... | ... |
... | ... | @@ -26,7 +26,7 @@ import com.google.protobuf.AbstractMessage; |
26 | 26 | import com.google.protobuf.InvalidProtocolBufferException; |
27 | 27 | import com.google.protobuf.MessageLite; |
28 | 28 | import lombok.extern.slf4j.Slf4j; |
29 | -import org.apache.commons.lang.RandomStringUtils; | |
29 | +import org.apache.commons.lang3.RandomStringUtils; | |
30 | 30 | import org.junit.After; |
31 | 31 | import org.junit.Assert; |
32 | 32 | import org.junit.Before; |
... | ... | @@ -1216,12 +1216,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { |
1216 | 1216 | |
1217 | 1217 | // Wait before device attributes saved to database before requesting them from controller |
1218 | 1218 | Thread.sleep(1000); |
1219 | - Map<String, List<Map<String, String>>> timeseries = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getUuidId() + "/values/timeseries?keys=" + timeseriesKey, Map.class); | |
1219 | + Map<String, List<Map<String, String>>> timeseries = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getUuidId() + "/values/timeseries?keys=" + timeseriesKey, new TypeReference<>() {}); | |
1220 | 1220 | Assert.assertTrue(timeseries.containsKey(timeseriesKey)); |
1221 | 1221 | Assert.assertEquals(1, timeseries.get(timeseriesKey).size()); |
1222 | 1222 | Assert.assertEquals(timeseriesValue, timeseries.get(timeseriesKey).get(0).get("value")); |
1223 | 1223 | |
1224 | - List<Map<String, String>> attributes = doGetAsync("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/attributes/" + DataConstants.SERVER_SCOPE, List.class); | |
1224 | + List<Map<String, String>> attributes = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId() + "/values/attributes/" + DataConstants.SERVER_SCOPE, new TypeReference<>() {}); | |
1225 | 1225 | Assert.assertEquals(1, attributes.size()); |
1226 | 1226 | Assert.assertEquals(attributes.get(0).get("key"), attributesKey); |
1227 | 1227 | Assert.assertEquals(attributes.get(0).get("value"), attributesValue); | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.mqtt.telemetry.attributes; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.core.JsonProcessingException; |
19 | +import com.fasterxml.jackson.core.type.TypeReference; | |
19 | 20 | import lombok.extern.slf4j.Slf4j; |
20 | 21 | import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
21 | 22 | import org.junit.After; |
... | ... | @@ -80,7 +81,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt |
80 | 81 | |
81 | 82 | List<String> actualKeys = null; |
82 | 83 | while (start <= end) { |
83 | - actualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", List.class); | |
84 | + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {}); | |
84 | 85 | if (actualKeys.size() == expectedKeys.size()) { |
85 | 86 | break; |
86 | 87 | } |
... | ... | @@ -96,7 +97,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt |
96 | 97 | assertEquals(expectedKeySet, actualKeySet); |
97 | 98 | |
98 | 99 | String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); |
99 | - List<Map<String, Object>> values = doGetAsync(getAttributesValuesUrl, List.class); | |
100 | + List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {}); | |
100 | 101 | assertAttributesValues(values, expectedKeySet); |
101 | 102 | String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); |
102 | 103 | doDelete(deleteAttributesUrl); |
... | ... | @@ -121,10 +122,10 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt |
121 | 122 | |
122 | 123 | Thread.sleep(2000); |
123 | 124 | |
124 | - List<String> firstDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/attributes/CLIENT_SCOPE", List.class); | |
125 | + List<String> firstDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {}); | |
125 | 126 | Set<String> firstDeviceActualKeySet = new HashSet<>(firstDeviceActualKeys); |
126 | 127 | |
127 | - List<String> secondDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/attributes/CLIENT_SCOPE", List.class); | |
128 | + List<String> secondDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {}); | |
128 | 129 | Set<String> secondDeviceActualKeySet = new HashSet<>(secondDeviceActualKeys); |
129 | 130 | |
130 | 131 | Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
... | ... | @@ -135,14 +136,15 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt |
135 | 136 | String getAttributesValuesUrlFirstDevice = getAttributesValuesUrl(firstDevice.getId(), firstDeviceActualKeySet); |
136 | 137 | String getAttributesValuesUrlSecondDevice = getAttributesValuesUrl(firstDevice.getId(), secondDeviceActualKeySet); |
137 | 138 | |
138 | - List<Map<String, Object>> firstDeviceValues = doGetAsync(getAttributesValuesUrlFirstDevice, List.class); | |
139 | - List<Map<String, Object>> secondDeviceValues = doGetAsync(getAttributesValuesUrlSecondDevice, List.class); | |
139 | + List<Map<String, Object>> firstDeviceValues = doGetAsyncTyped(getAttributesValuesUrlFirstDevice, new TypeReference<>() {}); | |
140 | + List<Map<String, Object>> secondDeviceValues = doGetAsyncTyped(getAttributesValuesUrlSecondDevice, new TypeReference<>() {}); | |
140 | 141 | |
141 | 142 | assertAttributesValues(firstDeviceValues, expectedKeySet); |
142 | 143 | assertAttributesValues(secondDeviceValues, expectedKeySet); |
143 | 144 | |
144 | 145 | } |
145 | 146 | |
147 | + @SuppressWarnings("unchecked") | |
146 | 148 | protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) throws JsonProcessingException { |
147 | 149 | for (Map<String, Object> map : deviceValues) { |
148 | 150 | String key = (String) map.get("key"); | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.mqtt.telemetry.timeseries; |
17 | 17 | |
18 | +import com.fasterxml.jackson.core.type.TypeReference; | |
18 | 19 | import io.netty.handler.codec.mqtt.MqttQoS; |
19 | 20 | import lombok.extern.slf4j.Slf4j; |
20 | 21 | import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
... | ... | @@ -25,6 +26,7 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; |
25 | 26 | import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; |
26 | 27 | import org.junit.After; |
27 | 28 | import org.junit.Before; |
29 | +import org.junit.Ignore; | |
28 | 30 | import org.junit.Test; |
29 | 31 | import org.thingsboard.server.common.data.Device; |
30 | 32 | import org.thingsboard.server.common.data.device.profile.MqttTopics; |
... | ... | @@ -107,7 +109,7 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt |
107 | 109 | |
108 | 110 | List<String> actualKeys = null; |
109 | 111 | while (start <= end) { |
110 | - actualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", List.class); | |
112 | + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() {}); | |
111 | 113 | if (actualKeys.size() == expectedKeys.size()) { |
112 | 114 | break; |
113 | 115 | } |
... | ... | @@ -129,13 +131,13 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt |
129 | 131 | } |
130 | 132 | start = System.currentTimeMillis(); |
131 | 133 | end = System.currentTimeMillis() + 5000; |
132 | - Map<String, List<Map<String, String>>> values = null; | |
134 | + Map<String, List<Map<String, Object>>> values = null; | |
133 | 135 | while (start <= end) { |
134 | - values = doGetAsync(getTelemetryValuesUrl, Map.class); | |
136 | + values = doGetAsyncTyped(getTelemetryValuesUrl, new TypeReference<>() {}); | |
135 | 137 | boolean valid = values.size() == expectedKeys.size(); |
136 | 138 | if (valid) { |
137 | 139 | for (String key : expectedKeys) { |
138 | - List<Map<String, String>> tsValues = values.get(key); | |
140 | + List<Map<String, Object>> tsValues = values.get(key); | |
139 | 141 | if (tsValues != null && tsValues.size() > 0) { |
140 | 142 | Object ts = tsValues.get(0).get("ts"); |
141 | 143 | if (ts == null) { |
... | ... | @@ -181,10 +183,10 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt |
181 | 183 | |
182 | 184 | Thread.sleep(2000); |
183 | 185 | |
184 | - List<String> firstDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/timeseries", List.class); | |
186 | + List<String> firstDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/timeseries", new TypeReference<>() {}); | |
185 | 187 | Set<String> firstDeviceActualKeySet = new HashSet<>(firstDeviceActualKeys); |
186 | 188 | |
187 | - List<String> secondDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/timeseries", List.class); | |
189 | + List<String> secondDeviceActualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/timeseries", new TypeReference<>() {}); | |
188 | 190 | Set<String> secondDeviceActualKeySet = new HashSet<>(secondDeviceActualKeys); |
189 | 191 | |
190 | 192 | Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
... | ... | @@ -195,8 +197,8 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt |
195 | 197 | String getTelemetryValuesUrlFirstDevice = getTelemetryValuesUrl(firstDevice.getId(), firstDeviceActualKeySet); |
196 | 198 | String getTelemetryValuesUrlSecondDevice = getTelemetryValuesUrl(firstDevice.getId(), secondDeviceActualKeySet); |
197 | 199 | |
198 | - Map<String, List<Map<String, String>>> firstDeviceValues = doGetAsync(getTelemetryValuesUrlFirstDevice, Map.class); | |
199 | - Map<String, List<Map<String, String>>> secondDeviceValues = doGetAsync(getTelemetryValuesUrlSecondDevice, Map.class); | |
200 | + Map<String, List<Map<String, Object>>> firstDeviceValues = doGetAsyncTyped(getTelemetryValuesUrlFirstDevice, new TypeReference<>() {}); | |
201 | + Map<String, List<Map<String, Object>>> secondDeviceValues = doGetAsyncTyped(getTelemetryValuesUrlSecondDevice, new TypeReference<>() {}); | |
200 | 202 | |
201 | 203 | assertGatewayDeviceData(firstDeviceValues, expectedKeys); |
202 | 204 | assertGatewayDeviceData(secondDeviceValues, expectedKeys); |
... | ... | @@ -212,7 +214,7 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt |
212 | 214 | return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?startTs=0&endTs=25000&keys=" + String.join(",", actualKeySet); |
213 | 215 | } |
214 | 216 | |
215 | - private void assertGatewayDeviceData(Map<String, List<Map<String, String>>> deviceValues, List<String> expectedKeys) { | |
217 | + private void assertGatewayDeviceData(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys) { | |
216 | 218 | |
217 | 219 | assertEquals(2, deviceValues.get(expectedKeys.get(0)).size()); |
218 | 220 | assertEquals(2, deviceValues.get(expectedKeys.get(1)).size()); |
... | ... | @@ -228,11 +230,11 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt |
228 | 230 | |
229 | 231 | } |
230 | 232 | |
231 | - private void assertValues(Map<String, List<Map<String, String>>> deviceValues, int arrayIndex) { | |
232 | - for (Map.Entry<String, List<Map<String, String>>> entry : deviceValues.entrySet()) { | |
233 | + private void assertValues(Map<String, List<Map<String, Object>>> deviceValues, int arrayIndex) { | |
234 | + for (Map.Entry<String, List<Map<String, Object>>> entry : deviceValues.entrySet()) { | |
233 | 235 | String key = entry.getKey(); |
234 | - List<Map<String, String>> tsKv = entry.getValue(); | |
235 | - String value = tsKv.get(arrayIndex).get("value"); | |
236 | + List<Map<String, Object>> tsKv = entry.getValue(); | |
237 | + String value = (String) tsKv.get(arrayIndex).get("value"); | |
236 | 238 | switch (key) { |
237 | 239 | case "key1": |
238 | 240 | assertEquals("value1", value); |
... | ... | @@ -253,7 +255,7 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt |
253 | 255 | } |
254 | 256 | } |
255 | 257 | |
256 | - private void assertTs(Map<String, List<Map<String, String>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) { | |
258 | + private void assertTs(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) { | |
257 | 259 | assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts")); |
258 | 260 | assertEquals(ts, deviceValues.get(expectedKeys.get(1)).get(arrayIndex).get("ts")); |
259 | 261 | assertEquals(ts, deviceValues.get(expectedKeys.get(2)).get(arrayIndex).get("ts")); | ... | ... |
... | ... | @@ -21,12 +21,11 @@ import org.junit.Assert; |
21 | 21 | import org.junit.Before; |
22 | 22 | import org.junit.Test; |
23 | 23 | import org.junit.runner.RunWith; |
24 | -import org.mockito.runners.MockitoJUnitRunner; | |
24 | +import org.mockito.junit.MockitoJUnitRunner; | |
25 | 25 | import org.springframework.context.ApplicationEventPublisher; |
26 | 26 | import org.springframework.test.util.ReflectionTestUtils; |
27 | 27 | import org.thingsboard.server.common.data.id.DeviceId; |
28 | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | -import org.thingsboard.server.common.msg.queue.ServiceQueue; | |
30 | 29 | import org.thingsboard.server.queue.discovery.HashPartitionService; |
31 | 30 | import org.thingsboard.server.common.msg.queue.ServiceType; |
32 | 31 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | ... | ... |
... | ... | @@ -20,7 +20,7 @@ import org.junit.Assert; |
20 | 20 | import org.junit.Test; |
21 | 21 | import org.junit.runner.RunWith; |
22 | 22 | import org.mockito.Mockito; |
23 | -import org.mockito.runners.MockitoJUnitRunner; | |
23 | +import org.mockito.junit.MockitoJUnitRunner; | |
24 | 24 | import org.thingsboard.server.gen.transport.TransportProtos; |
25 | 25 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
26 | 26 | import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; | ... | ... |
application/src/test/java/org/thingsboard/server/util/EventDeduplicationExecutorTest.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.util; | |
17 | + | |
18 | +import com.google.common.util.concurrent.MoreExecutors; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.junit.Test; | |
21 | +import org.junit.runner.RunWith; | |
22 | +import org.mockito.Mockito; | |
23 | +import org.mockito.junit.MockitoJUnitRunner; | |
24 | +import org.thingsboard.server.utils.EventDeduplicationExecutor; | |
25 | + | |
26 | +import java.util.concurrent.ExecutorService; | |
27 | +import java.util.concurrent.Executors; | |
28 | +import java.util.function.Consumer; | |
29 | + | |
30 | +@Slf4j | |
31 | +@RunWith(MockitoJUnitRunner.class) | |
32 | +public class EventDeduplicationExecutorTest { | |
33 | + | |
34 | + @Test | |
35 | + public void testSimpleFlowSameThread() throws InterruptedException { | |
36 | + simpleFlow(MoreExecutors.newDirectExecutorService()); | |
37 | + } | |
38 | + | |
39 | + @Test | |
40 | + public void testPeriodicFlowSameThread() throws InterruptedException { | |
41 | + periodicFlow(MoreExecutors.newDirectExecutorService()); | |
42 | + } | |
43 | + | |
44 | + @Test | |
45 | + public void testExceptionFlowSameThread() throws InterruptedException { | |
46 | + exceptionFlow(MoreExecutors.newDirectExecutorService()); | |
47 | + } | |
48 | + | |
49 | + @Test | |
50 | + public void testSimpleFlowSingleThread() throws InterruptedException { | |
51 | + simpleFlow(Executors.newSingleThreadExecutor()); | |
52 | + } | |
53 | + | |
54 | + @Test | |
55 | + public void testPeriodicFlowSingleThread() throws InterruptedException { | |
56 | + periodicFlow(Executors.newSingleThreadExecutor()); | |
57 | + } | |
58 | + | |
59 | + @Test | |
60 | + public void testExceptionFlowSingleThread() throws InterruptedException { | |
61 | + exceptionFlow(Executors.newSingleThreadExecutor()); | |
62 | + } | |
63 | + | |
64 | + @Test | |
65 | + public void testSimpleFlowMultiThread() throws InterruptedException { | |
66 | + simpleFlow(Executors.newFixedThreadPool(3)); | |
67 | + } | |
68 | + | |
69 | + @Test | |
70 | + public void testPeriodicFlowMultiThread() throws InterruptedException { | |
71 | + periodicFlow(Executors.newFixedThreadPool(3)); | |
72 | + } | |
73 | + | |
74 | + @Test | |
75 | + public void testExceptionFlowMultiThread() throws InterruptedException { | |
76 | + exceptionFlow(Executors.newFixedThreadPool(3)); | |
77 | + } | |
78 | + | |
79 | + private void simpleFlow(ExecutorService executorService) throws InterruptedException { | |
80 | + try { | |
81 | + Consumer<String> function = Mockito.spy(StringConsumer.class); | |
82 | + EventDeduplicationExecutor<String> executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function); | |
83 | + | |
84 | + String params1 = "params1"; | |
85 | + String params2 = "params2"; | |
86 | + String params3 = "params3"; | |
87 | + | |
88 | + executor.submit(params1); | |
89 | + executor.submit(params2); | |
90 | + executor.submit(params3); | |
91 | + Thread.sleep(500); | |
92 | + Mockito.verify(function).accept(params1); | |
93 | + Mockito.verify(function).accept(params3); | |
94 | + } finally { | |
95 | + executorService.shutdownNow(); | |
96 | + } | |
97 | + } | |
98 | + | |
99 | + private void periodicFlow(ExecutorService executorService) throws InterruptedException { | |
100 | + try { | |
101 | + Consumer<String> function = Mockito.spy(StringConsumer.class); | |
102 | + EventDeduplicationExecutor<String> executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function); | |
103 | + | |
104 | + String params1 = "params1"; | |
105 | + String params2 = "params2"; | |
106 | + String params3 = "params3"; | |
107 | + | |
108 | + executor.submit(params1); | |
109 | + Thread.sleep(500); | |
110 | + executor.submit(params2); | |
111 | + Thread.sleep(500); | |
112 | + executor.submit(params3); | |
113 | + Thread.sleep(500); | |
114 | + Mockito.verify(function).accept(params1); | |
115 | + Mockito.verify(function).accept(params2); | |
116 | + Mockito.verify(function).accept(params3); | |
117 | + } finally { | |
118 | + executorService.shutdownNow(); | |
119 | + } | |
120 | + } | |
121 | + | |
122 | + private void exceptionFlow(ExecutorService executorService) throws InterruptedException { | |
123 | + try { | |
124 | + Consumer<String> function = Mockito.spy(StringConsumer.class); | |
125 | + EventDeduplicationExecutor<String> executor = new EventDeduplicationExecutor<>(EventDeduplicationExecutorTest.class.getSimpleName(), executorService, function); | |
126 | + | |
127 | + String params1 = "params1"; | |
128 | + String params2 = "params2"; | |
129 | + String params3 = "params3"; | |
130 | + | |
131 | + Mockito.doThrow(new RuntimeException()).when(function).accept("params1"); | |
132 | + executor.submit(params1); | |
133 | + executor.submit(params2); | |
134 | + Thread.sleep(500); | |
135 | + executor.submit(params3); | |
136 | + Thread.sleep(500); | |
137 | + Mockito.verify(function).accept(params2); | |
138 | + Mockito.verify(function).accept(params3); | |
139 | + } finally { | |
140 | + executorService.shutdownNow(); | |
141 | + } | |
142 | + } | |
143 | + | |
144 | + public static class StringConsumer implements Consumer<String> { | |
145 | + @Override | |
146 | + public void accept(String s) { | |
147 | + try { | |
148 | + Thread.sleep(100); | |
149 | + } catch (InterruptedException e) { | |
150 | + throw new RuntimeException(e); | |
151 | + } | |
152 | + } | |
153 | + } | |
154 | + | |
155 | +} | ... | ... |
... | ... | @@ -30,7 +30,7 @@ public interface TbActor { |
30 | 30 | } |
31 | 31 | |
32 | 32 | default InitFailureStrategy onInitFailure(int attempt, Throwable t) { |
33 | - return InitFailureStrategy.retryWithDelay(5000 * attempt); | |
33 | + return InitFailureStrategy.retryWithDelay(5000L * attempt); | |
34 | 34 | } |
35 | 35 | |
36 | 36 | default ProcessFailureStrategy onProcessFailure(Throwable t) { | ... | ... |
... | ... | @@ -17,6 +17,8 @@ package org.thingsboard.server.actors; |
17 | 17 | |
18 | 18 | public class TbActorException extends Exception { |
19 | 19 | |
20 | + private static final long serialVersionUID = 8209771144711980882L; | |
21 | + | |
20 | 22 | public TbActorException(String message, Throwable cause) { |
21 | 23 | super(message, cause); |
22 | 24 | } | ... | ... |
... | ... | @@ -17,7 +17,9 @@ package org.thingsboard.server.actors; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.thingsboard.server.common.msg.MsgType; | |
20 | 21 | import org.thingsboard.server.common.msg.TbActorMsg; |
22 | +import org.thingsboard.server.common.msg.TbActorStopReason; | |
21 | 23 | |
22 | 24 | import java.util.List; |
23 | 25 | import java.util.concurrent.ConcurrentLinkedQueue; |
... | ... | @@ -49,6 +51,7 @@ public final class TbActorMailbox implements TbActorCtx { |
49 | 51 | private final AtomicBoolean busy = new AtomicBoolean(FREE); |
50 | 52 | private final AtomicBoolean ready = new AtomicBoolean(NOT_READY); |
51 | 53 | private final AtomicBoolean destroyInProgress = new AtomicBoolean(); |
54 | + private volatile TbActorStopReason stopReason; | |
52 | 55 | |
53 | 56 | public void initActor() { |
54 | 57 | dispatcher.getExecutor().execute(() -> tryInit(1)); |
... | ... | @@ -70,7 +73,8 @@ public final class TbActorMailbox implements TbActorCtx { |
70 | 73 | InitFailureStrategy strategy = actor.onInitFailure(attempt, t); |
71 | 74 | if (strategy.isStop() || (settings.getMaxActorInitAttempts() > 0 && attemptIdx > settings.getMaxActorInitAttempts())) { |
72 | 75 | log.info("[{}] Failed to init actor, attempt {}, going to stop attempts.", selfId, attempt, t); |
73 | - system.stop(selfId); | |
76 | + stopReason = TbActorStopReason.INIT_FAILED; | |
77 | + destroy(); | |
74 | 78 | } else if (strategy.getRetryDelay() > 0) { |
75 | 79 | log.info("[{}] Failed to init actor, attempt {}, going to retry in attempts in {}ms", selfId, attempt, strategy.getRetryDelay()); |
76 | 80 | log.debug("[{}] Error", selfId, t); |
... | ... | @@ -84,12 +88,28 @@ public final class TbActorMailbox implements TbActorCtx { |
84 | 88 | } |
85 | 89 | |
86 | 90 | private void enqueue(TbActorMsg msg, boolean highPriority) { |
87 | - if (highPriority) { | |
88 | - highPriorityMsgs.add(msg); | |
91 | + if (!destroyInProgress.get()) { | |
92 | + if (highPriority) { | |
93 | + highPriorityMsgs.add(msg); | |
94 | + } else { | |
95 | + normalPriorityMsgs.add(msg); | |
96 | + } | |
97 | + tryProcessQueue(true); | |
89 | 98 | } else { |
90 | - normalPriorityMsgs.add(msg); | |
99 | + if (highPriority && msg.getMsgType().equals(MsgType.RULE_NODE_UPDATED_MSG)) { | |
100 | + synchronized (this) { | |
101 | + if (stopReason == TbActorStopReason.INIT_FAILED) { | |
102 | + destroyInProgress.set(false); | |
103 | + stopReason = null; | |
104 | + initActor(); | |
105 | + } else { | |
106 | + msg.onTbActorStopped(stopReason); | |
107 | + } | |
108 | + } | |
109 | + } else { | |
110 | + msg.onTbActorStopped(stopReason); | |
111 | + } | |
91 | 112 | } |
92 | - tryProcessQueue(true); | |
93 | 113 | } |
94 | 114 | |
95 | 115 | private void tryProcessQueue(boolean newMsg) { |
... | ... | @@ -119,6 +139,9 @@ public final class TbActorMailbox implements TbActorCtx { |
119 | 139 | try { |
120 | 140 | log.debug("[{}] Going to process message: {}", selfId, msg); |
121 | 141 | actor.process(msg); |
142 | + } catch (TbRuleNodeUpdateException updateException){ | |
143 | + stopReason = TbActorStopReason.INIT_FAILED; | |
144 | + destroy(); | |
122 | 145 | } catch (Throwable t) { |
123 | 146 | log.debug("[{}] Failed to process message: {}", selfId, msg, t); |
124 | 147 | ProcessFailureStrategy strategy = actor.onProcessFailure(t); |
... | ... | @@ -180,11 +203,16 @@ public final class TbActorMailbox implements TbActorCtx { |
180 | 203 | } |
181 | 204 | |
182 | 205 | public void destroy() { |
206 | + if (stopReason == null) { | |
207 | + stopReason = TbActorStopReason.STOPPED; | |
208 | + } | |
183 | 209 | destroyInProgress.set(true); |
184 | 210 | dispatcher.getExecutor().execute(() -> { |
185 | 211 | try { |
186 | 212 | ready.set(NOT_READY); |
187 | 213 | actor.destroy(); |
214 | + highPriorityMsgs.forEach(msg -> msg.onTbActorStopped(stopReason)); | |
215 | + normalPriorityMsgs.forEach(msg -> msg.onTbActorStopped(stopReason)); | |
188 | 216 | } catch (Throwable t) { |
189 | 217 | log.warn("[{}] Failed to destroy actor: {}", selfId, t); |
190 | 218 | } | ... | ... |
common/actor/src/main/java/org/thingsboard/server/actors/TbRuleNodeUpdateException.java
renamed from
ui/src/app/edge/downlinks/edge-downlinks-header.directive.js
1 | -/* | |
2 | - * Copyright © 2016-2020 The Thingsboard Authors | |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | 3 | * |
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 5 | * you may not use this file except in compliance with the License. |
... | ... | @@ -13,27 +13,14 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -/* eslint-disable import/no-unresolved, import/default */ | |
16 | +package org.thingsboard.server.actors; | |
17 | 17 | |
18 | -import edgeDownlinksHeaderTemplate from './edge-downlinks-header.tpl.html' | |
18 | +public class TbRuleNodeUpdateException extends RuntimeException { | |
19 | 19 | |
20 | -/* eslint-enable import/no-unresolved, import/default */ | |
20 | + private static final long serialVersionUID = 8209771144711980882L; | |
21 | 21 | |
22 | -/*@ngInject*/ | |
23 | -export default function EdgeDownlinksHeaderDirective($compile, $templateCache) { | |
24 | - | |
25 | - var linker = function (scope, element) { | |
26 | - | |
27 | - var template = edgeDownlinksHeaderTemplate; | |
28 | - | |
29 | - element.html($templateCache.get(template)); | |
30 | - $compile(element.contents())(scope); | |
22 | + public TbRuleNodeUpdateException(String message, Throwable cause) { | |
23 | + super(message, cause); | |
31 | 24 | } |
32 | - | |
33 | - return { | |
34 | - restrict: "A", | |
35 | - replace: false, | |
36 | - link: linker, | |
37 | - scope: false | |
38 | - }; | |
39 | 25 | } |
26 | + | ... | ... |
... | ... | @@ -21,7 +21,7 @@ import org.junit.Assert; |
21 | 21 | import org.junit.Before; |
22 | 22 | import org.junit.Test; |
23 | 23 | import org.junit.runner.RunWith; |
24 | -import org.mockito.runners.MockitoJUnitRunner; | |
24 | +import org.mockito.junit.MockitoJUnitRunner; | |
25 | 25 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | 26 | |
27 | 27 | import java.util.ArrayList; | ... | ... |
... | ... | @@ -49,6 +49,10 @@ |
49 | 49 | <artifactId>guava</artifactId> |
50 | 50 | </dependency> |
51 | 51 | <dependency> |
52 | + <groupId>javax.annotation</groupId> | |
53 | + <artifactId>javax.annotation-api</artifactId> | |
54 | + </dependency> | |
55 | + <dependency> | |
52 | 56 | <groupId>com.github.fge</groupId> |
53 | 57 | <artifactId>json-schema-validator</artifactId> |
54 | 58 | </dependency> |
... | ... | @@ -99,7 +103,7 @@ |
99 | 103 | </dependency> |
100 | 104 | <dependency> |
101 | 105 | <groupId>org.mockito</groupId> |
102 | - <artifactId>mockito-all</artifactId> | |
106 | + <artifactId>mockito-core</artifactId> | |
103 | 107 | <scope>test</scope> |
104 | 108 | </dependency> |
105 | 109 | </dependencies> | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; |
23 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
24 | 24 | import org.springframework.beans.factory.annotation.Value; |
25 | 25 | import org.springframework.core.env.Environment; |
26 | +import org.springframework.core.env.Profiles; | |
26 | 27 | import org.thingsboard.server.dao.cassandra.guava.GuavaSession; |
27 | 28 | import org.thingsboard.server.dao.cassandra.guava.GuavaSessionBuilder; |
28 | 29 | import org.thingsboard.server.dao.cassandra.guava.GuavaSessionUtils; |
... | ... | @@ -77,7 +78,7 @@ public abstract class AbstractCassandraCluster { |
77 | 78 | } |
78 | 79 | |
79 | 80 | private boolean isInstall() { |
80 | - return environment.acceptsProfiles("install"); | |
81 | + return environment.acceptsProfiles(Profiles.of("install")); | |
81 | 82 | } |
82 | 83 | |
83 | 84 | private void initSession() { | ... | ... |
... | ... | @@ -18,38 +18,25 @@ package org.thingsboard.server.dao.cassandra.guava; |
18 | 18 | import com.datastax.oss.driver.api.core.CqlSession; |
19 | 19 | import com.datastax.oss.driver.api.core.config.DriverConfigLoader; |
20 | 20 | import com.datastax.oss.driver.api.core.context.DriverContext; |
21 | -import com.datastax.oss.driver.api.core.metadata.Node; | |
22 | -import com.datastax.oss.driver.api.core.metadata.NodeStateListener; | |
23 | -import com.datastax.oss.driver.api.core.metadata.schema.SchemaChangeListener; | |
21 | +import com.datastax.oss.driver.api.core.session.ProgrammaticArguments; | |
24 | 22 | import com.datastax.oss.driver.api.core.session.SessionBuilder; |
25 | -import com.datastax.oss.driver.api.core.tracker.RequestTracker; | |
26 | -import com.datastax.oss.driver.api.core.type.codec.TypeCodec; | |
27 | 23 | import edu.umd.cs.findbugs.annotations.NonNull; |
28 | -import java.util.List; | |
29 | -import java.util.Map; | |
30 | -import java.util.function.Predicate; | |
31 | 24 | |
32 | 25 | public class GuavaSessionBuilder extends SessionBuilder<GuavaSessionBuilder, GuavaSession> { |
33 | 26 | |
34 | 27 | @Override |
35 | 28 | protected DriverContext buildContext( |
36 | 29 | DriverConfigLoader configLoader, |
37 | - List<TypeCodec<?>> typeCodecs, | |
38 | - NodeStateListener nodeStateListener, | |
39 | - SchemaChangeListener schemaChangeListener, | |
40 | - RequestTracker requestTracker, | |
41 | - Map<String, String> localDatacenters, | |
42 | - Map<String, Predicate<Node>> nodeFilters, | |
43 | - ClassLoader classLoader) { | |
30 | + ProgrammaticArguments programmaticArguments) { | |
44 | 31 | return new GuavaDriverContext( |
45 | 32 | configLoader, |
46 | - typeCodecs, | |
47 | - nodeStateListener, | |
48 | - schemaChangeListener, | |
49 | - requestTracker, | |
50 | - localDatacenters, | |
51 | - nodeFilters, | |
52 | - classLoader); | |
33 | + programmaticArguments.getTypeCodecs(), | |
34 | + programmaticArguments.getNodeStateListener(), | |
35 | + programmaticArguments.getSchemaChangeListener(), | |
36 | + programmaticArguments.getRequestTracker(), | |
37 | + programmaticArguments.getLocalDatacenters(), | |
38 | + programmaticArguments.getNodeFilters(), | |
39 | + programmaticArguments.getClassLoader()); | |
53 | 40 | } |
54 | 41 | |
55 | 42 | @Override | ... | ... |
common/dao-api/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java
renamed from
dao/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.dao.util.mapping; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.core.JsonProcessingException; |
19 | +import com.fasterxml.jackson.core.type.TypeReference; | |
19 | 20 | import com.fasterxml.jackson.databind.JsonNode; |
20 | 21 | import com.fasterxml.jackson.databind.ObjectMapper; |
21 | 22 | import com.fasterxml.jackson.databind.node.ObjectNode; |
... | ... | @@ -38,6 +39,15 @@ public class JacksonUtil { |
38 | 39 | } |
39 | 40 | } |
40 | 41 | |
42 | + public static <T> T convertValue(Object fromValue, TypeReference<T> toValueTypeRef) { | |
43 | + try { | |
44 | + return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueTypeRef) : null; | |
45 | + } catch (IllegalArgumentException e) { | |
46 | + throw new IllegalArgumentException("The given object value: " | |
47 | + + fromValue + " cannot be converted to " + toValueTypeRef, e); | |
48 | + } | |
49 | + } | |
50 | + | |
41 | 51 | public static <T> T fromString(String string, Class<T> clazz) { |
42 | 52 | try { |
43 | 53 | return string != null ? OBJECT_MAPPER.readValue(string, clazz) : null; |
... | ... | @@ -72,7 +82,9 @@ public class JacksonUtil { |
72 | 82 | } |
73 | 83 | |
74 | 84 | public static <T> T clone(T value) { |
75 | - return fromString(toString(value), (Class<T>) value.getClass()); | |
85 | + @SuppressWarnings("unchecked") | |
86 | + Class<T> valueClass = (Class<T>) value.getClass(); | |
87 | + return fromString(toString(value), valueClass); | |
76 | 88 | } |
77 | 89 | |
78 | 90 | public static <T> JsonNode valueToTree(T value) { | ... | ... |
... | ... | @@ -24,6 +24,7 @@ public class DataConstants { |
24 | 24 | public static final String CUSTOMER = "CUSTOMER"; |
25 | 25 | public static final String DEVICE = "DEVICE"; |
26 | 26 | |
27 | + public static final String SCOPE = "scope"; | |
27 | 28 | public static final String CLIENT_SCOPE = "CLIENT_SCOPE"; |
28 | 29 | public static final String SERVER_SCOPE = "SERVER_SCOPE"; |
29 | 30 | public static final String SHARED_SCOPE = "SHARED_SCOPE"; | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/HomeDashboard.java
renamed from
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java
... | ... | @@ -13,25 +13,18 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.actors.ruleChain; | |
16 | +package org.thingsboard.server.common.data; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.msg.MsgType; | |
20 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
21 | -import org.thingsboard.server.common.msg.TbMsg; | |
22 | 19 | |
23 | -/** | |
24 | - * Created by ashvayka on 19.03.18. | |
25 | - */ | |
26 | 20 | @Data |
27 | -final class RuleNodeToSelfErrorMsg implements TbActorMsg { | |
21 | +public class HomeDashboard extends Dashboard { | |
28 | 22 | |
29 | - private final TbMsg msg; | |
30 | - private final Throwable error; | |
23 | + private boolean hideDashboardToolbar; | |
31 | 24 | |
32 | - @Override | |
33 | - public MsgType getMsgType() { | |
34 | - return MsgType.RULE_TO_SELF_ERROR_MSG; | |
25 | + public HomeDashboard(Dashboard dashboard, boolean hideDashboardToolbar) { | |
26 | + super(dashboard); | |
27 | + this.hideDashboardToolbar = hideDashboardToolbar; | |
35 | 28 | } |
36 | 29 | |
37 | 30 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data; | |
17 | + | |
18 | +import lombok.AllArgsConstructor; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.id.DashboardId; | |
21 | + | |
22 | +@Data | |
23 | +@AllArgsConstructor | |
24 | +public class HomeDashboardInfo { | |
25 | + private DashboardId dashboardId; | |
26 | + private boolean hideDashboardToolbar; | |
27 | +} | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.data.lwm2m; |
17 | 17 | |
18 | -import lombok.Builder; | |
19 | 18 | import lombok.Data; |
20 | 19 | |
21 | 20 | @Data |
... | ... | @@ -23,12 +22,8 @@ public class ServerSecurityConfig { |
23 | 22 | String host; |
24 | 23 | Integer port; |
25 | 24 | String serverPublicKey; |
26 | - @Builder.Default | |
27 | 25 | boolean bootstrapServerIs = true; |
28 | - @Builder.Default | |
29 | 26 | Integer clientHoldOffTime = 1; |
30 | - @Builder.Default | |
31 | 27 | Integer serverId = 111; |
32 | - @Builder.Default | |
33 | 28 | Integer bootstrapServerAccountTimeout = 0; |
34 | 29 | } | ... | ... |
... | ... | @@ -17,19 +17,25 @@ package org.thingsboard.server.common.data.query; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.annotation.JsonIgnore; |
19 | 19 | import lombok.Data; |
20 | -import lombok.Getter; | |
20 | +import lombok.RequiredArgsConstructor; | |
21 | 21 | |
22 | 22 | import java.io.Serializable; |
23 | 23 | |
24 | 24 | @Data |
25 | +@RequiredArgsConstructor | |
25 | 26 | public class DynamicValue<T> implements Serializable { |
26 | 27 | |
27 | 28 | @JsonIgnore |
28 | 29 | private T resolvedValue; |
29 | 30 | |
30 | - @Getter | |
31 | 31 | private final DynamicValueSourceType sourceType; |
32 | - @Getter | |
33 | 32 | private final String sourceAttribute; |
33 | + private final boolean inherit; | |
34 | + | |
35 | + public DynamicValue(DynamicValueSourceType sourceType, String sourceAttribute) { | |
36 | + this.sourceAttribute = sourceAttribute; | |
37 | + this.sourceType = sourceType; | |
38 | + this.inherit = false; | |
39 | + } | |
34 | 40 | |
35 | 41 | } | ... | ... |
... | ... | @@ -19,7 +19,7 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; |
19 | 19 | import org.junit.Assert; |
20 | 20 | import org.junit.Test; |
21 | 21 | import org.junit.runner.RunWith; |
22 | -import org.mockito.runners.MockitoJUnitRunner; | |
22 | +import org.mockito.junit.MockitoJUnitRunner; | |
23 | 23 | |
24 | 24 | import java.util.ArrayList; |
25 | 25 | import java.util.Arrays; | ... | ... |
... | ... | @@ -40,6 +40,11 @@ public enum MsgType { |
40 | 40 | COMPONENT_LIFE_CYCLE_MSG, |
41 | 41 | |
42 | 42 | /** |
43 | + * Special message to indicate rule node update request | |
44 | + */ | |
45 | + RULE_NODE_UPDATED_MSG, | |
46 | + | |
47 | + /** | |
43 | 48 | * Misc messages consumed from the Queue and forwarded to Rule Engine Actor. |
44 | 49 | * |
45 | 50 | * See {@link QueueToRuleEngineMsg} |
... | ... | @@ -67,11 +72,6 @@ public enum MsgType { |
67 | 72 | REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG, |
68 | 73 | |
69 | 74 | /** |
70 | - * Message that is sent by RuleActor implementation to RuleActor itself to log the error. | |
71 | - */ | |
72 | - RULE_TO_SELF_ERROR_MSG, | |
73 | - | |
74 | - /** | |
75 | 75 | * Message that is sent by RuleActor implementation to RuleActor itself to process the message. |
76 | 76 | */ |
77 | 77 | RULE_TO_SELF_MSG, | ... | ... |
... | ... | @@ -22,4 +22,12 @@ public interface TbActorMsg { |
22 | 22 | |
23 | 23 | MsgType getMsgType(); |
24 | 24 | |
25 | + /** | |
26 | + * Executed when the target TbActor is stopped or destroyed. | |
27 | + * For example, rule node failed to initialize or removed from rule chain. | |
28 | + * Implementation should cleanup the resources. | |
29 | + */ | |
30 | + default void onTbActorStopped(TbActorStopReason reason) { | |
31 | + } | |
32 | + | |
25 | 33 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.msg; | |
17 | + | |
18 | +public enum TbActorStopReason { | |
19 | + | |
20 | + INIT_FAILED, STOPPED | |
21 | + | |
22 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.msg; | |
17 | + | |
18 | +import lombok.EqualsAndHashCode; | |
19 | +import lombok.Getter; | |
20 | + | |
21 | +@EqualsAndHashCode | |
22 | +public abstract class TbRuleEngineActorMsg implements TbActorMsg { | |
23 | + | |
24 | + @Getter | |
25 | + protected final TbMsg msg; | |
26 | + | |
27 | + public TbRuleEngineActorMsg(TbMsg msg) { | |
28 | + this.msg = msg; | |
29 | + } | |
30 | +} | ... | ... |
common/message/src/main/java/org/thingsboard/server/common/msg/plugin/RuleNodeUpdatedMsg.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.msg.plugin; | |
17 | + | |
18 | +import lombok.ToString; | |
19 | +import org.thingsboard.server.common.data.id.EntityId; | |
20 | +import org.thingsboard.server.common.data.id.TenantId; | |
21 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
22 | +import org.thingsboard.server.common.msg.MsgType; | |
23 | + | |
24 | +import java.util.Optional; | |
25 | + | |
26 | +/** | |
27 | + * @author Andrew Shvayka | |
28 | + */ | |
29 | +@ToString | |
30 | +public class RuleNodeUpdatedMsg extends ComponentLifecycleMsg { | |
31 | + | |
32 | + public RuleNodeUpdatedMsg(TenantId tenantId, EntityId entityId) { | |
33 | + super(tenantId, entityId, ComponentLifecycleEvent.UPDATED); | |
34 | + } | |
35 | + | |
36 | + @Override | |
37 | + public MsgType getMsgType() { | |
38 | + return MsgType.RULE_NODE_UPDATED_MSG; | |
39 | + } | |
40 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -15,32 +15,58 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.msg.queue; |
17 | 17 | |
18 | -import lombok.Data; | |
18 | +import lombok.EqualsAndHashCode; | |
19 | +import lombok.Getter; | |
20 | +import lombok.ToString; | |
19 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
20 | 22 | import org.thingsboard.server.common.msg.MsgType; |
21 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
23 | +import org.thingsboard.server.common.msg.TbActorStopReason; | |
22 | 24 | import org.thingsboard.server.common.msg.TbMsg; |
25 | +import org.thingsboard.server.common.msg.TbRuleEngineActorMsg; | |
23 | 26 | |
24 | -import java.io.Serializable; | |
25 | 27 | import java.util.Set; |
26 | 28 | |
27 | 29 | /** |
28 | 30 | * Created by ashvayka on 15.03.18. |
29 | 31 | */ |
30 | -@Data | |
31 | -public final class QueueToRuleEngineMsg implements TbActorMsg { | |
32 | +@ToString | |
33 | +@EqualsAndHashCode(callSuper = true) | |
34 | +public final class QueueToRuleEngineMsg extends TbRuleEngineActorMsg { | |
32 | 35 | |
36 | + @Getter | |
33 | 37 | private final TenantId tenantId; |
34 | - private final TbMsg tbMsg; | |
38 | + @Getter | |
35 | 39 | private final Set<String> relationTypes; |
40 | + @Getter | |
36 | 41 | private final String failureMessage; |
37 | 42 | |
43 | + public QueueToRuleEngineMsg(TenantId tenantId, TbMsg tbMsg, Set<String> relationTypes, String failureMessage) { | |
44 | + super(tbMsg); | |
45 | + this.tenantId = tenantId; | |
46 | + this.relationTypes = relationTypes; | |
47 | + this.failureMessage = failureMessage; | |
48 | + } | |
49 | + | |
38 | 50 | @Override |
39 | 51 | public MsgType getMsgType() { |
40 | 52 | return MsgType.QUEUE_TO_RULE_ENGINE_MSG; |
41 | 53 | } |
42 | 54 | |
55 | + @Override | |
56 | + public void onTbActorStopped(TbActorStopReason reason) { | |
57 | + String message; | |
58 | + if (msg.getRuleChainId() != null) { | |
59 | + message = reason == TbActorStopReason.STOPPED ? | |
60 | + String.format("Rule chain [%s] stopped", msg.getRuleChainId().getId()) : | |
61 | + String.format("Failed to initialize rule chain [%s]!", msg.getRuleChainId().getId()); | |
62 | + } else { | |
63 | + message = reason == TbActorStopReason.STOPPED ? "Rule chain stopped" : "Failed to initialize rule chain!"; | |
64 | + } | |
65 | + msg.getCallback().onFailure(new RuleEngineException(message)); | |
66 | + } | |
67 | + | |
43 | 68 | public boolean isTellNext() { |
44 | 69 | return relationTypes != null && !relationTypes.isEmpty(); |
45 | 70 | } |
71 | + | |
46 | 72 | } | ... | ... |
... | ... | @@ -24,6 +24,9 @@ import org.thingsboard.server.common.data.rule.RuleNode; |
24 | 24 | |
25 | 25 | @Slf4j |
26 | 26 | public class RuleNodeException extends RuleEngineException { |
27 | + | |
28 | + private static final long serialVersionUID = -1776681087370749776L; | |
29 | + | |
27 | 30 | @Getter |
28 | 31 | private final String ruleChainName; |
29 | 32 | @Getter |
... | ... | @@ -33,6 +36,7 @@ public class RuleNodeException extends RuleEngineException { |
33 | 36 | @Getter |
34 | 37 | private final RuleNodeId ruleNodeId; |
35 | 38 | |
39 | + | |
36 | 40 | public RuleNodeException(String message, String ruleChainName, RuleNode ruleNode) { |
37 | 41 | super(message); |
38 | 42 | this.ruleChainName = ruleChainName; | ... | ... |
... | ... | @@ -154,6 +154,7 @@ public class TbServiceBusConsumerTemplate<T extends TbQueueMsg> extends Abstract |
154 | 154 | } |
155 | 155 | |
156 | 156 | private <V> CompletableFuture<List<V>> fromList(List<CompletableFuture<V>> futures) { |
157 | + @SuppressWarnings("unchecked") | |
157 | 158 | CompletableFuture<Collection<V>>[] arrayFuture = new CompletableFuture[futures.size()]; |
158 | 159 | futures.toArray(arrayFuture); |
159 | 160 | ... | ... |
... | ... | @@ -22,7 +22,9 @@ import org.thingsboard.server.common.msg.queue.ServiceQueueKey; |
22 | 22 | import java.util.Set; |
23 | 23 | |
24 | 24 | |
25 | -public class ClusterTopologyChangeEvent extends ApplicationEvent { | |
25 | +public class ClusterTopologyChangeEvent extends TbApplicationEvent { | |
26 | + | |
27 | + private static final long serialVersionUID = -2441739930040282254L; | |
26 | 28 | |
27 | 29 | @Getter |
28 | 30 | private final Set<ServiceQueueKey> serviceQueueKeys; | ... | ... |
... | ... | @@ -126,7 +126,7 @@ public class HashPartitionService implements PartitionService { |
126 | 126 | } |
127 | 127 | |
128 | 128 | @Override |
129 | - public void recalculatePartitions(ServiceInfo currentService, List<ServiceInfo> otherServices) { | |
129 | + public synchronized void recalculatePartitions(ServiceInfo currentService, List<ServiceInfo> otherServices) { | |
130 | 130 | logServiceInfo(currentService); |
131 | 131 | otherServices.forEach(this::logServiceInfo); |
132 | 132 | Map<ServiceQueueKey, List<ServiceInfo>> queueServicesMap = new HashMap<>(); |
... | ... | @@ -134,7 +134,7 @@ public class HashPartitionService implements PartitionService { |
134 | 134 | for (ServiceInfo other : otherServices) { |
135 | 135 | addNode(queueServicesMap, other); |
136 | 136 | } |
137 | - queueServicesMap.values().forEach(list -> list.sort((a, b) -> a.getServiceId().compareTo(b.getServiceId()))); | |
137 | + queueServicesMap.values().forEach(list -> list.sort(Comparator.comparing(ServiceInfo::getServiceId))); | |
138 | 138 | |
139 | 139 | ConcurrentMap<ServiceQueueKey, List<Integer>> oldPartitions = myPartitions; |
140 | 140 | TenantId myIsolatedOrSystemTenantId = getSystemOrIsolatedTenantId(currentService); | ... | ... |