Commit ae91c85e1b802f242f3d5a13e944809131caaef5
Merge branch 'master' of github.com:thingsboard/thingsboard
Showing
54 changed files
with
1608 additions
and
1386 deletions
Too many changes to show.
To preserve performance only 54 of 659 files are displayed.
... | ... | @@ -2,6 +2,7 @@ before_install: |
2 | 2 | - sudo rm -f /etc/mavenrc |
3 | 3 | - export M2_HOME=/usr/local/maven |
4 | 4 | - export MAVEN_OPTS="-Dmaven.repo.local=$HOME/.m2/repository -Xms1024m -Xmx3072m" |
5 | + - export HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE=false | |
5 | 6 | jdk: |
6 | 7 | - oraclejdk8 |
7 | 8 | language: java | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.1.1-SNAPSHOT</version> | |
23 | + <version>2.2.0-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>application</artifactId> |
... | ... | @@ -57,26 +57,30 @@ |
57 | 57 | <artifactId>rule-engine-components</artifactId> |
58 | 58 | </dependency> |
59 | 59 | <dependency> |
60 | - <groupId>org.thingsboard.common</groupId> | |
61 | - <artifactId>transport</artifactId> | |
60 | + <groupId>org.thingsboard.common.transport</groupId> | |
61 | + <artifactId>transport-api</artifactId> | |
62 | 62 | </dependency> |
63 | 63 | <dependency> |
64 | - <groupId>org.thingsboard.transport</groupId> | |
65 | - <artifactId>http</artifactId> | |
64 | + <groupId>org.thingsboard.common.transport</groupId> | |
65 | + <artifactId>mqtt</artifactId> | |
66 | 66 | </dependency> |
67 | 67 | <dependency> |
68 | - <groupId>org.thingsboard.transport</groupId> | |
69 | - <artifactId>coap</artifactId> | |
68 | + <groupId>org.thingsboard.common.transport</groupId> | |
69 | + <artifactId>http</artifactId> | |
70 | 70 | </dependency> |
71 | 71 | <dependency> |
72 | - <groupId>org.thingsboard.transport</groupId> | |
73 | - <artifactId>mqtt</artifactId> | |
72 | + <groupId>org.thingsboard.common.transport</groupId> | |
73 | + <artifactId>coap</artifactId> | |
74 | 74 | </dependency> |
75 | 75 | <dependency> |
76 | 76 | <groupId>org.thingsboard</groupId> |
77 | 77 | <artifactId>dao</artifactId> |
78 | 78 | </dependency> |
79 | 79 | <dependency> |
80 | + <groupId>org.thingsboard.common</groupId> | |
81 | + <artifactId>queue</artifactId> | |
82 | + </dependency> | |
83 | + <dependency> | |
80 | 84 | <groupId>org.thingsboard</groupId> |
81 | 85 | <artifactId>dao</artifactId> |
82 | 86 | <type>test-jar</type> |
... | ... | @@ -538,7 +542,8 @@ |
538 | 542 | <args> |
539 | 543 | <arg>-PprojectBuildDir=${project.build.directory}</arg> |
540 | 544 | <arg>-PprojectVersion=${project.version}</arg> |
541 | - <arg>-PmainJar=${project.build.directory}/${project.build.finalName}-boot.${project.packaging}</arg> | |
545 | + <arg>-PmainJar=${project.build.directory}/${project.build.finalName}-boot.${project.packaging} | |
546 | + </arg> | |
542 | 547 | <arg>-PpkgName=${pkg.name}</arg> |
543 | 548 | <arg>-PpkgInstallFolder=${pkg.installFolder}</arg> |
544 | 549 | <arg>-PpkgLogFolder=${pkg.unixLogFolder}</arg> |
... | ... | @@ -573,6 +578,27 @@ |
573 | 578 | </executions> |
574 | 579 | </plugin> |
575 | 580 | <plugin> |
581 | + <groupId>org.apache.maven.plugins</groupId> | |
582 | + <artifactId>maven-install-plugin</artifactId> | |
583 | + <configuration> | |
584 | + <file>${project.build.directory}/${pkg.name}.deb</file> | |
585 | + <artifactId>${project.artifactId}</artifactId> | |
586 | + <groupId>${project.groupId}</groupId> | |
587 | + <version>${project.version}</version> | |
588 | + <classifier>deb</classifier> | |
589 | + <packaging>deb</packaging> | |
590 | + </configuration> | |
591 | + <executions> | |
592 | + <execution> | |
593 | + <id>install-deb</id> | |
594 | + <phase>package</phase> | |
595 | + <goals> | |
596 | + <goal>install-file</goal> | |
597 | + </goals> | |
598 | + </execution> | |
599 | + </executions> | |
600 | + </plugin> | |
601 | + <plugin> | |
576 | 602 | <groupId>org.xolstice.maven.plugins</groupId> |
577 | 603 | <artifactId>protobuf-maven-plugin</artifactId> |
578 | 604 | </plugin> | ... | ... |
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | "resources": [], |
16 | 16 | "templateHtml": "", |
17 | 17 | "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n margin: 5px;\n padding: 8px;\n}\n\n.tbDatasource-title {\n font-size: 1.200rem;\n font-weight: 500;\n padding-bottom: 10px;\n}\n\n.tbDatasource-table {\n width: 100%;\n box-shadow: 0 0 10px #ccc;\n border-collapse: collapse;\n white-space: nowrap;\n font-size: 1.000rem;\n color: #757575;\n}\n\n.tbDatasource-table td {\n position: relative;\n border-top: 1px solid rgba(0, 0, 0, 0.12);\n border-bottom: 1px solid rgba(0, 0, 0, 0.12);\n padding: 0px 18px;\n box-sizing: border-box;\n}", |
18 | - "controllerScript": "self.onInit = function() {\n \n self.ctx.datasourceTitleCells = [];\n self.ctx.valueCells = [];\n self.ctx.labelCells = [];\n \n for (var i=0; i < self.ctx.datasources.length; i++) {\n var tbDatasource = self.ctx.datasources[i];\n\n var datasourceId = 'tbDatasource' + i;\n self.ctx.$container.append(\n \"<div id='\" + datasourceId +\n \"' class='tbDatasource-container'></div>\"\n );\n\n var datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n\n datasourceContainer.append(\n \"<div class='tbDatasource-title'>\" +\n tbDatasource.name + \"</div>\"\n );\n \n var datasourceTitleCell = $('.tbDatasource-title', datasourceContainer);\n self.ctx.datasourceTitleCells.push(datasourceTitleCell);\n \n var tableId = 'table' + i;\n datasourceContainer.append(\n \"<table id='\" + tableId +\n \"' class='tbDatasource-table'><col width='30%'><col width='70%'></table>\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n\n for (var a = 0; a < tbDatasource.dataKeys.length; a++) {\n var dataKey = tbDatasource.dataKeys[a];\n var labelCellId = 'labelCell' + a;\n var cellId = 'cell' + a;\n table.append(\"<tr><td id='\" + labelCellId + \"'>\" + dataKey.label +\n \"</td><td id='\" + cellId +\n \"'></td></tr>\");\n var labelCell = $('#' + labelCellId, table);\n self.ctx.labelCells.push(labelCell);\n var valueCell = $('#' + cellId, table);\n self.ctx.valueCells.push(valueCell);\n }\n } \n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.valueCells.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData && cellData.data && cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n self.ctx.valueCells[i].html(value);\n }\n } \n}\n\nself.onResize = function() {\n var datasoirceTitleFontSize = self.ctx.height/8;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n datasoirceTitleFontSize = self.ctx.width/12;\n }\n datasoirceTitleFontSize = Math.min(datasoirceTitleFontSize, 20);\n for (var i = 0; i < self.ctx.datasourceTitleCells.length; i++) {\n self.ctx.datasourceTitleCells[i].css('font-size', datasoirceTitleFontSize+'px');\n }\n var valueFontSize = self.ctx.height/9;\n var labelFontSize = self.ctx.height/9;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n valueFontSize = self.ctx.width/15;\n labelFontSize = self.ctx.width/15;\n }\n valueFontSize = Math.min(valueFontSize, 18);\n labelFontSize = Math.min(labelFontSize, 18);\n\n for (i = 0; i < self.ctx.valueCells; i++) {\n self.ctx.valueCells[i].css('font-size', valueFontSize+'px');\n self.ctx.valueCells[i].css('height', valueFontSize*2.5+'px');\n self.ctx.valueCells[i].css('padding', '0px ' + valueFontSize + 'px');\n self.ctx.labelCells[i].css('font-size', labelFontSize+'px');\n self.ctx.labelCells[i].css('height', labelFontSize*2.5+'px');\n self.ctx.labelCells[i].css('padding', '0px ' + labelFontSize + 'px');\n } \n}\n\nself.onDestroy = function() {\n}\n", | |
18 | + "controllerScript": "self.onInit = function() {\n \n self.ctx.datasourceTitleCells = [];\n self.ctx.valueCells = [];\n self.ctx.labelCells = [];\n \n for (var i=0; i < self.ctx.datasources.length; i++) {\n var tbDatasource = self.ctx.datasources[i];\n\n var datasourceId = 'tbDatasource' + i;\n self.ctx.$container.append(\n \"<div id='\" + datasourceId +\n \"' class='tbDatasource-container'></div>\"\n );\n\n var datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n\n datasourceContainer.append(\n \"<div class='tbDatasource-title'>\" +\n tbDatasource.name + \"</div>\"\n );\n \n var datasourceTitleCell = $('.tbDatasource-title', datasourceContainer);\n self.ctx.datasourceTitleCells.push(datasourceTitleCell);\n \n var tableId = 'table' + i;\n datasourceContainer.append(\n \"<table id='\" + tableId +\n \"' class='tbDatasource-table'><col width='30%'><col width='70%'></table>\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n\n for (var a = 0; a < tbDatasource.dataKeys.length; a++) {\n var dataKey = tbDatasource.dataKeys[a];\n var labelCellId = 'labelCell' + a;\n var cellId = 'cell' + a;\n table.append(\"<tr><td id='\" + labelCellId + \"'>\" + dataKey.label +\n \"</td><td id='\" + cellId +\n \"'></td></tr>\");\n var labelCell = $('#' + labelCellId, table);\n self.ctx.labelCells.push(labelCell);\n var valueCell = $('#' + cellId, table);\n self.ctx.valueCells.push(valueCell);\n }\n } \n \n self.onResize();\n}\n\nself.onDataUpdated = function() {\n for (var i = 0; i < self.ctx.valueCells.length; i++) {\n var cellData = self.ctx.data[i];\n if (cellData && cellData.data && cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var textValue;\n //toDo -> + IsNumber\n \n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (cellData.dataKey.decimals || cellData.dataKey.decimals === 0) {\n decimals = cellData.dataKey.decimals;\n }\n if (cellData.dataKey.units) {\n units = cellData.dataKey.units;\n }\n txtValue = self.ctx.utils.formatValue(value, decimals, units, true);\n } else {\n txtValue = value;\n }\n self.ctx.valueCells[i].html(txtValue);\n }\n }\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n}\n\nself.onResize = function() {\n var datasoirceTitleFontSize = self.ctx.height/8;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n datasoirceTitleFontSize = self.ctx.width/12;\n }\n datasoirceTitleFontSize = Math.min(datasoirceTitleFontSize, 20);\n for (var i = 0; i < self.ctx.datasourceTitleCells.length; i++) {\n self.ctx.datasourceTitleCells[i].css('font-size', datasoirceTitleFontSize+'px');\n }\n var valueFontSize = self.ctx.height/9;\n var labelFontSize = self.ctx.height/9;\n if (self.ctx.width/self.ctx.height <= 1.5) {\n valueFontSize = self.ctx.width/15;\n labelFontSize = self.ctx.width/15;\n }\n valueFontSize = Math.min(valueFontSize, 18);\n labelFontSize = Math.min(labelFontSize, 18);\n\n for (i = 0; i < self.ctx.valueCells; i++) {\n self.ctx.valueCells[i].css('font-size', valueFontSize+'px');\n self.ctx.valueCells[i].css('height', valueFontSize*2.5+'px');\n self.ctx.valueCells[i].css('padding', '0px ' + valueFontSize + 'px');\n self.ctx.labelCells[i].css('font-size', labelFontSize+'px');\n self.ctx.labelCells[i].css('height', labelFontSize*2.5+'px');\n self.ctx.labelCells[i].css('padding', '0px ' + labelFontSize + 'px');\n } \n}\n\nself.onDestroy = function() {\n}\n", | |
19 | 19 | "settingsSchema": "{}", |
20 | 20 | "dataKeySettingsSchema": "{}\n", |
21 | 21 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Attributes card\"}" |
... | ... | @@ -27,7 +27,7 @@ |
27 | 27 | "descriptor": { |
28 | 28 | "type": "latest", |
29 | 29 | "sizeX": 7.5, |
30 | - "sizeY": 4.5, | |
30 | + "sizeY": 6.5, | |
31 | 31 | "resources": [], |
32 | 32 | "templateHtml": "<tb-entities-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-entities-table-widget>", |
33 | 33 | "templateCss": "", |
... | ... | @@ -95,7 +95,7 @@ |
95 | 95 | "resources": [], |
96 | 96 | "templateHtml": "", |
97 | 97 | "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.tbDatasource-table {\n width: 100%;\n height: 100%;\n border-collapse: collapse;\n white-space: nowrap;\n font-weight: 100;\n text-align: right;\n}\n\n.tbDatasource-table td {\n padding: 12px;\n position: relative;\n box-sizing: border-box;\n}\n\n.tbDatasource-data-key {\n opacity: 0.7;\n font-weight: 400;\n font-size: 3.500rem;\n}\n\n.tbDatasource-value {\n font-size: 5.000rem;\n}", |
98 | - "controllerScript": "self.onInit = function() {\n\n self.ctx.labelPosition = self.ctx.settings.labelPosition || 'left';\n \n if (self.ctx.datasources.length > 0) {\n var tbDatasource = self.ctx.datasources[0];\n var datasourceId = 'tbDatasource' + 0;\n self.ctx.$container.append(\n \"<div id='\" + datasourceId +\n \"' class='tbDatasource-container'></div>\"\n );\n \n self.ctx.datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n \n var tableId = 'table' + 0;\n self.ctx.datasourceContainer.append(\n \"<table id='\" + tableId +\n \"' class='tbDatasource-table'><col width='30%'><col width='70%'></table>\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n if (self.ctx.labelPosition === 'top') {\n table.css('text-align', 'left');\n }\n \n if (tbDatasource.dataKeys.length > 0) {\n var dataKey = tbDatasource.dataKeys[0];\n var labelCellId = 'labelCell' + 0;\n var cellId = 'cell' + 0;\n if (self.ctx.labelPosition === 'left') {\n table.append(\n \"<tr><td class='tbDatasource-data-key' id='\" + labelCellId +\"'>\" +\n dataKey.label +\n \"</td><td class='tbDatasource-value' id='\" +\n cellId +\n \"'></td></tr>\");\n } else {\n table.append(\n \"<tr style='vertical-align: bottom;'><td class='tbDatasource-data-key' id='\" + labelCellId +\"'>\" +\n dataKey.label +\n \"</td></tr><tr><td class='tbDatasource-value' id='\" +\n cellId +\n \"'></td></tr>\");\n }\n self.ctx.labelCell = $('#' + labelCellId, table);\n self.ctx.valueCell = $('#' + cellId, table);\n self.ctx.valueCell.html(0 + ' ' + self.ctx.units);\n }\n }\n \n $.fn.textWidth = function(){\n var html_org = $(this).html();\n var html_calc = '<span>' + html_org + '</span>';\n $(this).html(html_calc);\n var width = $(this).find('span:first').width();\n $(this).html(html_org);\n return width;\n }; \n \n self.onResize();\n};\n\nself.onDataUpdated = function() {\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n if (self.ctx.valueCell && self.ctx.data.length > 0) {\n var cellData = self.ctx.data[0];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var txtValue;\n if (isNumber(value)) {\n txtValue = self.ctx.utils.formatValue(value, self.ctx.decimals, self.ctx.units);\n } else {\n txtValue = value;\n }\n self.ctx.valueCell.html(txtValue);\n var targetWidth;\n var minDelta;\n if (self.ctx.labelPosition === 'left') {\n targetWidth = self.ctx.datasourceContainer.width() - self.ctx.labelCell.width();\n minDelta = self.ctx.width/16 + self.ctx.padding;\n } else {\n targetWidth = self.ctx.datasourceContainer.width();\n minDelta = self.ctx.padding;\n }\n var delta = targetWidth - self.ctx.valueCell.textWidth();\n var fontSize = self.ctx.valueFontSize;\n if (targetWidth > minDelta) {\n while (delta < minDelta && fontSize > 6) {\n fontSize--;\n self.ctx.valueCell.css('font-size', fontSize+'px');\n delta = targetWidth - self.ctx.valueCell.textWidth();\n }\n }\n }\n } \n \n};\n\nself.onResize = function() {\n var labelFontSize;\n if (self.ctx.labelPosition === 'top') {\n self.ctx.padding = self.ctx.height/20;\n labelFontSize = self.ctx.height/4;\n self.ctx.valueFontSize = self.ctx.height/2;\n } else {\n self.ctx.padding = self.ctx.width/50;\n labelFontSize = self.ctx.height/2.5;\n self.ctx.valueFontSize = self.ctx.height/2;\n if (self.ctx.width/self.ctx.height <= 2.7) {\n labelFontSize = self.ctx.width/7;\n self.ctx.valueFontSize = self.ctx.width/6;\n }\n }\n self.ctx.padding = Math.min(12, self.ctx.padding);\n \n if (self.ctx.labelCell) {\n self.ctx.labelCell.css('font-size', labelFontSize+'px');\n self.ctx.labelCell.css('padding', self.ctx.padding+'px');\n }\n if (self.ctx.valueCell) {\n self.ctx.valueCell.css('font-size', self.ctx.valueFontSize+'px');\n self.ctx.valueCell.css('padding', self.ctx.padding+'px');\n } \n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n };\n};\n\n\nself.onDestroy = function() {\n};\n", | |
98 | + "controllerScript": "self.onInit = function() {\n\n self.ctx.labelPosition = self.ctx.settings.labelPosition || 'left';\n \n if (self.ctx.datasources.length > 0) {\n var tbDatasource = self.ctx.datasources[0];\n var datasourceId = 'tbDatasource' + 0;\n self.ctx.$container.append(\n \"<div id='\" + datasourceId +\n \"' class='tbDatasource-container'></div>\"\n );\n \n self.ctx.datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n \n var tableId = 'table' + 0;\n self.ctx.datasourceContainer.append(\n \"<table id='\" + tableId +\n \"' class='tbDatasource-table'><col width='30%'><col width='70%'></table>\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n if (self.ctx.labelPosition === 'top') {\n table.css('text-align', 'left');\n }\n \n if (tbDatasource.dataKeys.length > 0) {\n var dataKey = tbDatasource.dataKeys[0];\n var labelCellId = 'labelCell' + 0;\n var cellId = 'cell' + 0;\n if (self.ctx.labelPosition === 'left') {\n table.append(\n \"<tr><td class='tbDatasource-data-key' id='\" + labelCellId +\"'>\" +\n dataKey.label +\n \"</td><td class='tbDatasource-value' id='\" +\n cellId +\n \"'></td></tr>\");\n } else {\n table.append(\n \"<tr style='vertical-align: bottom;'><td class='tbDatasource-data-key' id='\" + labelCellId +\"'>\" +\n dataKey.label +\n \"</td></tr><tr><td class='tbDatasource-value' id='\" +\n cellId +\n \"'></td></tr>\");\n }\n self.ctx.labelCell = $('#' + labelCellId, table);\n self.ctx.valueCell = $('#' + cellId, table);\n self.ctx.valueCell.html(0 + ' ' + self.ctx.units);\n }\n }\n \n $.fn.textWidth = function(){\n var html_org = $(this).html();\n var html_calc = '<span>' + html_org + '</span>';\n $(this).html(html_calc);\n var width = $(this).find('span:first').width();\n $(this).html(html_org);\n return width;\n }; \n \n self.onResize();\n};\n\nself.onDataUpdated = function() {\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n if (self.ctx.valueCell && self.ctx.data.length > 0) {\n var cellData = self.ctx.data[0];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var txtValue;\n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (self.ctx.datasources.length > 0 && self.ctx.datasources[0].dataKeys.length > 0) {\n dataKey = self.ctx.datasources[0].dataKeys[0];\n if (dataKey.decimals || dataKey.decimals === 0) {\n decimals = dataKey.decimals;\n }\n if (dataKey.units) {\n units = dataKey.units;\n }\n }\n txtValue = self.ctx.utils.formatValue(value, decimals, units, true);\n } else {\n txtValue = value;\n }\n self.ctx.valueCell.html(txtValue);\n var targetWidth;\n var minDelta;\n if (self.ctx.labelPosition === 'left') {\n targetWidth = self.ctx.datasourceContainer.width() - self.ctx.labelCell.width();\n minDelta = self.ctx.width/16 + self.ctx.padding;\n } else {\n targetWidth = self.ctx.datasourceContainer.width();\n minDelta = self.ctx.padding;\n }\n var delta = targetWidth - self.ctx.valueCell.textWidth();\n var fontSize = self.ctx.valueFontSize;\n if (targetWidth > minDelta) {\n while (delta < minDelta && fontSize > 6) {\n fontSize--;\n self.ctx.valueCell.css('font-size', fontSize+'px');\n delta = targetWidth - self.ctx.valueCell.textWidth();\n }\n }\n }\n } \n \n};\n\nself.onResize = function() {\n var labelFontSize;\n if (self.ctx.labelPosition === 'top') {\n self.ctx.padding = self.ctx.height/20;\n labelFontSize = self.ctx.height/4;\n self.ctx.valueFontSize = self.ctx.height/2;\n } else {\n self.ctx.padding = self.ctx.width/50;\n labelFontSize = self.ctx.height/2.5;\n self.ctx.valueFontSize = self.ctx.height/2;\n if (self.ctx.width/self.ctx.height <= 2.7) {\n labelFontSize = self.ctx.width/7;\n self.ctx.valueFontSize = self.ctx.width/6;\n }\n }\n self.ctx.padding = Math.min(12, self.ctx.padding);\n \n if (self.ctx.labelCell) {\n self.ctx.labelCell.css('font-size', labelFontSize+'px');\n self.ctx.labelCell.css('padding', self.ctx.padding+'px');\n }\n if (self.ctx.valueCell) {\n self.ctx.valueCell.css('font-size', self.ctx.valueFontSize+'px');\n self.ctx.valueCell.css('padding', self.ctx.padding+'px');\n } \n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1\n };\n};\n\n\nself.onDestroy = function() {\n};\n", | |
99 | 99 | "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"labelPosition\": {\n \"title\": \"Label position\",\n \"type\": \"string\",\n \"default\": \"left\"\n }\n },\n \"required\": []\n },\n \"form\": [\n {\n \"key\": \"labelPosition\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"left\",\n \"label\": \"Left\"\n },\n {\n \"value\": \"top\",\n \"label\": \"Top\"\n }\n ]\n }\n ]\n}", |
100 | 100 | "dataKeySettingsSchema": "{}\n", |
101 | 101 | "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temp\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#ff5722\",\"color\":\"rgba(255, 255, 255, 0.87)\",\"padding\":\"16px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Simple card\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{}}" | ... | ... |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | "resources": [], |
36 | 36 | "templateHtml": "", |
37 | 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;\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\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);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
39 | 39 | "settingsSchema": "{}", |
40 | 40 | "dataKeySettingsSchema": "{}", |
41 | 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}" |
... | ... | @@ -147,10 +147,10 @@ |
147 | 147 | "resources": [], |
148 | 148 | "templateHtml": "", |
149 | 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", |
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;\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(false);\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, '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);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
151 | 151 | "settingsSchema": "{}", |
152 | 152 | "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},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":true,\"tooltipIndividual\":false},\"title\":\"Timeseries Bars - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" | |
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\":{}}" | |
154 | 154 | } |
155 | 155 | }, |
156 | 156 | { |
... | ... | @@ -163,7 +163,7 @@ |
163 | 163 | "resources": [], |
164 | 164 | "templateHtml": "", |
165 | 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, '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;\n}\n\nself.getDataKeySettingsSchema = function() {\n return TbFlot.datakeySettingsSchema(true);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\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);\n}\n\nself.onDestroy = function() {\n self.ctx.flot.destroy();\n}\n", | |
167 | 167 | "settingsSchema": "{}", |
168 | 168 | "dataKeySettingsSchema": "{}", |
169 | 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\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" | ... | ... |
1 | +-- | |
2 | +-- Copyright © 2016-2018 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 | + | |
17 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_name; | |
18 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_search_text; | |
19 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer; | |
20 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_entity_id; | |
21 | + | |
22 | +DROP TABLE IF EXISTS thingsboard.entity_views; | |
23 | + | |
24 | +CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( | |
25 | + id timeuuid, | |
26 | + entity_id timeuuid, | |
27 | + entity_type text, | |
28 | + tenant_id timeuuid, | |
29 | + customer_id timeuuid, | |
30 | + name text, | |
31 | + keys text, | |
32 | + start_ts bigint, | |
33 | + end_ts bigint, | |
34 | + search_text text, | |
35 | + additional_info text, | |
36 | + PRIMARY KEY (id, entity_id, tenant_id, customer_id) | |
37 | +); | |
38 | + | |
39 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_name AS | |
40 | + SELECT * | |
41 | + from thingsboard.entity_views | |
42 | + WHERE tenant_id IS NOT NULL | |
43 | + AND entity_id IS NOT NULL | |
44 | + AND customer_id IS NOT NULL | |
45 | + AND name IS NOT NULL | |
46 | + AND id IS NOT NULL | |
47 | + PRIMARY KEY (tenant_id, name, id, customer_id, entity_id) | |
48 | + WITH CLUSTERING ORDER BY (name ASC, id DESC, customer_id DESC); | |
49 | + | |
50 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS | |
51 | + SELECT * | |
52 | + from thingsboard.entity_views | |
53 | + WHERE tenant_id IS NOT NULL | |
54 | + AND entity_id IS NOT NULL | |
55 | + AND customer_id IS NOT NULL | |
56 | + AND search_text IS NOT NULL | |
57 | + AND id IS NOT NULL | |
58 | + PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id) | |
59 | + WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC); | |
60 | + | |
61 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer AS | |
62 | + SELECT * | |
63 | + from thingsboard.entity_views | |
64 | + WHERE tenant_id IS NOT NULL | |
65 | + AND customer_id IS NOT NULL | |
66 | + AND entity_id IS NOT NULL | |
67 | + AND search_text IS NOT NULL | |
68 | + AND id IS NOT NULL | |
69 | + PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id) | |
70 | + WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); | |
71 | + | |
72 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS | |
73 | + SELECT * | |
74 | + from thingsboard.entity_views | |
75 | + WHERE tenant_id IS NOT NULL | |
76 | + AND customer_id IS NOT NULL | |
77 | + AND entity_id IS NOT NULL | |
78 | + AND search_text IS NOT NULL | |
79 | + AND id IS NOT NULL | |
80 | + PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id) | |
81 | + WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC); | |
\ No newline at end of file | ... | ... |
1 | +-- | |
2 | +-- Copyright © 2016-2018 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 | + | |
17 | +DROP TABLE IF EXISTS entity_views; | |
18 | + | |
19 | +CREATE TABLE IF NOT EXISTS entity_views ( | |
20 | + id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, | |
21 | + entity_id varchar(31), | |
22 | + entity_type varchar(255), | |
23 | + tenant_id varchar(31), | |
24 | + customer_id varchar(31), | |
25 | + name varchar(255), | |
26 | + keys varchar(255), | |
27 | + start_ts bigint, | |
28 | + end_ts bigint, | |
29 | + search_text varchar(255), | |
30 | + additional_info varchar | |
31 | +); | ... | ... |
1 | +-- | |
2 | +-- Copyright © 2016-2018 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 | + | |
17 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_name; | |
18 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_search_text; | |
19 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer; | |
20 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_entity_id; | |
21 | + | |
22 | +DROP TABLE IF EXISTS thingsboard.entity_views; | |
23 | + | |
24 | +CREATE TABLE IF NOT EXISTS thingsboard.entity_view ( | |
25 | + id timeuuid, | |
26 | + entity_id timeuuid, | |
27 | + entity_type text, | |
28 | + tenant_id timeuuid, | |
29 | + customer_id timeuuid, | |
30 | + name text, | |
31 | + type text, | |
32 | + keys text, | |
33 | + start_ts bigint, | |
34 | + end_ts bigint, | |
35 | + search_text text, | |
36 | + additional_info text, | |
37 | + PRIMARY KEY (id, entity_id, tenant_id, customer_id, type) | |
38 | +); | |
39 | + | |
40 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_name AS | |
41 | + SELECT * | |
42 | + from thingsboard.entity_view | |
43 | + WHERE tenant_id IS NOT NULL | |
44 | + AND entity_id IS NOT NULL | |
45 | + AND customer_id IS NOT NULL | |
46 | + AND type IS NOT NULL | |
47 | + AND name IS NOT NULL | |
48 | + AND id IS NOT NULL | |
49 | + PRIMARY KEY (tenant_id, name, id, customer_id, entity_id, type) | |
50 | + WITH CLUSTERING ORDER BY (name ASC, id DESC, customer_id DESC); | |
51 | + | |
52 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_search_text AS | |
53 | + SELECT * | |
54 | + from thingsboard.entity_view | |
55 | + WHERE tenant_id IS NOT NULL | |
56 | + AND entity_id IS NOT NULL | |
57 | + AND customer_id IS NOT NULL | |
58 | + AND type IS NOT NULL | |
59 | + AND search_text IS NOT NULL | |
60 | + AND id IS NOT NULL | |
61 | + PRIMARY KEY (tenant_id, search_text, id, customer_id, entity_id, type) | |
62 | + WITH CLUSTERING ORDER BY (search_text ASC, id DESC, customer_id DESC); | |
63 | + | |
64 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_by_type_and_search_text AS | |
65 | + SELECT * | |
66 | + from thingsboard.entity_view | |
67 | + WHERE tenant_id IS NOT NULL | |
68 | + AND entity_id IS NOT NULL | |
69 | + AND customer_id IS NOT NULL | |
70 | + AND type IS NOT NULL | |
71 | + AND search_text IS NOT NULL | |
72 | + AND id IS NOT NULL | |
73 | + PRIMARY KEY (tenant_id, type, search_text, id, customer_id, entity_id) | |
74 | + WITH CLUSTERING ORDER BY (type ASC, search_text ASC, id DESC, customer_id DESC); | |
75 | + | |
76 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer AS | |
77 | + SELECT * | |
78 | + from thingsboard.entity_view | |
79 | + WHERE tenant_id IS NOT NULL | |
80 | + AND customer_id IS NOT NULL | |
81 | + AND entity_id IS NOT NULL | |
82 | + AND type IS NOT NULL | |
83 | + AND search_text IS NOT NULL | |
84 | + AND id IS NOT NULL | |
85 | + PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id, type) | |
86 | + WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC); | |
87 | + | |
88 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_customer_and_type AS | |
89 | + SELECT * | |
90 | + from thingsboard.entity_view | |
91 | + WHERE tenant_id IS NOT NULL | |
92 | + AND customer_id IS NOT NULL | |
93 | + AND entity_id IS NOT NULL | |
94 | + AND type IS NOT NULL | |
95 | + AND search_text IS NOT NULL | |
96 | + AND id IS NOT NULL | |
97 | + PRIMARY KEY (tenant_id, type, customer_id, search_text, id, entity_id) | |
98 | + WITH CLUSTERING ORDER BY (type ASC, customer_id DESC, search_text ASC, id DESC); | |
99 | + | |
100 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS | |
101 | + SELECT * | |
102 | + from thingsboard.entity_view | |
103 | + WHERE tenant_id IS NOT NULL | |
104 | + AND customer_id IS NOT NULL | |
105 | + AND entity_id IS NOT NULL | |
106 | + AND type IS NOT NULL | |
107 | + AND search_text IS NOT NULL | |
108 | + AND id IS NOT NULL | |
109 | + PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id, type) | |
110 | + WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC); | |
\ No newline at end of file | ... | ... |
1 | +-- | |
2 | +-- Copyright © 2016-2018 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 | + | |
17 | +DROP TABLE IF EXISTS entity_views; | |
18 | + | |
19 | +CREATE TABLE IF NOT EXISTS entity_view ( | |
20 | + id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, | |
21 | + entity_id varchar(31), | |
22 | + entity_type varchar(255), | |
23 | + tenant_id varchar(31), | |
24 | + customer_id varchar(31), | |
25 | + type varchar(255), | |
26 | + name varchar(255), | |
27 | + keys varchar(255), | |
28 | + start_ts bigint, | |
29 | + end_ts bigint, | |
30 | + search_text varchar(255), | |
31 | + additional_info varchar | |
32 | +); | ... | ... |
1 | +-- | |
2 | +-- Copyright © 2016-2018 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 | + | |
17 | +ALTER TABLE component_descriptor ADD UNIQUE (clazz); | ... | ... |
... | ... | @@ -31,6 +31,7 @@ import lombok.Setter; |
31 | 31 | import lombok.extern.slf4j.Slf4j; |
32 | 32 | import org.springframework.beans.factory.annotation.Autowired; |
33 | 33 | import org.springframework.beans.factory.annotation.Value; |
34 | +import org.springframework.context.annotation.Lazy; | |
34 | 35 | import org.springframework.stereotype.Component; |
35 | 36 | import org.thingsboard.rule.engine.api.MailService; |
36 | 37 | import org.thingsboard.server.actors.service.ActorService; |
... | ... | @@ -48,6 +49,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; |
48 | 49 | import org.thingsboard.server.dao.audit.AuditLogService; |
49 | 50 | import org.thingsboard.server.dao.customer.CustomerService; |
50 | 51 | import org.thingsboard.server.dao.device.DeviceService; |
52 | +import org.thingsboard.server.dao.entityview.EntityViewService; | |
51 | 53 | import org.thingsboard.server.dao.event.EventService; |
52 | 54 | import org.thingsboard.server.dao.relation.RelationService; |
53 | 55 | import org.thingsboard.server.dao.rule.RuleChainService; |
... | ... | @@ -62,12 +64,13 @@ import org.thingsboard.server.service.encoding.DataDecodingEncodingService; |
62 | 64 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
63 | 65 | import org.thingsboard.server.service.executors.ExternalCallExecutorService; |
64 | 66 | import org.thingsboard.server.service.mail.MailExecutorService; |
65 | -import org.thingsboard.server.service.queue.MsgQueueService; | |
66 | 67 | import org.thingsboard.server.service.rpc.DeviceRpcService; |
67 | 68 | import org.thingsboard.server.service.script.JsExecutorService; |
68 | -import org.thingsboard.server.service.script.JsSandboxService; | |
69 | +import org.thingsboard.server.service.script.JsInvokeService; | |
70 | +import org.thingsboard.server.service.session.DeviceSessionCacheService; | |
69 | 71 | import org.thingsboard.server.service.state.DeviceStateService; |
70 | 72 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
73 | +import org.thingsboard.server.service.transport.RuleEngineTransportService; | |
71 | 74 | |
72 | 75 | import javax.annotation.Nullable; |
73 | 76 | import java.io.IOException; |
... | ... | @@ -161,6 +164,10 @@ public class ActorSystemContext { |
161 | 164 | |
162 | 165 | @Autowired |
163 | 166 | @Getter |
167 | + private EntityViewService entityViewService; | |
168 | + | |
169 | + @Autowired | |
170 | + @Getter | |
164 | 171 | private TelemetrySubscriptionService tsSubService; |
165 | 172 | |
166 | 173 | @Autowired |
... | ... | @@ -169,7 +176,7 @@ public class ActorSystemContext { |
169 | 176 | |
170 | 177 | @Autowired |
171 | 178 | @Getter |
172 | - private JsSandboxService jsSandbox; | |
179 | + private JsInvokeService jsSandbox; | |
173 | 180 | |
174 | 181 | @Autowired |
175 | 182 | @Getter |
... | ... | @@ -193,11 +200,16 @@ public class ActorSystemContext { |
193 | 200 | |
194 | 201 | @Autowired |
195 | 202 | @Getter |
196 | - private MsgQueueService msgQueueService; | |
203 | + private DeviceStateService deviceStateService; | |
204 | + | |
205 | + @Autowired | |
206 | + @Getter | |
207 | + private DeviceSessionCacheService deviceSessionCacheService; | |
197 | 208 | |
209 | + @Lazy | |
198 | 210 | @Autowired |
199 | 211 | @Getter |
200 | - private DeviceStateService deviceStateService; | |
212 | + private RuleEngineTransportService ruleEngineTransportService; | |
201 | 213 | |
202 | 214 | @Value("${cluster.partition_id}") |
203 | 215 | @Getter |
... | ... | @@ -247,17 +259,21 @@ public class ActorSystemContext { |
247 | 259 | @Getter |
248 | 260 | private boolean allowSystemMailService; |
249 | 261 | |
262 | + @Value("${transport.sessions.inactivity_timeout}") | |
250 | 263 | @Getter |
251 | - @Setter | |
252 | - private ActorSystem actorSystem; | |
264 | + private long sessionInactivityTimeout; | |
265 | + | |
266 | + @Value("${transport.sessions.report_timeout}") | |
267 | + @Getter | |
268 | + private long sessionReportTimeout; | |
253 | 269 | |
254 | 270 | @Getter |
255 | 271 | @Setter |
256 | - private ActorRef appActor; | |
272 | + private ActorSystem actorSystem; | |
257 | 273 | |
258 | 274 | @Getter |
259 | 275 | @Setter |
260 | - private ActorRef sessionManagerActor; | |
276 | + private ActorRef appActor; | |
261 | 277 | |
262 | 278 | @Getter |
263 | 279 | @Setter | ... | ... |
... | ... | @@ -25,21 +25,24 @@ import akka.actor.Terminated; |
25 | 25 | import akka.event.Logging; |
26 | 26 | import akka.event.LoggingAdapter; |
27 | 27 | import akka.japi.Function; |
28 | +import com.google.common.collect.BiMap; | |
29 | +import com.google.common.collect.HashBiMap; | |
30 | +import lombok.extern.slf4j.Slf4j; | |
28 | 31 | import org.thingsboard.server.actors.ActorSystemContext; |
29 | 32 | import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; |
30 | 33 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
31 | 34 | import org.thingsboard.server.actors.service.DefaultActorService; |
32 | 35 | import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager; |
33 | 36 | import org.thingsboard.server.actors.tenant.TenantActor; |
37 | +import org.thingsboard.server.common.data.EntityType; | |
34 | 38 | import org.thingsboard.server.common.data.Tenant; |
35 | 39 | import org.thingsboard.server.common.data.id.TenantId; |
36 | 40 | import org.thingsboard.server.common.data.page.PageDataIterable; |
41 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
37 | 42 | import org.thingsboard.server.common.msg.TbActorMsg; |
38 | 43 | import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
39 | 44 | import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; |
40 | 45 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
41 | -import org.thingsboard.server.common.msg.core.BasicActorSystemToDeviceSessionActorMsg; | |
42 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
43 | 46 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
44 | 47 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
45 | 48 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -52,16 +55,14 @@ import java.util.Optional; |
52 | 55 | |
53 | 56 | public class AppActor extends RuleChainManagerActor { |
54 | 57 | |
55 | - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
56 | - | |
57 | - public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); | |
58 | + private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); | |
58 | 59 | private final TenantService tenantService; |
59 | - private final Map<TenantId, ActorRef> tenantActors; | |
60 | + private final BiMap<TenantId, ActorRef> tenantActors; | |
60 | 61 | |
61 | 62 | private AppActor(ActorSystemContext systemContext) { |
62 | 63 | super(systemContext, new SystemRuleChainManager(systemContext)); |
63 | 64 | this.tenantService = systemContext.getTenantService(); |
64 | - this.tenantActors = new HashMap<>(); | |
65 | + this.tenantActors = HashBiMap.create(); | |
65 | 66 | } |
66 | 67 | |
67 | 68 | @Override |
... | ... | @@ -71,22 +72,20 @@ public class AppActor extends RuleChainManagerActor { |
71 | 72 | |
72 | 73 | @Override |
73 | 74 | public void preStart() { |
74 | - logger.info("Starting main system actor."); | |
75 | + log.info("Starting main system actor."); | |
75 | 76 | try { |
76 | 77 | initRuleChains(); |
77 | - | |
78 | 78 | if (systemContext.isTenantComponentsInitEnabled()) { |
79 | 79 | PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); |
80 | 80 | for (Tenant tenant : tenantIterator) { |
81 | - logger.debug("[{}] Creating tenant actor", tenant.getId()); | |
81 | + log.debug("[{}] Creating tenant actor", tenant.getId()); | |
82 | 82 | getOrCreateTenantActor(tenant.getId()); |
83 | - logger.debug("Tenant actor created."); | |
83 | + log.debug("Tenant actor created."); | |
84 | 84 | } |
85 | 85 | } |
86 | - | |
87 | - logger.info("Main system actor started."); | |
86 | + log.info("Main system actor started."); | |
88 | 87 | } catch (Exception e) { |
89 | - logger.error(e, "Unknown failure"); | |
88 | + log.warn("Unknown failure", e); | |
90 | 89 | } |
91 | 90 | } |
92 | 91 | |
... | ... | @@ -105,7 +104,7 @@ public class AppActor extends RuleChainManagerActor { |
105 | 104 | case SERVICE_TO_RULE_ENGINE_MSG: |
106 | 105 | onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); |
107 | 106 | break; |
108 | - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | |
107 | + case TRANSPORT_TO_DEVICE_ACTOR_MSG: | |
109 | 108 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
110 | 109 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
111 | 110 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
... | ... | @@ -114,19 +113,12 @@ public class AppActor extends RuleChainManagerActor { |
114 | 113 | case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG: |
115 | 114 | onToDeviceActorMsg((TenantAwareMsg) msg); |
116 | 115 | break; |
117 | - case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG: | |
118 | - onToDeviceSessionMsg((BasicActorSystemToDeviceSessionActorMsg) msg); | |
119 | - break; | |
120 | 116 | default: |
121 | 117 | return false; |
122 | 118 | } |
123 | 119 | return true; |
124 | 120 | } |
125 | 121 | |
126 | - private void onToDeviceSessionMsg(BasicActorSystemToDeviceSessionActorMsg msg) { | |
127 | - systemContext.getSessionManagerActor().tell(msg, self()); | |
128 | - } | |
129 | - | |
130 | 122 | private void onPossibleClusterMsg(SendToClusterMsg msg) { |
131 | 123 | Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId()); |
132 | 124 | if (address.isPresent()) { |
... | ... | @@ -139,7 +131,8 @@ public class AppActor extends RuleChainManagerActor { |
139 | 131 | |
140 | 132 | private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { |
141 | 133 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
142 | - //TODO: ashvayka handle this. | |
134 | +// this may be a notification about system entities created. | |
135 | +// log.warn("[{}] Invalid service to rule engine msg called. System messages are not supported yet: {}", SYSTEM_TENANT, msg); | |
143 | 136 | } else { |
144 | 137 | getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); |
145 | 138 | } |
... | ... | @@ -152,16 +145,26 @@ public class AppActor extends RuleChainManagerActor { |
152 | 145 | } |
153 | 146 | |
154 | 147 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
155 | - ActorRef target; | |
148 | + ActorRef target = null; | |
156 | 149 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
157 | 150 | target = getEntityActorRef(msg.getEntityId()); |
158 | 151 | } else { |
159 | - target = getOrCreateTenantActor(msg.getTenantId()); | |
152 | + if (msg.getEntityId().getEntityType() == EntityType.TENANT | |
153 | + && msg.getEvent() == ComponentLifecycleEvent.DELETED) { | |
154 | + log.debug("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg); | |
155 | + ActorRef tenantActor = tenantActors.remove(new TenantId(msg.getEntityId().getId())); | |
156 | + if (tenantActor != null) { | |
157 | + log.debug("[{}] Deleting tenant actor: {}", msg.getTenantId(), tenantActor); | |
158 | + context().stop(tenantActor); | |
159 | + } | |
160 | + } else { | |
161 | + target = getOrCreateTenantActor(msg.getTenantId()); | |
162 | + } | |
160 | 163 | } |
161 | 164 | if (target != null) { |
162 | 165 | target.tell(msg, ActorRef.noSender()); |
163 | 166 | } else { |
164 | - logger.debug("Invalid component lifecycle msg: {}", msg); | |
167 | + log.debug("[{}] Invalid component lifecycle msg: {}", msg.getTenantId(), msg); | |
165 | 168 | } |
166 | 169 | } |
167 | 170 | |
... | ... | @@ -169,25 +172,25 @@ public class AppActor extends RuleChainManagerActor { |
169 | 172 | getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); |
170 | 173 | } |
171 | 174 | |
172 | - private void processDeviceMsg(DeviceToDeviceActorMsg deviceToDeviceActorMsg) { | |
173 | - TenantId tenantId = deviceToDeviceActorMsg.getTenantId(); | |
174 | - ActorRef tenantActor = getOrCreateTenantActor(tenantId); | |
175 | - if (deviceToDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { | |
176 | -// tenantActor.tell(new RuleChainDeviceMsg(deviceToDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | |
177 | - } else { | |
178 | - tenantActor.tell(deviceToDeviceActorMsg, context().self()); | |
179 | - } | |
180 | - } | |
181 | - | |
182 | 175 | private ActorRef getOrCreateTenantActor(TenantId tenantId) { |
183 | - return tenantActors.computeIfAbsent(tenantId, k -> context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId)) | |
184 | - .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString())); | |
176 | + return tenantActors.computeIfAbsent(tenantId, k -> { | |
177 | + log.debug("[{}] Creating tenant actor.", tenantId); | |
178 | + ActorRef tenantActor = context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId)) | |
179 | + .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString()); | |
180 | + context().watch(tenantActor); | |
181 | + log.debug("[{}] Created tenant actor: {}.", tenantId, tenantActor); | |
182 | + return tenantActor; | |
183 | + }); | |
185 | 184 | } |
186 | 185 | |
187 | - private void processTermination(Terminated message) { | |
186 | + @Override | |
187 | + protected void processTermination(Terminated message) { | |
188 | 188 | ActorRef terminated = message.actor(); |
189 | 189 | if (terminated instanceof LocalActorRef) { |
190 | - logger.debug("Removed actor: {}", terminated); | |
190 | + boolean removed = tenantActors.inverse().remove(terminated) != null; | |
191 | + if (removed) { | |
192 | + log.debug("[{}] Removed actor:", terminated); | |
193 | + } | |
191 | 194 | } else { |
192 | 195 | throw new IllegalStateException("Remote actors are not supported!"); |
193 | 196 | } |
... | ... | @@ -201,20 +204,17 @@ public class AppActor extends RuleChainManagerActor { |
201 | 204 | } |
202 | 205 | |
203 | 206 | @Override |
204 | - public AppActor create() throws Exception { | |
207 | + public AppActor create() { | |
205 | 208 | return new AppActor(context); |
206 | 209 | } |
207 | 210 | } |
208 | 211 | |
209 | - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, Directive>() { | |
210 | - @Override | |
211 | - public Directive apply(Throwable t) { | |
212 | - logger.error(t, "Unknown failure"); | |
213 | - if (t instanceof RuntimeException) { | |
214 | - return SupervisorStrategy.restart(); | |
215 | - } else { | |
216 | - return SupervisorStrategy.stop(); | |
217 | - } | |
212 | + private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> { | |
213 | + log.warn("Unknown failure", t); | |
214 | + if (t instanceof RuntimeException) { | |
215 | + return SupervisorStrategy.restart(); | |
216 | + } else { | |
217 | + return SupervisorStrategy.stop(); | |
218 | 218 | } |
219 | 219 | }); |
220 | 220 | } | ... | ... |
... | ... | @@ -15,43 +15,44 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | -import akka.event.Logging; | |
19 | -import akka.event.LoggingAdapter; | |
20 | 18 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
21 | 19 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
22 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 21 | import org.thingsboard.server.actors.service.ContextAwareActor; |
24 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | |
25 | 22 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
27 | 24 | import org.thingsboard.server.common.msg.TbActorMsg; |
28 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
29 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
30 | 25 | import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; |
31 | -import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | |
32 | 26 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
33 | 27 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
34 | 28 | import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; |
29 | +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | |
35 | 30 | |
36 | 31 | public class DeviceActor extends ContextAwareActor { |
37 | 32 | |
38 | - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
39 | - | |
40 | 33 | private final DeviceActorMessageProcessor processor; |
41 | 34 | |
42 | - private DeviceActor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { | |
35 | + DeviceActor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { | |
43 | 36 | super(systemContext); |
44 | - this.processor = new DeviceActorMessageProcessor(systemContext, logger, tenantId, deviceId); | |
37 | + this.processor = new DeviceActorMessageProcessor(systemContext, tenantId, deviceId); | |
38 | + } | |
39 | + | |
40 | + @Override | |
41 | + public void preStart() { | |
42 | + log.debug("[{}][{}] Starting device actor.", processor.tenantId, processor.deviceId); | |
43 | + try { | |
44 | + processor.initSessionTimeout(context()); | |
45 | + log.debug("[{}][{}] Device actor started.", processor.tenantId, processor.deviceId); | |
46 | + } catch (Exception e) { | |
47 | + log.warn("[{}][{}] Unknown failure", processor.tenantId, processor.deviceId, e); | |
48 | + } | |
45 | 49 | } |
46 | 50 | |
47 | 51 | @Override |
48 | 52 | protected boolean process(TbActorMsg msg) { |
49 | 53 | switch (msg.getMsgType()) { |
50 | - case CLUSTER_EVENT_MSG: | |
51 | - processor.processClusterEventMsg((ClusterEventMsg) msg); | |
52 | - break; | |
53 | - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | |
54 | - processor.process(context(), (DeviceToDeviceActorMsg) msg); | |
54 | + case TRANSPORT_TO_DEVICE_ACTOR_MSG: | |
55 | + processor.process(context(), (TransportToDeviceActorMsgWrapper) msg); | |
55 | 56 | break; |
56 | 57 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
57 | 58 | processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); |
... | ... | @@ -74,11 +75,8 @@ public class DeviceActor extends ContextAwareActor { |
74 | 75 | case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG: |
75 | 76 | processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg); |
76 | 77 | break; |
77 | - case DEVICE_ACTOR_QUEUE_TIMEOUT_MSG: | |
78 | - processor.processQueueTimeout(context(), (DeviceActorQueueTimeoutMsg) msg); | |
79 | - break; | |
80 | - case RULE_ENGINE_QUEUE_PUT_ACK_MSG: | |
81 | - processor.processQueueAck(context(), (RuleEngineQueuePutAckMsg) msg); | |
78 | + case SESSION_TIMEOUT_MSG: | |
79 | + processor.checkSessionsTimeout(); | |
82 | 80 | break; |
83 | 81 | default: |
84 | 82 | return false; |
... | ... | @@ -86,22 +84,4 @@ public class DeviceActor extends ContextAwareActor { |
86 | 84 | return true; |
87 | 85 | } |
88 | 86 | |
89 | - public static class ActorCreator extends ContextBasedCreator<DeviceActor> { | |
90 | - private static final long serialVersionUID = 1L; | |
91 | - | |
92 | - private final TenantId tenantId; | |
93 | - private final DeviceId deviceId; | |
94 | - | |
95 | - public ActorCreator(ActorSystemContext context, TenantId tenantId, DeviceId deviceId) { | |
96 | - super(context); | |
97 | - this.tenantId = tenantId; | |
98 | - this.deviceId = deviceId; | |
99 | - } | |
100 | - | |
101 | - @Override | |
102 | - public DeviceActor create() throws Exception { | |
103 | - return new DeviceActor(context, tenantId, deviceId); | |
104 | - } | |
105 | - } | |
106 | - | |
107 | 87 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorCreator.java
renamed from
common/message/src/main/java/org/thingsboard/server/common/msg/core/SessionCloseNotification.java
... | ... | @@ -13,26 +13,27 @@ |
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.common.msg.core; | |
16 | +package org.thingsboard.server.actors.device; | |
17 | 17 | |
18 | -import lombok.ToString; | |
19 | -import org.thingsboard.server.common.msg.kv.AttributesKVMsg; | |
20 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | |
21 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | |
22 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | |
23 | - | |
24 | -@ToString | |
25 | -public class SessionCloseNotification implements ToDeviceMsg { | |
18 | +import org.thingsboard.server.actors.ActorSystemContext; | |
19 | +import org.thingsboard.server.actors.service.ContextBasedCreator; | |
20 | +import org.thingsboard.server.common.data.id.DeviceId; | |
21 | +import org.thingsboard.server.common.data.id.TenantId; | |
26 | 22 | |
23 | +public class DeviceActorCreator extends ContextBasedCreator<DeviceActor> { | |
27 | 24 | private static final long serialVersionUID = 1L; |
28 | 25 | |
29 | - @Override | |
30 | - public boolean isSuccess() { | |
31 | - return true; | |
32 | - } | |
26 | + private final TenantId tenantId; | |
27 | + private final DeviceId deviceId; | |
33 | 28 | |
34 | - public SessionMsgType getSessionMsgType() { | |
35 | - return SessionMsgType.SESSION_CLOSE; | |
29 | + public DeviceActorCreator(ActorSystemContext context, TenantId tenantId, DeviceId deviceId) { | |
30 | + super(context); | |
31 | + this.tenantId = tenantId; | |
32 | + this.deviceId = deviceId; | |
36 | 33 | } |
37 | 34 | |
35 | + @Override | |
36 | + public DeviceActor create() { | |
37 | + return new DeviceActor(context, tenantId, deviceId); | |
38 | + } | |
38 | 39 | } | ... | ... |
... | ... | @@ -16,7 +16,6 @@ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | 18 | import akka.actor.ActorContext; |
19 | -import akka.actor.ActorRef; | |
20 | 19 | import akka.event.LoggingAdapter; |
21 | 20 | import com.datastax.driver.core.utils.UUIDs; |
22 | 21 | import com.google.common.util.concurrent.FutureCallback; |
... | ... | @@ -25,6 +24,7 @@ import com.google.common.util.concurrent.ListenableFuture; |
25 | 24 | import com.google.gson.Gson; |
26 | 25 | import com.google.gson.JsonObject; |
27 | 26 | import com.google.gson.JsonParser; |
27 | +import lombok.extern.slf4j.Slf4j; | |
28 | 28 | import org.thingsboard.rule.engine.api.RpcError; |
29 | 29 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
30 | 30 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
... | ... | @@ -33,7 +33,6 @@ import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
33 | 33 | import org.thingsboard.server.common.data.DataConstants; |
34 | 34 | import org.thingsboard.server.common.data.Device; |
35 | 35 | import org.thingsboard.server.common.data.id.DeviceId; |
36 | -import org.thingsboard.server.common.data.id.SessionId; | |
37 | 36 | import org.thingsboard.server.common.data.id.TenantId; |
38 | 37 | import org.thingsboard.server.common.data.kv.AttributeKey; |
39 | 38 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
... | ... | @@ -43,37 +42,34 @@ import org.thingsboard.server.common.msg.TbMsg; |
43 | 42 | import org.thingsboard.server.common.msg.TbMsgDataType; |
44 | 43 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
45 | 44 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
46 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
47 | -import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; | |
48 | -import org.thingsboard.server.common.msg.core.AttributesUpdateNotification; | |
49 | -import org.thingsboard.server.common.msg.core.AttributesUpdateRequest; | |
50 | -import org.thingsboard.server.common.msg.core.BasicActorSystemToDeviceSessionActorMsg; | |
51 | -import org.thingsboard.server.common.msg.core.BasicCommandAckResponse; | |
52 | -import org.thingsboard.server.common.msg.core.BasicGetAttributesResponse; | |
53 | -import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; | |
54 | -import org.thingsboard.server.common.msg.core.GetAttributesRequest; | |
55 | -import org.thingsboard.server.common.msg.core.RuleEngineError; | |
56 | -import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg; | |
57 | -import org.thingsboard.server.common.msg.core.SessionCloseMsg; | |
58 | -import org.thingsboard.server.common.msg.core.SessionCloseNotification; | |
59 | -import org.thingsboard.server.common.msg.core.SessionOpenMsg; | |
60 | -import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | |
61 | -import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg; | |
62 | -import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg; | |
63 | -import org.thingsboard.server.common.msg.core.ToServerRpcRequestMsg; | |
64 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
65 | -import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg; | |
66 | 45 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
67 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | |
68 | 46 | import org.thingsboard.server.common.msg.session.SessionMsgType; |
69 | -import org.thingsboard.server.common.msg.session.SessionType; | |
70 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | |
71 | 47 | import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; |
72 | -import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | |
73 | 48 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
49 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
50 | +import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | |
51 | +import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; | |
52 | +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; | |
53 | +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | |
54 | +import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; | |
55 | +import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; | |
56 | +import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; | |
57 | +import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg; | |
58 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; | |
59 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; | |
60 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; | |
61 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | |
62 | +import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; | |
63 | +import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg; | |
64 | +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; | |
65 | +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; | |
66 | +import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | |
67 | +import org.thingsboard.server.gen.transport.TransportProtos.TsKvListProto; | |
68 | +import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; | |
74 | 69 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
75 | 70 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
76 | 71 | import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; |
72 | +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | |
77 | 73 | |
78 | 74 | import javax.annotation.Nullable; |
79 | 75 | import java.util.ArrayList; |
... | ... | @@ -87,24 +83,22 @@ import java.util.Map; |
87 | 83 | import java.util.Optional; |
88 | 84 | import java.util.Set; |
89 | 85 | import java.util.UUID; |
90 | -import java.util.concurrent.TimeoutException; | |
91 | 86 | import java.util.function.Consumer; |
92 | -import java.util.function.Predicate; | |
93 | 87 | import java.util.stream.Collectors; |
94 | 88 | |
95 | 89 | /** |
96 | 90 | * @author Andrew Shvayka |
97 | 91 | */ |
98 | -public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | |
99 | - | |
100 | - private final TenantId tenantId; | |
101 | - private final DeviceId deviceId; | |
102 | - private final Map<SessionId, SessionInfo> sessions; | |
103 | - private final Map<SessionId, SessionInfo> attributeSubscriptions; | |
104 | - private final Map<SessionId, SessionInfo> rpcSubscriptions; | |
92 | +@Slf4j | |
93 | +class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | |
94 | + | |
95 | + final TenantId tenantId; | |
96 | + final DeviceId deviceId; | |
97 | + private final Map<UUID, SessionInfoMetaData> sessions; | |
98 | + private final Map<UUID, SessionInfo> attributeSubscriptions; | |
99 | + private final Map<UUID, SessionInfo> rpcSubscriptions; | |
105 | 100 | private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; |
106 | 101 | private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap; |
107 | - private final Map<UUID, PendingSessionMsgData> pendingMsgs; | |
108 | 102 | |
109 | 103 | private final Gson gson = new Gson(); |
110 | 104 | private final JsonParser jsonParser = new JsonParser(); |
... | ... | @@ -114,8 +108,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
114 | 108 | private String deviceType; |
115 | 109 | private TbMsgMetaData defaultMetaData; |
116 | 110 | |
117 | - DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, DeviceId deviceId) { | |
118 | - super(systemContext, logger); | |
111 | + DeviceActorMessageProcessor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { | |
112 | + super(systemContext); | |
119 | 113 | this.tenantId = tenantId; |
120 | 114 | this.deviceId = deviceId; |
121 | 115 | this.sessions = new LinkedHashMap<>(); |
... | ... | @@ -123,8 +117,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
123 | 117 | this.rpcSubscriptions = new HashMap<>(); |
124 | 118 | this.toDeviceRpcPendingMap = new HashMap<>(); |
125 | 119 | this.toServerRpcPendingMap = new HashMap<>(); |
126 | - this.pendingMsgs = new HashMap<>(); | |
127 | 120 | initAttributes(); |
121 | + restoreSessions(); | |
128 | 122 | } |
129 | 123 | |
130 | 124 | private void initAttributes() { |
... | ... | @@ -139,41 +133,36 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
139 | 133 | void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) { |
140 | 134 | ToDeviceRpcRequest request = msg.getMsg(); |
141 | 135 | ToDeviceRpcRequestBody body = request.getBody(); |
142 | - ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( | |
143 | - rpcSeq++, | |
144 | - body.getMethod(), | |
145 | - body.getParams() | |
146 | - ); | |
136 | + ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId( | |
137 | + rpcSeq++).setMethodName(body.getMethod()).setParams(body.getParams()).build(); | |
147 | 138 | |
148 | 139 | long timeout = request.getExpirationTime() - System.currentTimeMillis(); |
149 | 140 | if (timeout <= 0) { |
150 | - logger.debug("[{}][{}] Ignoring message due to exp time reached", deviceId, request.getId(), request.getExpirationTime()); | |
141 | + log.debug("[{}][{}] Ignoring message due to exp time reached, {}", deviceId, request.getId(), request.getExpirationTime()); | |
151 | 142 | return; |
152 | 143 | } |
153 | 144 | |
154 | 145 | boolean sent = rpcSubscriptions.size() > 0; |
155 | - Set<SessionId> syncSessionSet = new HashSet<>(); | |
156 | - rpcSubscriptions.entrySet().forEach(sub -> { | |
157 | - ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sub.getKey()); | |
158 | - sendMsgToSessionActor(response, sub.getValue().getServer()); | |
159 | - if (SessionType.SYNC == sub.getValue().getType()) { | |
160 | - syncSessionSet.add(sub.getKey()); | |
146 | + Set<UUID> syncSessionSet = new HashSet<>(); | |
147 | + rpcSubscriptions.forEach((key, value) -> { | |
148 | + sendToTransport(rpcRequest, key, value.getNodeId()); | |
149 | + if (TransportProtos.SessionType.SYNC == value.getType()) { | |
150 | + syncSessionSet.add(key); | |
161 | 151 | } |
162 | 152 | }); |
163 | 153 | syncSessionSet.forEach(rpcSubscriptions::remove); |
164 | 154 | |
165 | 155 | if (request.isOneway() && sent) { |
166 | - logger.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); | |
167 | - systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(msg.getMsg().getId(), msg.getServerAddress(), null, null)); | |
156 | + log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); | |
157 | + systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null)); | |
168 | 158 | } else { |
169 | 159 | registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); |
170 | 160 | } |
171 | 161 | if (sent) { |
172 | - logger.debug("[{}] RPC request {} is sent!", deviceId, request.getId()); | |
162 | + log.debug("[{}] RPC request {} is sent!", deviceId, request.getId()); | |
173 | 163 | } else { |
174 | - logger.debug("[{}] RPC request {} is NOT sent!", deviceId, request.getId()); | |
164 | + log.debug("[{}] RPC request {} is NOT sent!", deviceId, request.getId()); | |
175 | 165 | } |
176 | - | |
177 | 166 | } |
178 | 167 | |
179 | 168 | private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { |
... | ... | @@ -185,101 +174,82 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
185 | 174 | void processServerSideRpcTimeout(ActorContext context, DeviceActorServerSideRpcTimeoutMsg msg) { |
186 | 175 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); |
187 | 176 | if (requestMd != null) { |
188 | - logger.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); | |
189 | - systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | |
190 | - requestMd.getMsg().getServerAddress(), null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); | |
191 | - } | |
192 | - } | |
193 | - | |
194 | - void processQueueTimeout(ActorContext context, DeviceActorQueueTimeoutMsg msg) { | |
195 | - PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | |
196 | - if (data != null) { | |
197 | - logger.debug("[{}] Queue put [{}] timeout detected!", deviceId, msg.getId()); | |
198 | - ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(data.getSessionMsgType(), RuleEngineError.QUEUE_PUT_TIMEOUT); | |
199 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | |
200 | - } | |
201 | - } | |
202 | - | |
203 | - void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { | |
204 | - PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | |
205 | - if (data != null && data.isReplyOnQueueAck()) { | |
206 | - int remainingAcks = data.getAckMsgCount() - 1; | |
207 | - data.setAckMsgCount(remainingAcks); | |
208 | - logger.debug("[{}] Queue put [{}] ack detected. Remaining acks: {}!", deviceId, msg.getId(), remainingAcks); | |
209 | - if (remainingAcks == 0) { | |
210 | - ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId()); | |
211 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | |
212 | - } | |
177 | + log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); | |
178 | + systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | |
179 | + null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); | |
213 | 180 | } |
214 | 181 | } |
215 | 182 | |
216 | - private void sendPendingRequests(ActorContext context, SessionId sessionId, SessionType type, Optional<ServerAddress> server) { | |
183 | + private void sendPendingRequests(ActorContext context, UUID sessionId, SessionInfoProto sessionInfo) { | |
184 | + TransportProtos.SessionType sessionType = getSessionType(sessionId); | |
217 | 185 | if (!toDeviceRpcPendingMap.isEmpty()) { |
218 | - logger.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); | |
219 | - if (type == SessionType.SYNC) { | |
220 | - logger.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); | |
186 | + log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); | |
187 | + if (sessionType == TransportProtos.SessionType.SYNC) { | |
188 | + log.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); | |
221 | 189 | rpcSubscriptions.remove(sessionId); |
222 | 190 | } |
223 | 191 | } else { |
224 | - logger.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId); | |
192 | + log.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId); | |
225 | 193 | } |
226 | 194 | Set<Integer> sentOneWayIds = new HashSet<>(); |
227 | - if (type == SessionType.ASYNC) { | |
228 | - toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, server, sentOneWayIds)); | |
195 | + if (sessionType == TransportProtos.SessionType.ASYNC) { | |
196 | + toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); | |
229 | 197 | } else { |
230 | - toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, server, sentOneWayIds)); | |
198 | + toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); | |
231 | 199 | } |
232 | 200 | |
233 | 201 | sentOneWayIds.forEach(toDeviceRpcPendingMap::remove); |
234 | 202 | } |
235 | 203 | |
236 | - private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, SessionId sessionId, Optional<ServerAddress> server, Set<Integer> sentOneWayIds) { | |
204 | + private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, UUID sessionId, String nodeId, Set<Integer> sentOneWayIds) { | |
237 | 205 | return entry -> { |
238 | - ToDeviceRpcRequestActorMsg requestActorMsg = entry.getValue().getMsg(); | |
239 | 206 | ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg(); |
240 | 207 | ToDeviceRpcRequestBody body = request.getBody(); |
241 | 208 | if (request.isOneway()) { |
242 | 209 | sentOneWayIds.add(entry.getKey()); |
243 | - systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(request.getId(), requestActorMsg.getServerAddress(), null, null)); | |
210 | + systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(request.getId(), null, null)); | |
244 | 211 | } |
245 | - ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( | |
246 | - entry.getKey(), | |
247 | - body.getMethod(), | |
248 | - body.getParams() | |
249 | - ); | |
250 | - ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sessionId); | |
251 | - sendMsgToSessionActor(response, server); | |
212 | + ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId( | |
213 | + entry.getKey()).setMethodName(body.getMethod()).setParams(body.getParams()).build(); | |
214 | + sendToTransport(rpcRequest, sessionId, nodeId); | |
252 | 215 | }; |
253 | 216 | } |
254 | 217 | |
255 | - void process(ActorContext context, DeviceToDeviceActorMsg msg) { | |
256 | - processSubscriptionCommands(context, msg); | |
257 | - processRpcResponses(context, msg); | |
258 | - processSessionStateMsgs(msg); | |
259 | - | |
260 | - SessionMsgType sessionMsgType = msg.getPayload().getMsgType(); | |
261 | - if (sessionMsgType.requiresRulesProcessing()) { | |
262 | - switch (sessionMsgType) { | |
263 | - case GET_ATTRIBUTES_REQUEST: | |
264 | - handleGetAttributesRequest(msg); | |
265 | - break; | |
266 | - case POST_ATTRIBUTES_REQUEST: | |
267 | - handlePostAttributesRequest(context, msg); | |
268 | - reportActivity(); | |
269 | - break; | |
270 | - case POST_TELEMETRY_REQUEST: | |
271 | - handlePostTelemetryRequest(context, msg); | |
272 | - reportActivity(); | |
273 | - break; | |
274 | - case TO_SERVER_RPC_REQUEST: | |
275 | - handleClientSideRPCRequest(context, msg); | |
276 | - reportActivity(); | |
277 | - break; | |
278 | - } | |
218 | + void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) { | |
219 | + TransportToDeviceActorMsg msg = wrapper.getMsg(); | |
220 | + if (msg.hasSessionEvent()) { | |
221 | + processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent()); | |
222 | + } | |
223 | + if (msg.hasSubscribeToAttributes()) { | |
224 | + processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToAttributes()); | |
225 | + } | |
226 | + if (msg.hasSubscribeToRPC()) { | |
227 | + processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToRPC()); | |
228 | + } | |
229 | + if (msg.hasPostAttributes()) { | |
230 | + handlePostAttributesRequest(context, msg.getSessionInfo(), msg.getPostAttributes()); | |
231 | + reportLogicalDeviceActivity(); | |
232 | + } | |
233 | + if (msg.hasPostTelemetry()) { | |
234 | + handlePostTelemetryRequest(context, msg.getSessionInfo(), msg.getPostTelemetry()); | |
235 | + reportLogicalDeviceActivity(); | |
236 | + } | |
237 | + if (msg.hasGetAttributes()) { | |
238 | + handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes()); | |
239 | + } | |
240 | + if (msg.hasToDeviceRPCCallResponse()) { | |
241 | + processRpcResponses(context, msg.getSessionInfo(), msg.getToDeviceRPCCallResponse()); | |
242 | + } | |
243 | + if (msg.hasToServerRPCCallRequest()) { | |
244 | + handleClientSideRPCRequest(context, msg.getSessionInfo(), msg.getToServerRPCCallRequest()); | |
245 | + reportLogicalDeviceActivity(); | |
246 | + } | |
247 | + if (msg.hasSubscriptionInfo()) { | |
248 | + handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); | |
279 | 249 | } |
280 | 250 | } |
281 | 251 | |
282 | - private void reportActivity() { | |
252 | + private void reportLogicalDeviceActivity() { | |
283 | 253 | systemContext.getDeviceStateService().onDeviceActivity(deviceId); |
284 | 254 | } |
285 | 255 | |
... | ... | @@ -291,27 +261,27 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
291 | 261 | systemContext.getDeviceStateService().onDeviceDisconnect(deviceId); |
292 | 262 | } |
293 | 263 | |
294 | - private void handleGetAttributesRequest(DeviceToDeviceActorMsg src) { | |
295 | - GetAttributesRequest request = (GetAttributesRequest) src.getPayload(); | |
296 | - ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, request.getClientAttributeNames()); | |
297 | - ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, request.getSharedAttributeNames()); | |
298 | - | |
264 | + private void handleGetAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, GetAttributeRequestMsg request) { | |
265 | + ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, toOptionalSet(request.getClientAttributeNamesList())); | |
266 | + ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, toOptionalSet(request.getSharedAttributeNamesList())); | |
267 | + int requestId = request.getRequestId(); | |
299 | 268 | Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() { |
300 | 269 | @Override |
301 | 270 | public void onSuccess(@Nullable List<List<AttributeKvEntry>> result) { |
302 | - BasicGetAttributesResponse response = BasicGetAttributesResponse.onSuccess(request.getMsgType(), | |
303 | - request.getRequestId(), BasicAttributeKVMsg.from(result.get(0), result.get(1))); | |
304 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(response, src.getSessionId()), src.getServerAddress()); | |
271 | + GetAttributeResponseMsg responseMsg = GetAttributeResponseMsg.newBuilder() | |
272 | + .setRequestId(requestId) | |
273 | + .addAllClientAttributeList(toTsKvProtos(result.get(0))) | |
274 | + .addAllSharedAttributeList(toTsKvProtos(result.get(1))) | |
275 | + .build(); | |
276 | + sendToTransport(responseMsg, sessionInfo); | |
305 | 277 | } |
306 | 278 | |
307 | 279 | @Override |
308 | 280 | public void onFailure(Throwable t) { |
309 | - if (t instanceof Exception) { | |
310 | - ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onError(SessionMsgType.GET_ATTRIBUTES_REQUEST, request.getRequestId(), (Exception) t); | |
311 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, src.getSessionId()), src.getServerAddress()); | |
312 | - } else { | |
313 | - logger.error("[{}] Failed to process attributes request", deviceId, t); | |
314 | - } | |
281 | + GetAttributeResponseMsg responseMsg = GetAttributeResponseMsg.newBuilder() | |
282 | + .setError(t.getMessage()) | |
283 | + .build(); | |
284 | + sendToTransport(responseMsg, sessionInfo); | |
315 | 285 | } |
316 | 286 | }); |
317 | 287 | } |
... | ... | @@ -328,220 +298,221 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
328 | 298 | } |
329 | 299 | } |
330 | 300 | |
331 | - private void handlePostAttributesRequest(ActorContext context, DeviceToDeviceActorMsg src) { | |
332 | - AttributesUpdateRequest request = (AttributesUpdateRequest) src.getPayload(); | |
333 | - | |
334 | - JsonObject json = new JsonObject(); | |
335 | - for (AttributeKvEntry kv : request.getAttributes()) { | |
336 | - kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
337 | - kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
338 | - kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
339 | - kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
340 | - } | |
341 | - | |
342 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | |
343 | - PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | |
344 | - SessionMsgType.POST_ATTRIBUTES_REQUEST, request.getRequestId(), true, 1); | |
345 | - pushToRuleEngineWithTimeout(context, tbMsg, msgData); | |
301 | + private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) { | |
302 | + JsonObject json = getJsonObject(postAttributes.getKvList()); | |
303 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), | |
304 | + TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | |
305 | + pushToRuleEngine(context, tbMsg); | |
346 | 306 | } |
347 | 307 | |
348 | - private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) { | |
349 | - TelemetryUploadRequest request = (TelemetryUploadRequest) src.getPayload(); | |
350 | - | |
351 | - Map<Long, List<KvEntry>> tsData = request.getData(); | |
352 | - | |
353 | - PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | |
354 | - SessionMsgType.POST_TELEMETRY_REQUEST, request.getRequestId(), true, tsData.size()); | |
355 | - | |
356 | - for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) { | |
357 | - JsonObject json = new JsonObject(); | |
358 | - for (KvEntry kv : entry.getValue()) { | |
359 | - kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
360 | - kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
361 | - kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
362 | - kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
363 | - } | |
308 | + private void handlePostTelemetryRequest(ActorContext context, SessionInfoProto sessionInfo, PostTelemetryMsg postTelemetry) { | |
309 | + for (TsKvListProto tsKv : postTelemetry.getTsKvListList()) { | |
310 | + JsonObject json = getJsonObject(tsKv.getKvList()); | |
364 | 311 | TbMsgMetaData metaData = defaultMetaData.copy(); |
365 | - metaData.putValue("ts", entry.getKey() + ""); | |
312 | + metaData.putValue("ts", tsKv.getTs() + ""); | |
366 | 313 | TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); |
367 | - pushToRuleEngineWithTimeout(context, tbMsg, msgData); | |
314 | + pushToRuleEngine(context, tbMsg); | |
368 | 315 | } |
369 | 316 | } |
370 | 317 | |
371 | - private void handleClientSideRPCRequest(ActorContext context, DeviceToDeviceActorMsg src) { | |
372 | - ToServerRpcRequestMsg request = (ToServerRpcRequestMsg) src.getPayload(); | |
373 | - | |
318 | + private void handleClientSideRPCRequest(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.ToServerRpcRequestMsg request) { | |
319 | + UUID sessionId = getSessionId(sessionInfo); | |
374 | 320 | JsonObject json = new JsonObject(); |
375 | - json.addProperty("method", request.getMethod()); | |
321 | + json.addProperty("method", request.getMethodName()); | |
376 | 322 | json.add("params", jsonParser.parse(request.getParams())); |
377 | 323 | |
378 | 324 | TbMsgMetaData requestMetaData = defaultMetaData.copy(); |
379 | 325 | requestMetaData.putValue("requestId", Integer.toString(request.getRequestId())); |
380 | 326 | TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); |
381 | - PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), SessionMsgType.TO_SERVER_RPC_REQUEST, request.getRequestId(), false, 1); | |
382 | - pushToRuleEngineWithTimeout(context, tbMsg, msgData); | |
327 | + context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); | |
383 | 328 | |
384 | 329 | scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout()); |
385 | - toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(src.getSessionId(), src.getSessionType(), src.getServerAddress())); | |
330 | + toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(sessionId, getSessionType(sessionId), sessionInfo.getNodeId())); | |
331 | + } | |
332 | + | |
333 | + private TransportProtos.SessionType getSessionType(UUID sessionId) { | |
334 | + return sessions.containsKey(sessionId) ? TransportProtos.SessionType.ASYNC : TransportProtos.SessionType.SYNC; | |
386 | 335 | } |
387 | 336 | |
388 | - public void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) { | |
337 | + void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) { | |
389 | 338 | ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId()); |
390 | 339 | if (data != null) { |
391 | - logger.debug("[{}] Client side RPC request [{}] timeout detected!", deviceId, msg.getId()); | |
392 | - ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(SessionMsgType.TO_SERVER_RPC_REQUEST, RuleEngineError.TIMEOUT); | |
393 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServer()); | |
340 | + log.debug("[{}] Client side RPC request [{}] timeout detected!", deviceId, msg.getId()); | |
341 | + sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder() | |
342 | + .setRequestId(msg.getId()).setError("timeout").build() | |
343 | + , data.getSessionId(), data.getNodeId()); | |
394 | 344 | } |
395 | 345 | } |
396 | 346 | |
397 | 347 | void processToServerRPCResponse(ActorContext context, ToServerRpcResponseActorMsg msg) { |
398 | - ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getMsg().getRequestId()); | |
348 | + int requestId = msg.getMsg().getRequestId(); | |
349 | + ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(requestId); | |
399 | 350 | if (data != null) { |
400 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(msg.getMsg(), data.getSessionId()), data.getServer()); | |
351 | + log.debug("[{}] Pushing reply to [{}][{}]!", deviceId, data.getNodeId(), data.getSessionId()); | |
352 | + sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder() | |
353 | + .setRequestId(requestId).setPayload(msg.getMsg().getData()).build() | |
354 | + , data.getSessionId(), data.getNodeId()); | |
355 | + } else { | |
356 | + log.debug("[{}][{}] Pending RPC request to server not found!", deviceId, requestId); | |
401 | 357 | } |
402 | 358 | } |
403 | 359 | |
404 | - private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, PendingSessionMsgData pendingMsgData) { | |
405 | - SessionMsgType sessionMsgType = pendingMsgData.getSessionMsgType(); | |
406 | - int requestId = pendingMsgData.getRequestId(); | |
407 | - if (systemContext.isQueuePersistenceEnabled()) { | |
408 | - pendingMsgs.put(tbMsg.getId(), pendingMsgData); | |
409 | - scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout()); | |
410 | - } else { | |
411 | - ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), pendingMsgData.getSessionId()); | |
412 | - sendMsgToSessionActor(response, pendingMsgData.getServerAddress()); | |
413 | - } | |
360 | + private void pushToRuleEngine(ActorContext context, TbMsg tbMsg) { | |
414 | 361 | context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); |
415 | 362 | } |
416 | 363 | |
417 | 364 | void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { |
418 | 365 | if (attributeSubscriptions.size() > 0) { |
419 | - ToDeviceMsg notification = null; | |
366 | + boolean hasNotificationData = false; | |
367 | + AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder(); | |
420 | 368 | if (msg.isDeleted()) { |
421 | - List<AttributeKey> sharedKeys = msg.getDeletedKeys().stream() | |
369 | + List<String> sharedKeys = msg.getDeletedKeys().stream() | |
422 | 370 | .filter(key -> DataConstants.SHARED_SCOPE.equals(key.getScope())) |
371 | + .map(AttributeKey::getAttributeKey) | |
423 | 372 | .collect(Collectors.toList()); |
424 | - notification = new AttributesUpdateNotification(BasicAttributeKVMsg.fromDeleted(sharedKeys)); | |
373 | + if (!sharedKeys.isEmpty()) { | |
374 | + notification.addAllSharedDeleted(sharedKeys); | |
375 | + hasNotificationData = true; | |
376 | + } | |
425 | 377 | } else { |
426 | 378 | if (DataConstants.SHARED_SCOPE.equals(msg.getScope())) { |
427 | 379 | List<AttributeKvEntry> attributes = new ArrayList<>(msg.getValues()); |
428 | 380 | if (attributes.size() > 0) { |
429 | - notification = new AttributesUpdateNotification(BasicAttributeKVMsg.fromShared(attributes)); | |
381 | + List<TsKvProto> sharedUpdated = msg.getValues().stream().map(this::toTsKvProto) | |
382 | + .collect(Collectors.toList()); | |
383 | + if (!sharedUpdated.isEmpty()) { | |
384 | + notification.addAllSharedUpdated(sharedUpdated); | |
385 | + hasNotificationData = true; | |
386 | + } | |
430 | 387 | } else { |
431 | - logger.debug("[{}] No public server side attributes changed!", deviceId); | |
388 | + log.debug("[{}] No public server side attributes changed!", deviceId); | |
432 | 389 | } |
433 | 390 | } |
434 | 391 | } |
435 | - if (notification != null) { | |
436 | - ToDeviceMsg finalNotification = notification; | |
392 | + if (hasNotificationData) { | |
393 | + AttributeUpdateNotificationMsg finalNotification = notification.build(); | |
437 | 394 | attributeSubscriptions.entrySet().forEach(sub -> { |
438 | - ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(finalNotification, sub.getKey()); | |
439 | - sendMsgToSessionActor(response, sub.getValue().getServer()); | |
395 | + sendToTransport(finalNotification, sub.getKey(), sub.getValue().getNodeId()); | |
440 | 396 | }); |
441 | 397 | } |
442 | 398 | } else { |
443 | - logger.debug("[{}] No registered attributes subscriptions to process!", deviceId); | |
399 | + log.debug("[{}] No registered attributes subscriptions to process!", deviceId); | |
444 | 400 | } |
445 | 401 | } |
446 | 402 | |
447 | - private void processRpcResponses(ActorContext context, DeviceToDeviceActorMsg msg) { | |
448 | - SessionId sessionId = msg.getSessionId(); | |
449 | - FromDeviceMsg inMsg = msg.getPayload(); | |
450 | - if (inMsg.getMsgType() == SessionMsgType.TO_DEVICE_RPC_RESPONSE) { | |
451 | - logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); | |
452 | - ToDeviceRpcResponseMsg responseMsg = (ToDeviceRpcResponseMsg) inMsg; | |
453 | - ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); | |
454 | - boolean success = requestMd != null; | |
455 | - if (success) { | |
456 | - systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | |
457 | - requestMd.getMsg().getServerAddress(), responseMsg.getData(), null)); | |
458 | - } else { | |
459 | - logger.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); | |
460 | - } | |
461 | - if (msg.getSessionType() == SessionType.SYNC) { | |
462 | - BasicCommandAckResponse response = success | |
463 | - ? BasicCommandAckResponse.onSuccess(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId()) | |
464 | - : BasicCommandAckResponse.onError(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId(), new TimeoutException()); | |
465 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(response, msg.getSessionId()), msg.getServerAddress()); | |
466 | - } | |
403 | + private void processRpcResponses(ActorContext context, SessionInfoProto sessionInfo, ToDeviceRpcResponseMsg responseMsg) { | |
404 | + UUID sessionId = getSessionId(sessionInfo); | |
405 | + log.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); | |
406 | + ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); | |
407 | + boolean success = requestMd != null; | |
408 | + if (success) { | |
409 | + systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | |
410 | + responseMsg.getPayload(), null)); | |
411 | + } else { | |
412 | + log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); | |
467 | 413 | } |
468 | 414 | } |
469 | 415 | |
470 | - void processClusterEventMsg(ClusterEventMsg msg) { | |
471 | - if (!msg.isAdded()) { | |
472 | - logger.debug("[{}] Clearing attributes/rpc subscription for server [{}]", deviceId, msg.getServerAddress()); | |
473 | - Predicate<Map.Entry<SessionId, SessionInfo>> filter = e -> e.getValue().getServer() | |
474 | - .map(serverAddress -> serverAddress.equals(msg.getServerAddress())).orElse(false); | |
475 | - attributeSubscriptions.entrySet().removeIf(filter); | |
476 | - rpcSubscriptions.entrySet().removeIf(filter); | |
416 | + private void processSubscriptionCommands(ActorContext context, SessionInfoProto sessionInfo, SubscribeToAttributeUpdatesMsg subscribeCmd) { | |
417 | + UUID sessionId = getSessionId(sessionInfo); | |
418 | + if (subscribeCmd.getUnsubscribe()) { | |
419 | + log.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId); | |
420 | + attributeSubscriptions.remove(sessionId); | |
421 | + } else { | |
422 | + SessionInfoMetaData sessionMD = sessions.get(sessionId); | |
423 | + if (sessionMD == null) { | |
424 | + sessionMD = new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.SYNC, sessionInfo.getNodeId())); | |
425 | + } | |
426 | + sessionMD.setSubscribedToAttributes(true); | |
427 | + log.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); | |
428 | + attributeSubscriptions.put(sessionId, sessionMD.getSessionInfo()); | |
429 | + dumpSessions(); | |
477 | 430 | } |
478 | 431 | } |
479 | 432 | |
480 | - private void processSubscriptionCommands(ActorContext context, DeviceToDeviceActorMsg msg) { | |
481 | - SessionId sessionId = msg.getSessionId(); | |
482 | - SessionType sessionType = msg.getSessionType(); | |
483 | - FromDeviceMsg inMsg = msg.getPayload(); | |
484 | - if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST) { | |
485 | - logger.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); | |
486 | - attributeSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); | |
487 | - } else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST) { | |
488 | - logger.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId); | |
489 | - attributeSubscriptions.remove(sessionId); | |
490 | - } else if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST) { | |
491 | - logger.debug("[{}] Registering rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); | |
492 | - rpcSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); | |
493 | - sendPendingRequests(context, sessionId, sessionType, msg.getServerAddress()); | |
494 | - } else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST) { | |
495 | - logger.debug("[{}] Canceling rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); | |
433 | + private UUID getSessionId(SessionInfoProto sessionInfo) { | |
434 | + return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); | |
435 | + } | |
436 | + | |
437 | + private void processSubscriptionCommands(ActorContext context, SessionInfoProto sessionInfo, SubscribeToRPCMsg subscribeCmd) { | |
438 | + UUID sessionId = getSessionId(sessionInfo); | |
439 | + if (subscribeCmd.getUnsubscribe()) { | |
440 | + log.debug("[{}] Canceling rpc subscription for session [{}]", deviceId, sessionId); | |
496 | 441 | rpcSubscriptions.remove(sessionId); |
442 | + } else { | |
443 | + SessionInfoMetaData sessionMD = sessions.get(sessionId); | |
444 | + if (sessionMD == null) { | |
445 | + sessionMD = new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.SYNC, sessionInfo.getNodeId())); | |
446 | + } | |
447 | + sessionMD.setSubscribedToRPC(true); | |
448 | + log.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId); | |
449 | + rpcSubscriptions.put(sessionId, sessionMD.getSessionInfo()); | |
450 | + sendPendingRequests(context, sessionId, sessionInfo); | |
451 | + dumpSessions(); | |
497 | 452 | } |
498 | 453 | } |
499 | 454 | |
500 | - private void processSessionStateMsgs(DeviceToDeviceActorMsg msg) { | |
501 | - SessionId sessionId = msg.getSessionId(); | |
502 | - FromDeviceMsg inMsg = msg.getPayload(); | |
503 | - if (inMsg instanceof SessionOpenMsg) { | |
504 | - logger.debug("[{}] Processing new session [{}]", deviceId, sessionId); | |
455 | + private void processSessionStateMsgs(SessionInfoProto sessionInfo, SessionEventMsg msg) { | |
456 | + UUID sessionId = getSessionId(sessionInfo); | |
457 | + if (msg.getEvent() == SessionEvent.OPEN) { | |
458 | + if (sessions.containsKey(sessionId)) { | |
459 | + log.debug("[{}] Received duplicate session open event [{}]", deviceId, sessionId); | |
460 | + return; | |
461 | + } | |
462 | + log.debug("[{}] Processing new session [{}]", deviceId, sessionId); | |
505 | 463 | if (sessions.size() >= systemContext.getMaxConcurrentSessionsPerDevice()) { |
506 | - SessionId sessionIdToRemove = sessions.keySet().stream().findFirst().orElse(null); | |
464 | + UUID sessionIdToRemove = sessions.keySet().stream().findFirst().orElse(null); | |
507 | 465 | if (sessionIdToRemove != null) { |
508 | - closeSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); | |
466 | + notifyTransportAboutClosedSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); | |
509 | 467 | } |
510 | 468 | } |
511 | - sessions.put(sessionId, new SessionInfo(SessionType.ASYNC, msg.getServerAddress())); | |
469 | + sessions.put(sessionId, new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfo.getNodeId()))); | |
512 | 470 | if (sessions.size() == 1) { |
513 | 471 | reportSessionOpen(); |
514 | 472 | } |
515 | - } else if (inMsg instanceof SessionCloseMsg) { | |
516 | - logger.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); | |
473 | + dumpSessions(); | |
474 | + } else if (msg.getEvent() == SessionEvent.CLOSED) { | |
475 | + log.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); | |
517 | 476 | sessions.remove(sessionId); |
518 | 477 | attributeSubscriptions.remove(sessionId); |
519 | 478 | rpcSubscriptions.remove(sessionId); |
520 | 479 | if (sessions.isEmpty()) { |
521 | 480 | reportSessionClose(); |
522 | 481 | } |
482 | + dumpSessions(); | |
523 | 483 | } |
524 | 484 | } |
525 | 485 | |
526 | - private void sendMsgToSessionActor(ActorSystemToDeviceSessionActorMsg response, Optional<ServerAddress> sessionAddress) { | |
527 | - if (sessionAddress.isPresent()) { | |
528 | - ServerAddress address = sessionAddress.get(); | |
529 | - logger.debug("{} Forwarding msg: {}", address, response); | |
530 | - systemContext.getRpcService().tell(systemContext.getEncodingService() | |
531 | - .convertToProtoDataMessage(sessionAddress.get(), response)); | |
532 | - } else { | |
533 | - systemContext.getSessionManagerActor().tell(response, ActorRef.noSender()); | |
486 | + private void handleSessionActivity(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.SubscriptionInfoProto subscriptionInfo) { | |
487 | + UUID sessionId = getSessionId(sessionInfo); | |
488 | + SessionInfoMetaData sessionMD = sessions.get(sessionId); | |
489 | + if (sessionMD != null) { | |
490 | + sessionMD.setLastActivityTime(subscriptionInfo.getLastActivityTime()); | |
491 | + sessionMD.setSubscribedToAttributes(subscriptionInfo.getAttributeSubscription()); | |
492 | + sessionMD.setSubscribedToRPC(subscriptionInfo.getRpcSubscription()); | |
493 | + if (subscriptionInfo.getAttributeSubscription()) { | |
494 | + attributeSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo()); | |
495 | + } | |
496 | + if (subscriptionInfo.getRpcSubscription()) { | |
497 | + rpcSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo()); | |
498 | + } | |
534 | 499 | } |
500 | + dumpSessions(); | |
535 | 501 | } |
536 | 502 | |
537 | 503 | void processCredentialsUpdate() { |
538 | - sessions.forEach(this::closeSession); | |
504 | + sessions.forEach(this::notifyTransportAboutClosedSession); | |
539 | 505 | attributeSubscriptions.clear(); |
540 | 506 | rpcSubscriptions.clear(); |
507 | + dumpSessions(); | |
541 | 508 | } |
542 | 509 | |
543 | - private void closeSession(SessionId sessionId, SessionInfo sessionInfo) { | |
544 | - sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(new SessionCloseNotification(), sessionId), sessionInfo.getServer()); | |
510 | + private void notifyTransportAboutClosedSession(UUID sessionId, SessionInfoMetaData sessionMd) { | |
511 | + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | |
512 | + .setSessionIdMSB(sessionId.getMostSignificantBits()) | |
513 | + .setSessionIdLSB(sessionId.getLeastSignificantBits()) | |
514 | + .setSessionCloseNotification(SessionCloseNotificationProto.getDefaultInstance()).build(); | |
515 | + systemContext.getRuleEngineTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); | |
545 | 516 | } |
546 | 517 | |
547 | 518 | void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { |
... | ... | @@ -552,4 +523,178 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
552 | 523 | this.defaultMetaData.putValue("deviceType", deviceType); |
553 | 524 | } |
554 | 525 | |
526 | + private JsonObject getJsonObject(List<KeyValueProto> tsKv) { | |
527 | + JsonObject json = new JsonObject(); | |
528 | + for (KeyValueProto kv : tsKv) { | |
529 | + switch (kv.getType()) { | |
530 | + case BOOLEAN_V: | |
531 | + json.addProperty(kv.getKey(), kv.getBoolV()); | |
532 | + break; | |
533 | + case LONG_V: | |
534 | + json.addProperty(kv.getKey(), kv.getLongV()); | |
535 | + break; | |
536 | + case DOUBLE_V: | |
537 | + json.addProperty(kv.getKey(), kv.getDoubleV()); | |
538 | + break; | |
539 | + case STRING_V: | |
540 | + json.addProperty(kv.getKey(), kv.getStringV()); | |
541 | + break; | |
542 | + } | |
543 | + } | |
544 | + return json; | |
545 | + } | |
546 | + | |
547 | + private Optional<Set<String>> toOptionalSet(List<String> strings) { | |
548 | + if (strings == null || strings.isEmpty()) { | |
549 | + return Optional.empty(); | |
550 | + } else { | |
551 | + return Optional.of(new HashSet<>(strings)); | |
552 | + } | |
553 | + } | |
554 | + | |
555 | + private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { | |
556 | + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | |
557 | + .setSessionIdMSB(sessionInfo.getSessionIdMSB()) | |
558 | + .setSessionIdLSB(sessionInfo.getSessionIdLSB()) | |
559 | + .setGetAttributesResponse(responseMsg).build(); | |
560 | + systemContext.getRuleEngineTransportService().process(sessionInfo.getNodeId(), msg); | |
561 | + } | |
562 | + | |
563 | + private void sendToTransport(AttributeUpdateNotificationMsg notificationMsg, UUID sessionId, String nodeId) { | |
564 | + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | |
565 | + .setSessionIdMSB(sessionId.getMostSignificantBits()) | |
566 | + .setSessionIdLSB(sessionId.getLeastSignificantBits()) | |
567 | + .setAttributeUpdateNotification(notificationMsg).build(); | |
568 | + systemContext.getRuleEngineTransportService().process(nodeId, msg); | |
569 | + } | |
570 | + | |
571 | + private void sendToTransport(ToDeviceRpcRequestMsg rpcMsg, UUID sessionId, String nodeId) { | |
572 | + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | |
573 | + .setSessionIdMSB(sessionId.getMostSignificantBits()) | |
574 | + .setSessionIdLSB(sessionId.getLeastSignificantBits()) | |
575 | + .setToDeviceRequest(rpcMsg).build(); | |
576 | + systemContext.getRuleEngineTransportService().process(nodeId, msg); | |
577 | + } | |
578 | + | |
579 | + private void sendToTransport(TransportProtos.ToServerRpcResponseMsg rpcMsg, UUID sessionId, String nodeId) { | |
580 | + DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() | |
581 | + .setSessionIdMSB(sessionId.getMostSignificantBits()) | |
582 | + .setSessionIdLSB(sessionId.getLeastSignificantBits()) | |
583 | + .setToServerResponse(rpcMsg).build(); | |
584 | + systemContext.getRuleEngineTransportService().process(nodeId, msg); | |
585 | + } | |
586 | + | |
587 | + | |
588 | + private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) { | |
589 | + List<TsKvProto> clientAttributes; | |
590 | + if (result == null || result.isEmpty()) { | |
591 | + clientAttributes = Collections.emptyList(); | |
592 | + } else { | |
593 | + clientAttributes = new ArrayList<>(result.size()); | |
594 | + for (AttributeKvEntry attrEntry : result) { | |
595 | + clientAttributes.add(toTsKvProto(attrEntry)); | |
596 | + } | |
597 | + } | |
598 | + return clientAttributes; | |
599 | + } | |
600 | + | |
601 | + private TsKvProto toTsKvProto(AttributeKvEntry attrEntry) { | |
602 | + return TsKvProto.newBuilder().setTs(attrEntry.getLastUpdateTs()) | |
603 | + .setKv(toKeyValueProto(attrEntry)).build(); | |
604 | + } | |
605 | + | |
606 | + private KeyValueProto toKeyValueProto(KvEntry kvEntry) { | |
607 | + KeyValueProto.Builder builder = KeyValueProto.newBuilder(); | |
608 | + builder.setKey(kvEntry.getKey()); | |
609 | + switch (kvEntry.getDataType()) { | |
610 | + case BOOLEAN: | |
611 | + builder.setType(KeyValueType.BOOLEAN_V); | |
612 | + builder.setBoolV(kvEntry.getBooleanValue().get()); | |
613 | + break; | |
614 | + case DOUBLE: | |
615 | + builder.setType(KeyValueType.DOUBLE_V); | |
616 | + builder.setDoubleV(kvEntry.getDoubleValue().get()); | |
617 | + break; | |
618 | + case LONG: | |
619 | + builder.setType(KeyValueType.LONG_V); | |
620 | + builder.setLongV(kvEntry.getLongValue().get()); | |
621 | + break; | |
622 | + case STRING: | |
623 | + builder.setType(KeyValueType.STRING_V); | |
624 | + builder.setStringV(kvEntry.getStrValue().get()); | |
625 | + break; | |
626 | + } | |
627 | + return builder.build(); | |
628 | + } | |
629 | + | |
630 | + private void restoreSessions() { | |
631 | + log.debug("[{}] Restoring sessions from cache", deviceId); | |
632 | + TransportProtos.DeviceSessionsCacheEntry sessionsDump = systemContext.getDeviceSessionCacheService().get(deviceId); | |
633 | + if (sessionsDump.getSerializedSize() == 0) { | |
634 | + log.debug("[{}] No session information found", deviceId); | |
635 | + return; | |
636 | + } | |
637 | + for (TransportProtos.SessionSubscriptionInfoProto sessionSubscriptionInfoProto : sessionsDump.getSessionsList()) { | |
638 | + SessionInfoProto sessionInfoProto = sessionSubscriptionInfoProto.getSessionInfo(); | |
639 | + UUID sessionId = getSessionId(sessionInfoProto); | |
640 | + SessionInfo sessionInfo = new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfoProto.getNodeId()); | |
641 | + TransportProtos.SubscriptionInfoProto subInfo = sessionSubscriptionInfoProto.getSubscriptionInfo(); | |
642 | + SessionInfoMetaData sessionMD = new SessionInfoMetaData(sessionInfo, subInfo.getLastActivityTime()); | |
643 | + sessions.put(sessionId, sessionMD); | |
644 | + if (subInfo.getAttributeSubscription()) { | |
645 | + attributeSubscriptions.put(sessionId, sessionInfo); | |
646 | + sessionMD.setSubscribedToAttributes(true); | |
647 | + } | |
648 | + if (subInfo.getRpcSubscription()) { | |
649 | + rpcSubscriptions.put(sessionId, sessionInfo); | |
650 | + sessionMD.setSubscribedToRPC(true); | |
651 | + } | |
652 | + log.debug("[{}] Restored session: {}", deviceId, sessionMD); | |
653 | + } | |
654 | + log.debug("[{}] Restored sessions: {}, rpc subscriptions: {}, attribute subscriptions: {}", deviceId, sessions.size(), rpcSubscriptions.size(), attributeSubscriptions.size()); | |
655 | + } | |
656 | + | |
657 | + private void dumpSessions() { | |
658 | + log.debug("[{}] Dumping sessions: {}, rpc subscriptions: {}, attribute subscriptions: {} to cache", deviceId, sessions.size(), rpcSubscriptions.size(), attributeSubscriptions.size()); | |
659 | + List<TransportProtos.SessionSubscriptionInfoProto> sessionsList = new ArrayList<>(sessions.size()); | |
660 | + sessions.forEach((uuid, sessionMD) -> { | |
661 | + if (sessionMD.getSessionInfo().getType() == TransportProtos.SessionType.SYNC) { | |
662 | + return; | |
663 | + } | |
664 | + SessionInfo sessionInfo = sessionMD.getSessionInfo(); | |
665 | + TransportProtos.SubscriptionInfoProto subscriptionInfoProto = TransportProtos.SubscriptionInfoProto.newBuilder() | |
666 | + .setLastActivityTime(sessionMD.getLastActivityTime()) | |
667 | + .setAttributeSubscription(sessionMD.isSubscribedToAttributes()) | |
668 | + .setRpcSubscription(sessionMD.isSubscribedToRPC()).build(); | |
669 | + TransportProtos.SessionInfoProto sessionInfoProto = TransportProtos.SessionInfoProto.newBuilder() | |
670 | + .setSessionIdMSB(uuid.getMostSignificantBits()) | |
671 | + .setSessionIdLSB(uuid.getLeastSignificantBits()) | |
672 | + .setNodeId(sessionInfo.getNodeId()).build(); | |
673 | + sessionsList.add(TransportProtos.SessionSubscriptionInfoProto.newBuilder() | |
674 | + .setSessionInfo(sessionInfoProto) | |
675 | + .setSubscriptionInfo(subscriptionInfoProto).build()); | |
676 | + log.debug("[{}] Dumping session: {}", deviceId, sessionMD); | |
677 | + }); | |
678 | + systemContext.getDeviceSessionCacheService() | |
679 | + .put(deviceId, TransportProtos.DeviceSessionsCacheEntry.newBuilder() | |
680 | + .addAllSessions(sessionsList).build()); | |
681 | + } | |
682 | + | |
683 | + void initSessionTimeout(ActorContext context) { | |
684 | + schedulePeriodicMsgWithDelay(context, SessionTimeoutCheckMsg.instance(), systemContext.getSessionInactivityTimeout(), systemContext.getSessionInactivityTimeout()); | |
685 | + } | |
686 | + | |
687 | + void checkSessionsTimeout() { | |
688 | + long expTime = System.currentTimeMillis() - systemContext.getSessionInactivityTimeout(); | |
689 | + Map<UUID, SessionInfoMetaData> sessionsToRemove = sessions.entrySet().stream().filter(kv -> kv.getValue().getLastActivityTime() < expTime).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); | |
690 | + sessionsToRemove.forEach((sessionId, sessionMD) -> { | |
691 | + sessions.remove(sessionId); | |
692 | + rpcSubscriptions.remove(sessionId); | |
693 | + attributeSubscriptions.remove(sessionId); | |
694 | + notifyTransportAboutClosedSession(sessionId, sessionMD); | |
695 | + }); | |
696 | + if (!sessionsToRemove.isEmpty()) { | |
697 | + dumpSessions(); | |
698 | + } | |
699 | + } | |
555 | 700 | } | ... | ... |
... | ... | @@ -16,10 +16,7 @@ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
20 | -import org.thingsboard.server.common.msg.session.SessionType; | |
21 | - | |
22 | -import java.util.Optional; | |
19 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionType; | |
23 | 20 | |
24 | 21 | /** |
25 | 22 | * @author Andrew Shvayka |
... | ... | @@ -27,5 +24,6 @@ import java.util.Optional; |
27 | 24 | @Data |
28 | 25 | public class SessionInfo { |
29 | 26 | private final SessionType type; |
30 | - private final Optional<ServerAddress> server; | |
27 | + private final String nodeId; | |
28 | + private long lastActivityTime; | |
31 | 29 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/device/SessionInfoMetaData.java
renamed from
common/message/src/main/java/org/thingsboard/server/common/msg/core/ToDeviceRpcResponseMsg.java
... | ... | @@ -13,24 +13,27 @@ |
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.common.msg.core; | |
16 | +package org.thingsboard.server.actors.device; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | |
20 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | |
21 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | |
19 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionType; | |
22 | 20 | |
23 | 21 | /** |
24 | 22 | * @author Andrew Shvayka |
25 | 23 | */ |
26 | 24 | @Data |
27 | -public class ToDeviceRpcResponseMsg implements FromDeviceMsg { | |
25 | +class SessionInfoMetaData { | |
26 | + private final SessionInfo sessionInfo; | |
27 | + private long lastActivityTime; | |
28 | + private boolean subscribedToAttributes; | |
29 | + private boolean subscribedToRPC; | |
28 | 30 | |
29 | - private final int requestId; | |
30 | - private final String data; | |
31 | + SessionInfoMetaData(SessionInfo sessionInfo) { | |
32 | + this(sessionInfo, System.currentTimeMillis()); | |
33 | + } | |
31 | 34 | |
32 | - @Override | |
33 | - public SessionMsgType getMsgType() { | |
34 | - return SessionMsgType.TO_DEVICE_RPC_RESPONSE; | |
35 | + SessionInfoMetaData(SessionInfo sessionInfo, long lastActivityTime) { | |
36 | + this.sessionInfo = sessionInfo; | |
37 | + this.lastActivityTime = lastActivityTime; | |
35 | 38 | } |
36 | 39 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/device/SessionTimeoutCheckMsg.java
renamed from
application/src/main/java/org/thingsboard/server/actors/device/RuleEngineQueuePutAckMsg.java
... | ... | @@ -15,22 +15,25 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | -import lombok.Data; | |
19 | 18 | import org.thingsboard.server.common.msg.MsgType; |
20 | 19 | import org.thingsboard.server.common.msg.TbActorMsg; |
21 | 20 | |
22 | -import java.util.UUID; | |
23 | - | |
24 | 21 | /** |
25 | - * Created by ashvayka on 15.03.18. | |
22 | + * Created by ashvayka on 29.10.18. | |
26 | 23 | */ |
27 | -@Data | |
28 | -public final class RuleEngineQueuePutAckMsg implements TbActorMsg { | |
24 | +public class SessionTimeoutCheckMsg implements TbActorMsg { | |
25 | + | |
26 | + private static final SessionTimeoutCheckMsg INSTANCE = new SessionTimeoutCheckMsg(); | |
29 | 27 | |
30 | - private final UUID id; | |
28 | + private SessionTimeoutCheckMsg() { | |
29 | + } | |
30 | + | |
31 | + public static SessionTimeoutCheckMsg instance() { | |
32 | + return INSTANCE; | |
33 | + } | |
31 | 34 | |
32 | 35 | @Override |
33 | 36 | public MsgType getMsgType() { |
34 | - return MsgType.RULE_ENGINE_QUEUE_PUT_ACK_MSG; | |
37 | + return MsgType.SESSION_TIMEOUT_MSG; | |
35 | 38 | } |
36 | 39 | } | ... | ... |
... | ... | @@ -16,18 +16,16 @@ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.data.id.SessionId; | |
20 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
21 | -import org.thingsboard.server.common.msg.session.SessionType; | |
19 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
22 | 20 | |
23 | -import java.util.Optional; | |
21 | +import java.util.UUID; | |
24 | 22 | |
25 | 23 | /** |
26 | 24 | * @author Andrew Shvayka |
27 | 25 | */ |
28 | 26 | @Data |
29 | 27 | public class ToServerRpcRequestMetadata { |
30 | - private final SessionId sessionId; | |
31 | - private final SessionType type; | |
32 | - private final Optional<ServerAddress> server; | |
28 | + private final UUID sessionId; | |
29 | + private final TransportProtos.SessionType type; | |
30 | + private final String nodeId; | |
33 | 31 | } | ... | ... |
... | ... | @@ -32,7 +32,7 @@ public class BasicRpcSessionListener implements GrpcSessionListener { |
32 | 32 | private final ActorRef manager; |
33 | 33 | private final ActorRef self; |
34 | 34 | |
35 | - public BasicRpcSessionListener(ActorService service, ActorRef manager, ActorRef self) { | |
35 | + BasicRpcSessionListener(ActorService service, ActorRef manager, ActorRef self) { | |
36 | 36 | this.service = service; |
37 | 37 | this.manager = manager; |
38 | 38 | this.self = self; |
... | ... | @@ -40,7 +40,7 @@ public class BasicRpcSessionListener implements GrpcSessionListener { |
40 | 40 | |
41 | 41 | @Override |
42 | 42 | public void onConnected(GrpcSession session) { |
43 | - log.info("{} session started -> {}", getType(session), session.getRemoteServer()); | |
43 | + log.info("[{}][{}] session started", session.getRemoteServer(), getType(session)); | |
44 | 44 | if (!session.isClient()) { |
45 | 45 | manager.tell(new RpcSessionConnectedMsg(session.getRemoteServer(), session.getSessionId()), self); |
46 | 46 | } |
... | ... | @@ -48,21 +48,19 @@ public class BasicRpcSessionListener implements GrpcSessionListener { |
48 | 48 | |
49 | 49 | @Override |
50 | 50 | public void onDisconnected(GrpcSession session) { |
51 | - log.info("{} session closed -> {}", getType(session), session.getRemoteServer()); | |
51 | + log.info("[{}][{}] session closed", session.getRemoteServer(), getType(session)); | |
52 | 52 | manager.tell(new RpcSessionDisconnectedMsg(session.isClient(), session.getRemoteServer()), self); |
53 | 53 | } |
54 | 54 | |
55 | 55 | @Override |
56 | 56 | public void onReceiveClusterGrpcMsg(GrpcSession session, ClusterAPIProtos.ClusterMessage clusterMessage) { |
57 | - log.trace("{} Service [{}] received session actor msg {}", getType(session), | |
58 | - session.getRemoteServer(), | |
59 | - clusterMessage); | |
57 | + log.trace("Received session actor msg from [{}][{}]: {}", session.getRemoteServer(), getType(session), clusterMessage); | |
60 | 58 | service.onReceivedMsg(session.getRemoteServer(), clusterMessage); |
61 | 59 | } |
62 | 60 | |
63 | 61 | @Override |
64 | 62 | public void onError(GrpcSession session, Throwable t) { |
65 | - log.warn("{} session got error -> {}", getType(session), session.getRemoteServer(), t); | |
63 | + log.warn("[{}][{}] session got error -> {}", session.getRemoteServer(), getType(session), t); | |
66 | 64 | manager.tell(new RpcSessionClosedMsg(session.isClient(), session.getRemoteServer()), self); |
67 | 65 | session.close(); |
68 | 66 | } | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import akka.actor.ActorRef; |
19 | 19 | import akka.actor.Props; |
20 | 20 | import akka.event.Logging; |
21 | 21 | import akka.event.LoggingAdapter; |
22 | +import lombok.extern.slf4j.Slf4j; | |
22 | 23 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 24 | import org.thingsboard.server.actors.service.ContextAwareActor; |
24 | 25 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
... | ... | @@ -26,6 +27,7 @@ import org.thingsboard.server.actors.service.DefaultActorService; |
26 | 27 | import org.thingsboard.server.common.msg.TbActorMsg; |
27 | 28 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
28 | 29 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
30 | +import org.thingsboard.server.common.msg.cluster.ServerType; | |
29 | 31 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
30 | 32 | import org.thingsboard.server.service.cluster.discovery.ServerInstance; |
31 | 33 | |
... | ... | @@ -36,15 +38,13 @@ import java.util.*; |
36 | 38 | */ |
37 | 39 | public class RpcManagerActor extends ContextAwareActor { |
38 | 40 | |
39 | - private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); | |
40 | - | |
41 | 41 | private final Map<ServerAddress, SessionActorInfo> sessionActors; |
42 | 42 | |
43 | 43 | private final Map<ServerAddress, Queue<ClusterAPIProtos.ClusterMessage>> pendingMsgs; |
44 | 44 | |
45 | 45 | private final ServerAddress instance; |
46 | 46 | |
47 | - public RpcManagerActor(ActorSystemContext systemContext) { | |
47 | + private RpcManagerActor(ActorSystemContext systemContext) { | |
48 | 48 | super(systemContext); |
49 | 49 | this.sessionActors = new HashMap<>(); |
50 | 50 | this.pendingMsgs = new HashMap<>(); |
... | ... | @@ -54,7 +54,6 @@ public class RpcManagerActor extends ContextAwareActor { |
54 | 54 | .filter(otherServer -> otherServer.getServerAddress().compareTo(instance) > 0) |
55 | 55 | .forEach(otherServer -> onCreateSessionRequest( |
56 | 56 | new RpcSessionCreateRequestMsg(UUID.randomUUID(), otherServer.getServerAddress(), null))); |
57 | - | |
58 | 57 | } |
59 | 58 | |
60 | 59 | @Override |
... | ... | @@ -100,24 +99,23 @@ public class RpcManagerActor extends ContextAwareActor { |
100 | 99 | |
101 | 100 | private void onMsg(ClusterAPIProtos.ClusterMessage msg) { |
102 | 101 | if (msg.hasServerAddress()) { |
103 | - ServerAddress address = new ServerAddress(msg.getServerAddress().getHost(), | |
104 | - msg.getServerAddress().getPort()); | |
102 | + ServerAddress address = new ServerAddress(msg.getServerAddress().getHost(), msg.getServerAddress().getPort(), ServerType.CORE); | |
105 | 103 | SessionActorInfo session = sessionActors.get(address); |
106 | 104 | if (session != null) { |
107 | - log.debug("{} Forwarding msg to session actor", address); | |
105 | + log.debug("{} Forwarding msg to session actor: {}", address, msg); | |
108 | 106 | session.getActor().tell(msg, ActorRef.noSender()); |
109 | 107 | } else { |
110 | - log.debug("{} Storing msg to pending queue", address); | |
108 | + log.debug("{} Storing msg to pending queue: {}", address, msg); | |
111 | 109 | Queue<ClusterAPIProtos.ClusterMessage> queue = pendingMsgs.get(address); |
112 | 110 | if (queue == null) { |
113 | 111 | queue = new LinkedList<>(); |
114 | 112 | pendingMsgs.put(new ServerAddress( |
115 | - msg.getServerAddress().getHost(), msg.getServerAddress().getPort()), queue); | |
113 | + msg.getServerAddress().getHost(), msg.getServerAddress().getPort(), ServerType.CORE), queue); | |
116 | 114 | } |
117 | 115 | queue.add(msg); |
118 | 116 | } |
119 | 117 | } else { |
120 | - logger.warning("Cluster msg doesn't have set Server Address [{}]", msg); | |
118 | + log.warn("Cluster msg doesn't have server address [{}]", msg); | |
121 | 119 | } |
122 | 120 | } |
123 | 121 | |
... | ... | @@ -162,9 +160,9 @@ public class RpcManagerActor extends ContextAwareActor { |
162 | 160 | } |
163 | 161 | |
164 | 162 | private void onSessionClose(boolean reconnect, ServerAddress remoteAddress) { |
165 | - log.debug("[{}] session closed. Should reconnect: {}", remoteAddress, reconnect); | |
163 | + log.info("[{}] session closed. Should reconnect: {}", remoteAddress, reconnect); | |
166 | 164 | SessionActorInfo sessionRef = sessionActors.get(remoteAddress); |
167 | - if (context().sender() != null && context().sender().equals(sessionRef.actor)) { | |
165 | + if (sessionRef != null && context().sender() != null && context().sender().equals(sessionRef.actor)) { | |
168 | 166 | sessionActors.remove(remoteAddress); |
169 | 167 | pendingMsgs.remove(remoteAddress); |
170 | 168 | if (reconnect) { |
... | ... | @@ -182,18 +180,18 @@ public class RpcManagerActor extends ContextAwareActor { |
182 | 180 | |
183 | 181 | private void register(ServerAddress remoteAddress, UUID uuid, ActorRef sender) { |
184 | 182 | sessionActors.put(remoteAddress, new SessionActorInfo(uuid, sender)); |
185 | - log.debug("[{}][{}] Registering session actor.", remoteAddress, uuid); | |
183 | + log.info("[{}][{}] Registering session actor.", remoteAddress, uuid); | |
186 | 184 | Queue<ClusterAPIProtos.ClusterMessage> data = pendingMsgs.remove(remoteAddress); |
187 | 185 | if (data != null) { |
188 | - log.debug("[{}][{}] Forwarding {} pending messages.", remoteAddress, uuid, data.size()); | |
186 | + log.info("[{}][{}] Forwarding {} pending messages.", remoteAddress, uuid, data.size()); | |
189 | 187 | data.forEach(msg -> sender.tell(new RpcSessionTellMsg(msg), ActorRef.noSender())); |
190 | 188 | } else { |
191 | - log.debug("[{}][{}] No pending messages to forward.", remoteAddress, uuid); | |
189 | + log.info("[{}][{}] No pending messages to forward.", remoteAddress, uuid); | |
192 | 190 | } |
193 | 191 | } |
194 | 192 | |
195 | 193 | private ActorRef createSessionActor(RpcSessionCreateRequestMsg msg) { |
196 | - log.debug("[{}] Creating session actor.", msg.getMsgUid()); | |
194 | + log.info("[{}] Creating session actor.", msg.getMsgUid()); | |
197 | 195 | ActorRef actor = context().actorOf( |
198 | 196 | Props.create(new RpcSessionActor.ActorCreator(systemContext, msg.getMsgUid())).withDispatcher(DefaultActorService.RPC_DISPATCHER_NAME)); |
199 | 197 | actor.tell(msg, context().self()); |
... | ... | @@ -208,7 +206,7 @@ public class RpcManagerActor extends ContextAwareActor { |
208 | 206 | } |
209 | 207 | |
210 | 208 | @Override |
211 | - public RpcManagerActor create() throws Exception { | |
209 | + public RpcManagerActor create() { | |
212 | 210 | return new RpcManagerActor(context); |
213 | 211 | } |
214 | 212 | } | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.actors.rpc; |
18 | 18 | import akka.event.Logging; |
19 | 19 | import akka.event.LoggingAdapter; |
20 | 20 | import io.grpc.Channel; |
21 | +import io.grpc.ManagedChannel; | |
21 | 22 | import io.grpc.ManagedChannelBuilder; |
22 | 23 | import io.grpc.stub.StreamObserver; |
23 | 24 | import org.thingsboard.server.actors.ActorSystemContext; |
... | ... | @@ -88,8 +89,8 @@ public class RpcSessionActor extends ContextAwareActor { |
88 | 89 | systemContext.getRpcService().onSessionCreated(msg.getMsgUid(), session.getInputStream()); |
89 | 90 | } else { |
90 | 91 | // Client session |
91 | - Channel channel = ManagedChannelBuilder.forAddress(remoteServer.getHost(), remoteServer.getPort()).usePlaintext(true).build(); | |
92 | - session = new GrpcSession(remoteServer, listener); | |
92 | + ManagedChannel channel = ManagedChannelBuilder.forAddress(remoteServer.getHost(), remoteServer.getPort()).usePlaintext().build(); | |
93 | + session = new GrpcSession(remoteServer, listener, channel); | |
93 | 94 | session.initInputStream(); |
94 | 95 | |
95 | 96 | ClusterRpcServiceGrpc.ClusterRpcServiceStub stub = ClusterRpcServiceGrpc.newStub(channel); | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | 18 | import akka.actor.ActorRef; |
19 | 19 | import com.datastax.driver.core.utils.UUIDs; |
20 | +import org.springframework.util.StringUtils; | |
20 | 21 | import org.thingsboard.rule.engine.api.ListeningExecutor; |
21 | 22 | import org.thingsboard.rule.engine.api.MailService; |
22 | 23 | import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest; |
... | ... | @@ -35,12 +36,15 @@ import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; |
35 | 36 | import org.thingsboard.server.common.data.rule.RuleNode; |
36 | 37 | import org.thingsboard.server.common.msg.TbMsg; |
37 | 38 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
39 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
40 | +import org.thingsboard.server.common.msg.cluster.ServerType; | |
38 | 41 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
39 | 42 | import org.thingsboard.server.dao.alarm.AlarmService; |
40 | 43 | import org.thingsboard.server.dao.asset.AssetService; |
41 | 44 | import org.thingsboard.server.dao.attributes.AttributesService; |
42 | 45 | import org.thingsboard.server.dao.customer.CustomerService; |
43 | 46 | import org.thingsboard.server.dao.device.DeviceService; |
47 | +import org.thingsboard.server.dao.entityview.EntityViewService; | |
44 | 48 | import org.thingsboard.server.dao.relation.RelationService; |
45 | 49 | import org.thingsboard.server.dao.rule.RuleChainService; |
46 | 50 | import org.thingsboard.server.dao.tenant.TenantService; |
... | ... | @@ -154,7 +158,7 @@ class DefaultTbContext implements TbContext { |
154 | 158 | |
155 | 159 | @Override |
156 | 160 | public ScriptEngine createJsScriptEngine(String script, String... argNames) { |
157 | - return new RuleNodeJsScriptEngine(mainCtx.getJsSandbox(), script, argNames); | |
161 | + return new RuleNodeJsScriptEngine(mainCtx.getJsSandbox(), nodeCtx.getSelf().getId(), script, argNames); | |
158 | 162 | } |
159 | 163 | |
160 | 164 | @Override |
... | ... | @@ -213,6 +217,11 @@ class DefaultTbContext implements TbContext { |
213 | 217 | } |
214 | 218 | |
215 | 219 | @Override |
220 | + public EntityViewService getEntityViewService() { | |
221 | + return mainCtx.getEntityViewService(); | |
222 | + } | |
223 | + | |
224 | + @Override | |
216 | 225 | public MailService getMailService() { |
217 | 226 | if (mainCtx.isAllowSystemMailService()) { |
218 | 227 | return mainCtx.getMailService(); |
... | ... | @@ -226,16 +235,22 @@ class DefaultTbContext implements TbContext { |
226 | 235 | return new RuleEngineRpcService() { |
227 | 236 | @Override |
228 | 237 | public void sendRpcReply(DeviceId deviceId, int requestId, String body) { |
229 | - mainCtx.getDeviceRpcService().sendRpcReplyToDevice(nodeCtx.getTenantId(), deviceId, requestId, body); | |
238 | + mainCtx.getDeviceRpcService().sendReplyToRpcCallFromDevice(nodeCtx.getTenantId(), deviceId, requestId, body); | |
230 | 239 | } |
231 | 240 | |
232 | 241 | @Override |
233 | 242 | public void sendRpcRequest(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) { |
234 | 243 | ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), nodeCtx.getTenantId(), src.getDeviceId(), |
235 | 244 | src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody())); |
236 | - mainCtx.getDeviceRpcService().processRpcRequestToDevice(request, response -> { | |
245 | + mainCtx.getDeviceRpcService().forwardServerSideRPCRequestToDeviceActor(request, response -> { | |
237 | 246 | if (src.isRestApiCall()) { |
238 | - mainCtx.getDeviceRpcService().processRestAPIRpcResponseFromRuleEngine(response); | |
247 | + ServerAddress requestOriginAddress; | |
248 | + if (!StringUtils.isEmpty(src.getOriginHost())) { | |
249 | + requestOriginAddress = new ServerAddress(src.getOriginHost(), src.getOriginPort(), ServerType.CORE); | |
250 | + } else { | |
251 | + requestOriginAddress = mainCtx.getRoutingService().getCurrentServer(); | |
252 | + } | |
253 | + mainCtx.getDeviceRpcService().processResponseToServerSideRPCRequestFromRuleEngine(requestOriginAddress, response); | |
239 | 254 | } |
240 | 255 | consumer.accept(RuleEngineDeviceRpcResponse.builder() |
241 | 256 | .deviceId(src.getDeviceId()) | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | +import akka.actor.ActorInitializationException; | |
18 | 19 | import akka.actor.OneForOneStrategy; |
19 | 20 | import akka.actor.SupervisorStrategy; |
20 | 21 | import org.thingsboard.server.actors.ActorSystemContext; |
... | ... | @@ -33,7 +34,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe |
33 | 34 | private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) { |
34 | 35 | super(systemContext, tenantId, ruleChainId); |
35 | 36 | setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext, |
36 | - logger, context().parent(), context().self())); | |
37 | + context().parent(), context().self())); | |
37 | 38 | } |
38 | 39 | |
39 | 40 | @Override |
... | ... | @@ -79,7 +80,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe |
79 | 80 | } |
80 | 81 | |
81 | 82 | @Override |
82 | - public RuleChainActor create() throws Exception { | |
83 | + public RuleChainActor create() { | |
83 | 84 | return new RuleChainActor(context, tenantId, ruleChainId); |
84 | 85 | } |
85 | 86 | } | ... | ... |
... | ... | @@ -23,9 +23,9 @@ import com.datastax.driver.core.utils.UUIDs; |
23 | 23 | |
24 | 24 | import java.util.Optional; |
25 | 25 | |
26 | +import lombok.extern.slf4j.Slf4j; | |
26 | 27 | import org.thingsboard.server.actors.ActorSystemContext; |
27 | 28 | import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; |
28 | -import org.thingsboard.server.actors.device.RuleEngineQueuePutAckMsg; | |
29 | 29 | import org.thingsboard.server.actors.service.DefaultActorService; |
30 | 30 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
31 | 31 | import org.thingsboard.server.common.data.EntityType; |
... | ... | @@ -56,6 +56,7 @@ import java.util.stream.Collectors; |
56 | 56 | /** |
57 | 57 | * @author Andrew Shvayka |
58 | 58 | */ |
59 | +@Slf4j | |
59 | 60 | public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { |
60 | 61 | |
61 | 62 | private static final long DEFAULT_CLUSTER_PARTITION = 0L; |
... | ... | @@ -68,59 +69,58 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
68 | 69 | private RuleNodeId firstId; |
69 | 70 | private RuleNodeCtx firstNode; |
70 | 71 | private boolean started; |
72 | + private String ruleChainName; | |
71 | 73 | |
72 | 74 | RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext |
73 | - , LoggingAdapter logger, ActorRef parent, ActorRef self) { | |
74 | - super(systemContext, logger, tenantId, ruleChainId); | |
75 | + , ActorRef parent, ActorRef self) { | |
76 | + super(systemContext, tenantId, ruleChainId); | |
75 | 77 | this.parent = parent; |
76 | 78 | this.self = self; |
77 | 79 | this.nodeActors = new HashMap<>(); |
78 | 80 | this.nodeRoutes = new HashMap<>(); |
79 | 81 | this.service = systemContext.getRuleChainService(); |
82 | + this.ruleChainName = ruleChainId.toString(); | |
80 | 83 | } |
81 | 84 | |
82 | 85 | @Override |
83 | - public void start(ActorContext context) throws Exception { | |
86 | + public String getComponentName() { | |
87 | + return null; | |
88 | + } | |
89 | + | |
90 | + @Override | |
91 | + public void start(ActorContext context) { | |
84 | 92 | if (!started) { |
85 | 93 | RuleChain ruleChain = service.findRuleChainById(entityId); |
94 | + ruleChainName = ruleChain.getName(); | |
86 | 95 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId); |
96 | + log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | |
87 | 97 | // Creating and starting the actors; |
88 | 98 | for (RuleNode ruleNode : ruleNodeList) { |
99 | + log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | |
89 | 100 | ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); |
90 | 101 | nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); |
91 | 102 | } |
92 | 103 | initRoutes(ruleChain, ruleNodeList); |
93 | - reprocess(ruleNodeList); | |
94 | 104 | started = true; |
95 | 105 | } else { |
96 | 106 | onUpdate(context); |
97 | 107 | } |
98 | 108 | } |
99 | 109 | |
100 | - private void reprocess(List<RuleNode> ruleNodeList) { | |
101 | - for (RuleNode ruleNode : ruleNodeList) { | |
102 | - for (TbMsg tbMsg : queue.findUnprocessed(tenantId, ruleNode.getId().getId(), systemContext.getQueuePartitionId())) { | |
103 | - pushMsgToNode(nodeActors.get(ruleNode.getId()), tbMsg, ""); | |
104 | - } | |
105 | - } | |
106 | - if (firstNode != null) { | |
107 | - for (TbMsg tbMsg : queue.findUnprocessed(tenantId, entityId.getId(), systemContext.getQueuePartitionId())) { | |
108 | - pushMsgToNode(firstNode, tbMsg, ""); | |
109 | - } | |
110 | - } | |
111 | - } | |
112 | - | |
113 | 110 | @Override |
114 | - public void onUpdate(ActorContext context) throws Exception { | |
111 | + public void onUpdate(ActorContext context) { | |
115 | 112 | RuleChain ruleChain = service.findRuleChainById(entityId); |
113 | + ruleChainName = ruleChain.getName(); | |
116 | 114 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId); |
117 | - | |
115 | + log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | |
118 | 116 | for (RuleNode ruleNode : ruleNodeList) { |
119 | 117 | RuleNodeCtx existing = nodeActors.get(ruleNode.getId()); |
120 | 118 | if (existing == null) { |
119 | + log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | |
121 | 120 | ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); |
122 | 121 | nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); |
123 | 122 | } else { |
123 | + log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); | |
124 | 124 | existing.setSelf(ruleNode); |
125 | 125 | existing.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self); |
126 | 126 | } |
... | ... | @@ -129,16 +129,17 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
129 | 129 | Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet()); |
130 | 130 | List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList()); |
131 | 131 | removedRules.forEach(ruleNodeId -> { |
132 | + log.trace("[{}][{}] Removing rule node [{}]", tenantId, entityId, ruleNodeId); | |
132 | 133 | RuleNodeCtx removed = nodeActors.remove(ruleNodeId); |
133 | 134 | removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self); |
134 | 135 | }); |
135 | 136 | |
136 | 137 | initRoutes(ruleChain, ruleNodeList); |
137 | - reprocess(ruleNodeList); | |
138 | 138 | } |
139 | 139 | |
140 | 140 | @Override |
141 | - public void stop(ActorContext context) throws Exception { | |
141 | + public void stop(ActorContext context) { | |
142 | + log.trace("[{}][{}] Stopping rule chain with {} nodes", tenantId, entityId, nodeActors.size()); | |
142 | 143 | nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(context::stop); |
143 | 144 | nodeActors.clear(); |
144 | 145 | nodeRoutes.clear(); |
... | ... | @@ -147,7 +148,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
147 | 148 | } |
148 | 149 | |
149 | 150 | @Override |
150 | - public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | |
151 | + public void onClusterEventMsg(ClusterEventMsg msg) { | |
151 | 152 | |
152 | 153 | } |
153 | 154 | |
... | ... | @@ -164,10 +165,12 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
164 | 165 | // Populating the routes map; |
165 | 166 | for (RuleNode ruleNode : ruleNodeList) { |
166 | 167 | List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId()); |
168 | + log.trace("[{}][{}][{}] Processing rule node relations [{}]", tenantId, entityId, ruleNode.getId(), relations.size()); | |
167 | 169 | if (relations.size() == 0) { |
168 | 170 | nodeRoutes.put(ruleNode.getId(), Collections.emptyList()); |
169 | 171 | } else { |
170 | 172 | for (EntityRelation relation : relations) { |
173 | + log.trace("[{}][{}][{}] Processing rule node relation [{}]", tenantId, entityId, ruleNode.getId(), relation.getTo()); | |
171 | 174 | if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { |
172 | 175 | RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId())); |
173 | 176 | if (ruleNodeCtx == null) { |
... | ... | @@ -181,24 +184,23 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
181 | 184 | } |
182 | 185 | |
183 | 186 | firstId = ruleChain.getFirstRuleNodeId(); |
184 | - firstNode = nodeActors.get(ruleChain.getFirstRuleNodeId()); | |
187 | + firstNode = nodeActors.get(firstId); | |
185 | 188 | state = ComponentLifecycleState.ACTIVE; |
186 | 189 | } |
187 | 190 | |
188 | 191 | void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) { |
192 | + log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, envelope.getTbMsg().getId(), envelope.getTbMsg()); | |
189 | 193 | checkActive(); |
190 | 194 | if (firstNode != null) { |
191 | - putToQueue(enrichWithRuleChainId(envelope.getTbMsg()), msg -> pushMsgToNode(firstNode, msg, "")); | |
195 | + log.trace("[{}][{}] Pushing message to first rule node", entityId, firstId); | |
196 | + pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getTbMsg()), ""); | |
192 | 197 | } |
193 | 198 | } |
194 | 199 | |
195 | 200 | void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) { |
196 | 201 | checkActive(); |
197 | 202 | if (firstNode != null) { |
198 | - putToQueue(enrichWithRuleChainId(envelope.getTbMsg()), msg -> { | |
199 | - pushMsgToNode(firstNode, msg, ""); | |
200 | - envelope.getCallbackRef().tell(new RuleEngineQueuePutAckMsg(msg.getId()), self); | |
201 | - }); | |
203 | + pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getTbMsg()), ""); | |
202 | 204 | } |
203 | 205 | } |
204 | 206 | |
... | ... | @@ -206,15 +208,16 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
206 | 208 | checkActive(); |
207 | 209 | if (envelope.isEnqueue()) { |
208 | 210 | if (firstNode != null) { |
209 | - putToQueue(enrichWithRuleChainId(envelope.getMsg()), msg -> pushMsgToNode(firstNode, msg, envelope.getFromRelationType())); | |
211 | + pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getMsg()), envelope.getFromRelationType()); | |
210 | 212 | } |
211 | 213 | } else { |
212 | 214 | if (firstNode != null) { |
213 | 215 | pushMsgToNode(firstNode, envelope.getMsg(), envelope.getFromRelationType()); |
214 | 216 | } else { |
215 | - TbMsg msg = envelope.getMsg(); | |
216 | - EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId(); | |
217 | - queue.ack(tenantId, envelope.getMsg(), ackId.getId(), msg.getClusterPartition()); | |
217 | +// TODO: Ack this message in Kafka | |
218 | +// TbMsg msg = envelope.getMsg(); | |
219 | +// EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId(); | |
220 | +// queue.ack(tenantId, envelope.getMsg(), ackId.getId(), msg.getClusterPartition()); | |
218 | 221 | } |
219 | 222 | } |
220 | 223 | } |
... | ... | @@ -234,7 +237,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
234 | 237 | |
235 | 238 | private void onRemoteTellNext(ServerAddress serverAddress, RuleNodeToRuleChainTellNextMsg envelope) { |
236 | 239 | TbMsg msg = envelope.getMsg(); |
237 | - logger.debug("Forwarding [{}] msg to remote server [{}] due to changed originator id: [{}]", msg.getId(), serverAddress, msg.getOriginator()); | |
240 | + log.debug("Forwarding [{}] msg to remote server [{}] due to changed originator id: [{}]", msg.getId(), serverAddress, msg.getOriginator()); | |
238 | 241 | envelope = new RemoteToRuleChainTellNextMsg(envelope, tenantId, entityId); |
239 | 242 | systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(serverAddress, envelope)); |
240 | 243 | } |
... | ... | @@ -248,16 +251,20 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
248 | 251 | int relationsCount = relations.size(); |
249 | 252 | EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId(); |
250 | 253 | if (relationsCount == 0) { |
254 | + log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId()); | |
251 | 255 | if (ackId != null) { |
252 | - queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition()); | |
256 | +// TODO: Ack this message in Kafka | |
257 | +// queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition()); | |
253 | 258 | } |
254 | 259 | } else if (relationsCount == 1) { |
255 | 260 | for (RuleNodeRelation relation : relations) { |
261 | + log.trace("[{}][{}][{}] Pushing message to single target: [{}]", tenantId, entityId, msg.getId(), relation.getOut()); | |
256 | 262 | pushToTarget(msg, relation.getOut(), relation.getType()); |
257 | 263 | } |
258 | 264 | } else { |
259 | 265 | for (RuleNodeRelation relation : relations) { |
260 | 266 | EntityId target = relation.getOut(); |
267 | + log.trace("[{}][{}][{}] Pushing message to multiple targets: [{}]", tenantId, entityId, msg.getId(), relation.getOut()); | |
261 | 268 | switch (target.getEntityType()) { |
262 | 269 | case RULE_NODE: |
263 | 270 | enqueueAndForwardMsgCopyToNode(msg, target, relation.getType()); |
... | ... | @@ -269,7 +276,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
269 | 276 | } |
270 | 277 | //TODO: Ideally this should happen in async way when all targets confirm that the copied messages are successfully written to corresponding target queues. |
271 | 278 | if (ackId != null) { |
272 | - queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition()); | |
279 | +// TODO: Ack this message in Kafka | |
280 | +// queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition()); | |
273 | 281 | } |
274 | 282 | } |
275 | 283 | } |
... | ... | @@ -296,7 +304,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
296 | 304 | RuleNodeId targetId = new RuleNodeId(target.getId()); |
297 | 305 | RuleNodeCtx targetNodeCtx = nodeActors.get(targetId); |
298 | 306 | TbMsg copy = msg.copy(UUIDs.timeBased(), entityId, targetId, DEFAULT_CLUSTER_PARTITION); |
299 | - putToQueue(copy, queuedMsg -> pushMsgToNode(targetNodeCtx, queuedMsg, fromRelationType)); | |
307 | + pushMsgToNode(targetNodeCtx, copy, fromRelationType); | |
300 | 308 | } |
301 | 309 | |
302 | 310 | private void pushToTarget(TbMsg msg, EntityId target, String fromRelationType) { | ... | ... |
... | ... | @@ -32,7 +32,7 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa |
32 | 32 | super(systemContext, tenantId, ruleNodeId); |
33 | 33 | this.ruleChainId = ruleChainId; |
34 | 34 | setProcessor(new RuleNodeActorMessageProcessor(tenantId, ruleChainId, ruleNodeId, systemContext, |
35 | - logger, context().parent(), context().self())); | |
35 | + context().parent(), context().self())); | |
36 | 36 | } |
37 | 37 | |
38 | 38 | @Override |
... | ... | @@ -60,7 +60,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa |
60 | 60 | } |
61 | 61 | |
62 | 62 | private void onRuleNodeToSelfMsg(RuleNodeToSelfMsg msg) { |
63 | - logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg()); | |
63 | + if (log.isDebugEnabled()) { | |
64 | + log.debug("[{}][{}][{}] Going to process rule msg: {}", ruleChainId, id, processor.getComponentName(), msg.getMsg()); | |
65 | + } | |
64 | 66 | try { |
65 | 67 | processor.onRuleToSelfMsg(msg); |
66 | 68 | increaseMessagesProcessedCount(); |
... | ... | @@ -70,7 +72,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa |
70 | 72 | } |
71 | 73 | |
72 | 74 | private void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) { |
73 | - logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg()); | |
75 | + if (log.isDebugEnabled()) { | |
76 | + log.debug("[{}][{}][{}] Going to process rule msg: {}", ruleChainId, id, processor.getComponentName(), msg.getMsg()); | |
77 | + } | |
74 | 78 | try { |
75 | 79 | processor.onRuleChainToRuleNodeMsg(msg); |
76 | 80 | increaseMessagesProcessedCount(); | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
... | ... | @@ -44,8 +44,8 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
44 | 44 | private TbContext defaultCtx; |
45 | 45 | |
46 | 46 | RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext |
47 | - , LoggingAdapter logger, ActorRef parent, ActorRef self) { | |
48 | - super(systemContext, logger, tenantId, ruleNodeId); | |
47 | + , ActorRef parent, ActorRef self) { | |
48 | + super(systemContext, tenantId, ruleNodeId); | |
49 | 49 | this.parent = parent; |
50 | 50 | this.self = self; |
51 | 51 | this.service = systemContext.getRuleChainService(); |
... | ... | @@ -75,7 +75,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
75 | 75 | } |
76 | 76 | |
77 | 77 | @Override |
78 | - public void stop(ActorContext context) throws Exception { | |
78 | + public void stop(ActorContext context) { | |
79 | 79 | if (tbNode != null) { |
80 | 80 | tbNode.destroy(); |
81 | 81 | } |
... | ... | @@ -83,7 +83,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
83 | 83 | } |
84 | 84 | |
85 | 85 | @Override |
86 | - public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | |
86 | + public void onClusterEventMsg(ClusterEventMsg msg) { | |
87 | 87 | |
88 | 88 | } |
89 | 89 | |
... | ... | @@ -111,6 +111,11 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
111 | 111 | } |
112 | 112 | } |
113 | 113 | |
114 | + @Override | |
115 | + public String getComponentName() { | |
116 | + return ruleNode.getName(); | |
117 | + } | |
118 | + | |
114 | 119 | private TbNode initComponent(RuleNode ruleNode) throws Exception { |
115 | 120 | Class<?> componentClazz = Class.forName(ruleNode.getType()); |
116 | 121 | TbNode tbNode = (TbNode) (componentClazz.newInstance()); | ... | ... |
... | ... | @@ -35,5 +35,4 @@ public interface ActorService extends SessionMsgProcessor, RpcMsgListener, Disco |
35 | 35 | |
36 | 36 | void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType); |
37 | 37 | |
38 | - void onMsg(ServiceToRuleEngineMsg serviceToRuleEngineMsg); | |
39 | 38 | } | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.actors.service; |
18 | 18 | import akka.actor.ActorRef; |
19 | 19 | import akka.event.Logging; |
20 | 20 | import akka.event.LoggingAdapter; |
21 | +import lombok.extern.slf4j.Slf4j; | |
21 | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | 23 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
23 | 24 | import org.thingsboard.server.actors.stats.StatsPersistMsg; |
... | ... | @@ -32,8 +33,6 @@ import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
32 | 33 | */ |
33 | 34 | public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ContextAwareActor { |
34 | 35 | |
35 | - protected final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
36 | - | |
37 | 36 | private long lastPersistedErrorTs = 0L; |
38 | 37 | protected final TenantId tenantId; |
39 | 38 | protected final T id; |
... | ... | @@ -54,13 +53,14 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
54 | 53 | @Override |
55 | 54 | public void preStart() { |
56 | 55 | try { |
56 | + log.debug("[{}][{}][{}] Starting processor.", tenantId, id, id.getEntityType()); | |
57 | 57 | processor.start(context()); |
58 | 58 | logLifecycleEvent(ComponentLifecycleEvent.STARTED); |
59 | 59 | if (systemContext.isStatisticsEnabled()) { |
60 | 60 | scheduleStatsPersistTick(); |
61 | 61 | } |
62 | 62 | } catch (Exception e) { |
63 | - logger.warning("[{}][{}] Failed to start {} processor: {}", tenantId, id, id.getEntityType(), e); | |
63 | + log.warn("[{}][{}] Failed to start {} processor: {}", tenantId, id, id.getEntityType(), e); | |
64 | 64 | logAndPersist("OnStart", e, true); |
65 | 65 | logLifecycleEvent(ComponentLifecycleEvent.STARTED, e); |
66 | 66 | } |
... | ... | @@ -70,7 +70,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
70 | 70 | try { |
71 | 71 | processor.scheduleStatsPersistTick(context(), systemContext.getStatisticsPersistFrequency()); |
72 | 72 | } catch (Exception e) { |
73 | - logger.error("[{}][{}] Failed to schedule statistics store message. No statistics is going to be stored: {}", tenantId, id, e.getMessage()); | |
73 | + log.error("[{}][{}] Failed to schedule statistics store message. No statistics is going to be stored: {}", tenantId, id, e.getMessage()); | |
74 | 74 | logAndPersist("onScheduleStatsPersistMsg", e); |
75 | 75 | } |
76 | 76 | } |
... | ... | @@ -78,16 +78,18 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
78 | 78 | @Override |
79 | 79 | public void postStop() { |
80 | 80 | try { |
81 | + log.debug("[{}][{}] Stopping processor.", tenantId, id, id.getEntityType()); | |
81 | 82 | processor.stop(context()); |
82 | 83 | logLifecycleEvent(ComponentLifecycleEvent.STOPPED); |
83 | 84 | } catch (Exception e) { |
84 | - logger.warning("[{}][{}] Failed to stop {} processor: {}", tenantId, id, id.getEntityType(), e.getMessage()); | |
85 | + log.warn("[{}][{}] Failed to stop {} processor: {}", tenantId, id, id.getEntityType(), e.getMessage()); | |
85 | 86 | logAndPersist("OnStop", e, true); |
86 | 87 | logLifecycleEvent(ComponentLifecycleEvent.STOPPED, e); |
87 | 88 | } |
88 | 89 | } |
89 | 90 | |
90 | 91 | protected void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
92 | + log.debug("[{}][{}][{}] onComponentLifecycleMsg: [{}]", tenantId, id, id.getEntityType(), msg.getEvent()); | |
91 | 93 | try { |
92 | 94 | switch (msg.getEvent()) { |
93 | 95 | case CREATED: |
... | ... | @@ -148,9 +150,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
148 | 150 | private void logAndPersist(String method, Exception e, boolean critical) { |
149 | 151 | errorsOccurred++; |
150 | 152 | if (critical) { |
151 | - logger.warning("[{}][{}] Failed to process {} msg: {}", id, tenantId, method, e); | |
153 | + log.warn("[{}][{}][{}] Failed to process {} msg: {}", id, tenantId, processor.getComponentName(), method, e); | |
152 | 154 | } else { |
153 | - logger.debug("[{}][{}] Failed to process {} msg: {}", id, tenantId, method, e); | |
155 | + log.debug("[{}][{}][{}] Failed to process {} msg: {}", id, tenantId, processor.getComponentName(), method, e); | |
154 | 156 | } |
155 | 157 | long ts = System.currentTimeMillis(); |
156 | 158 | if (ts - lastPersistedErrorTs > getErrorPersistFrequency()) { | ... | ... |
... | ... | @@ -15,14 +15,17 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.service; |
17 | 17 | |
18 | +import akka.actor.Terminated; | |
18 | 19 | import akka.actor.UntypedActor; |
19 | -import akka.event.Logging; | |
20 | -import akka.event.LoggingAdapter; | |
20 | +import org.slf4j.Logger; | |
21 | +import org.slf4j.LoggerFactory; | |
21 | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | 23 | import org.thingsboard.server.common.msg.TbActorMsg; |
23 | 24 | |
25 | + | |
24 | 26 | public abstract class ContextAwareActor extends UntypedActor { |
25 | - protected final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
27 | + | |
28 | + protected final Logger log = LoggerFactory.getLogger(getClass()); | |
26 | 29 | |
27 | 30 | public static final int ENTITY_PACK_LIMIT = 1024; |
28 | 31 | |
... | ... | @@ -35,21 +38,26 @@ public abstract class ContextAwareActor extends UntypedActor { |
35 | 38 | |
36 | 39 | @Override |
37 | 40 | public void onReceive(Object msg) throws Exception { |
38 | - if (logger.isDebugEnabled()) { | |
39 | - logger.debug("Processing msg: {}", msg); | |
41 | + if (log.isDebugEnabled()) { | |
42 | + log.debug("Processing msg: {}", msg); | |
40 | 43 | } |
41 | 44 | if (msg instanceof TbActorMsg) { |
42 | 45 | try { |
43 | 46 | if (!process((TbActorMsg) msg)) { |
44 | - logger.warning("Unknown message: {}!", msg); | |
47 | + log.warn("Unknown message: {}!", msg); | |
45 | 48 | } |
46 | 49 | } catch (Exception e) { |
47 | 50 | throw e; |
48 | 51 | } |
52 | + } else if (msg instanceof Terminated) { | |
53 | + processTermination((Terminated) msg); | |
49 | 54 | } else { |
50 | - logger.warning("Unknown message: {}!", msg); | |
55 | + log.warn("Unknown message: {}!", msg); | |
51 | 56 | } |
52 | 57 | } |
53 | 58 | |
59 | + protected void processTermination(Terminated msg) { | |
60 | + } | |
61 | + | |
54 | 62 | protected abstract boolean process(TbActorMsg msg); |
55 | 63 | } | ... | ... |
... | ... | @@ -30,7 +30,6 @@ import org.thingsboard.server.actors.app.AppActor; |
30 | 30 | import org.thingsboard.server.actors.rpc.RpcBroadcastMsg; |
31 | 31 | import org.thingsboard.server.actors.rpc.RpcManagerActor; |
32 | 32 | import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; |
33 | -import org.thingsboard.server.actors.session.SessionManagerActor; | |
34 | 33 | import org.thingsboard.server.actors.stats.StatsActor; |
35 | 34 | import org.thingsboard.server.common.data.Device; |
36 | 35 | import org.thingsboard.server.common.data.id.DeviceId; |
... | ... | @@ -38,13 +37,11 @@ import org.thingsboard.server.common.data.id.EntityId; |
38 | 37 | import org.thingsboard.server.common.data.id.TenantId; |
39 | 38 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
40 | 39 | import org.thingsboard.server.common.msg.TbActorMsg; |
41 | -import org.thingsboard.server.common.msg.aware.SessionAwareMsg; | |
42 | 40 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
43 | 41 | import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; |
44 | 42 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
45 | 43 | import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
46 | 44 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
47 | -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
48 | 45 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
49 | 46 | import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
50 | 47 | import org.thingsboard.server.service.cluster.discovery.ServerInstance; |
... | ... | @@ -68,10 +65,7 @@ public class DefaultActorService implements ActorService { |
68 | 65 | public static final String APP_DISPATCHER_NAME = "app-dispatcher"; |
69 | 66 | public static final String CORE_DISPATCHER_NAME = "core-dispatcher"; |
70 | 67 | public static final String SYSTEM_RULE_DISPATCHER_NAME = "system-rule-dispatcher"; |
71 | - public static final String SYSTEM_PLUGIN_DISPATCHER_NAME = "system-plugin-dispatcher"; | |
72 | 68 | public static final String TENANT_RULE_DISPATCHER_NAME = "rule-dispatcher"; |
73 | - public static final String TENANT_PLUGIN_DISPATCHER_NAME = "plugin-dispatcher"; | |
74 | - public static final String SESSION_DISPATCHER_NAME = "session-dispatcher"; | |
75 | 69 | public static final String RPC_DISPATCHER_NAME = "rpc-dispatcher"; |
76 | 70 | |
77 | 71 | @Autowired |
... | ... | @@ -90,8 +84,6 @@ public class DefaultActorService implements ActorService { |
90 | 84 | |
91 | 85 | private ActorRef appActor; |
92 | 86 | |
93 | - private ActorRef sessionManagerActor; | |
94 | - | |
95 | 87 | private ActorRef rpcManagerActor; |
96 | 88 | |
97 | 89 | @PostConstruct |
... | ... | @@ -104,10 +96,6 @@ public class DefaultActorService implements ActorService { |
104 | 96 | appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor"); |
105 | 97 | actorContext.setAppActor(appActor); |
106 | 98 | |
107 | - sessionManagerActor = system.actorOf(Props.create(new SessionManagerActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), | |
108 | - "sessionManagerActor"); | |
109 | - actorContext.setSessionManagerActor(sessionManagerActor); | |
110 | - | |
111 | 99 | rpcManagerActor = system.actorOf(Props.create(new RpcManagerActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), |
112 | 100 | "rpcManagerActor"); |
113 | 101 | |
... | ... | @@ -115,8 +103,6 @@ public class DefaultActorService implements ActorService { |
115 | 103 | actorContext.setStatsActor(statsActor); |
116 | 104 | |
117 | 105 | rpcService.init(this); |
118 | - | |
119 | - discoveryService.addListener(this); | |
120 | 106 | log.info("Actor system initialized."); |
121 | 107 | } |
122 | 108 | |
... | ... | @@ -137,12 +123,6 @@ public class DefaultActorService implements ActorService { |
137 | 123 | } |
138 | 124 | |
139 | 125 | @Override |
140 | - public void process(SessionAwareMsg msg) { | |
141 | - log.debug("Processing session aware msg: {}", msg); | |
142 | - sessionManagerActor.tell(msg, ActorRef.noSender()); | |
143 | - } | |
144 | - | |
145 | - @Override | |
146 | 126 | public void onServerAdded(ServerInstance server) { |
147 | 127 | log.trace("Processing onServerAdded msg: {}", server); |
148 | 128 | broadcast(new ClusterEventMsg(server.getServerAddress(), true)); |
... | ... | @@ -178,11 +158,6 @@ public class DefaultActorService implements ActorService { |
178 | 158 | appActor.tell(new SendToClusterMsg(deviceId, msg), ActorRef.noSender()); |
179 | 159 | } |
180 | 160 | |
181 | - @Override | |
182 | - public void onMsg(ServiceToRuleEngineMsg msg) { | |
183 | - appActor.tell(msg, ActorRef.noSender()); | |
184 | - } | |
185 | - | |
186 | 161 | public void broadcast(ToAllNodesMsg msg) { |
187 | 162 | actorContext.getEncodingService().encode(msg); |
188 | 163 | rpcService.broadcast(new RpcBroadcastMsg(ClusterAPIProtos.ClusterMessage |
... | ... | @@ -196,16 +171,15 @@ public class DefaultActorService implements ActorService { |
196 | 171 | |
197 | 172 | private void broadcast(ClusterEventMsg msg) { |
198 | 173 | this.appActor.tell(msg, ActorRef.noSender()); |
199 | - this.sessionManagerActor.tell(msg, ActorRef.noSender()); | |
200 | 174 | this.rpcManagerActor.tell(msg, ActorRef.noSender()); |
201 | 175 | } |
202 | 176 | |
203 | 177 | @Override |
204 | 178 | public void onReceivedMsg(ServerAddress source, ClusterAPIProtos.ClusterMessage msg) { |
205 | - ServerAddress serverAddress = new ServerAddress(source.getHost(), source.getPort()); | |
206 | - log.info("Received msg [{}] from [{}]", msg.getMessageType().name(), serverAddress); | |
179 | + ServerAddress serverAddress = new ServerAddress(source.getHost(), source.getPort(), source.getServerType()); | |
207 | 180 | if (log.isDebugEnabled()) { |
208 | - log.info("MSG: ", msg); | |
181 | + log.info("Received msg [{}] from [{}]", msg.getMessageType().name(), serverAddress); | |
182 | + log.info("MSG: {}", msg); | |
209 | 183 | } |
210 | 184 | switch (msg.getMessageType()) { |
211 | 185 | case CLUSTER_ACTOR_MESSAGE: |
... | ... | @@ -239,7 +213,7 @@ public class DefaultActorService implements ActorService { |
239 | 213 | actorContext.getTsSubService().onRemoteTsUpdate(serverAddress, msg.getPayload().toByteArray()); |
240 | 214 | break; |
241 | 215 | case CLUSTER_RPC_FROM_DEVICE_RESPONSE_MESSAGE: |
242 | - actorContext.getDeviceRpcService().processRemoteResponseFromDevice(serverAddress, msg.getPayload().toByteArray()); | |
216 | + actorContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromRemoteServer(serverAddress, msg.getPayload().toByteArray()); | |
243 | 217 | break; |
244 | 218 | case CLUSTER_DEVICE_STATE_SERVICE_MESSAGE: |
245 | 219 | actorContext.getDeviceStateService().onRemoteMsg(serverAddress, msg.getPayload().toByteArray()); | ... | ... |
application/src/main/java/org/thingsboard/server/actors/session/ASyncMsgProcessor.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 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.session; | |
17 | - | |
18 | -import akka.actor.ActorContext; | |
19 | -import akka.event.LoggingAdapter; | |
20 | -import org.thingsboard.server.actors.ActorSystemContext; | |
21 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | |
22 | -import org.thingsboard.server.common.data.id.SessionId; | |
23 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
24 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
25 | -import org.thingsboard.server.common.msg.core.AttributesSubscribeMsg; | |
26 | -import org.thingsboard.server.common.msg.core.ResponseMsg; | |
27 | -import org.thingsboard.server.common.msg.core.RpcSubscribeMsg; | |
28 | -import org.thingsboard.server.common.msg.core.SessionCloseMsg; | |
29 | -import org.thingsboard.server.common.msg.core.SessionOpenMsg; | |
30 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
31 | -import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; | |
32 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | |
33 | -import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; | |
34 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | |
35 | -import org.thingsboard.server.common.msg.session.SessionType; | |
36 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | |
37 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | |
38 | -import org.thingsboard.server.common.msg.session.ex.SessionException; | |
39 | - | |
40 | -import java.util.HashMap; | |
41 | -import java.util.Map; | |
42 | -import java.util.Optional; | |
43 | - | |
44 | -class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { | |
45 | - | |
46 | - private boolean firstMsg = true; | |
47 | - private Map<Integer, DeviceToDeviceActorMsg> pendingMap = new HashMap<>(); | |
48 | - private Optional<ServerAddress> currentTargetServer; | |
49 | - private boolean subscribedToAttributeUpdates; | |
50 | - private boolean subscribedToRpcCommands; | |
51 | - | |
52 | - public ASyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { | |
53 | - super(ctx, logger, sessionId); | |
54 | - } | |
55 | - | |
56 | - @Override | |
57 | - protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { | |
58 | - updateSessionCtx(msg, SessionType.ASYNC); | |
59 | - DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg); | |
60 | - FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload(); | |
61 | - if (firstMsg) { | |
62 | - if (fromDeviceMsg.getMsgType() != SessionMsgType.SESSION_OPEN) { | |
63 | - toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); | |
64 | - } | |
65 | - firstMsg = false; | |
66 | - } | |
67 | - switch (fromDeviceMsg.getMsgType()) { | |
68 | - case POST_TELEMETRY_REQUEST: | |
69 | - case POST_ATTRIBUTES_REQUEST: | |
70 | - FromDeviceRequestMsg requestMsg = (FromDeviceRequestMsg) fromDeviceMsg; | |
71 | - if (requestMsg.getRequestId() >= 0) { | |
72 | - logger.debug("[{}] Pending request {} registered", requestMsg.getRequestId(), requestMsg.getMsgType()); | |
73 | - //TODO: handle duplicates. | |
74 | - pendingMap.put(requestMsg.getRequestId(), pendingMsg); | |
75 | - } | |
76 | - break; | |
77 | - case SUBSCRIBE_ATTRIBUTES_REQUEST: | |
78 | - subscribedToAttributeUpdates = true; | |
79 | - break; | |
80 | - case UNSUBSCRIBE_ATTRIBUTES_REQUEST: | |
81 | - subscribedToAttributeUpdates = false; | |
82 | - break; | |
83 | - case SUBSCRIBE_RPC_COMMANDS_REQUEST: | |
84 | - subscribedToRpcCommands = true; | |
85 | - break; | |
86 | - case UNSUBSCRIBE_RPC_COMMANDS_REQUEST: | |
87 | - subscribedToRpcCommands = false; | |
88 | - break; | |
89 | - default: | |
90 | - break; | |
91 | - } | |
92 | - currentTargetServer = forwardToAppActor(ctx, pendingMsg); | |
93 | - } | |
94 | - | |
95 | - @Override | |
96 | - public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { | |
97 | - try { | |
98 | - if (msg.getSessionMsgType() != SessionMsgType.SESSION_CLOSE) { | |
99 | - switch (msg.getSessionMsgType()) { | |
100 | - case STATUS_CODE_RESPONSE: | |
101 | - case GET_ATTRIBUTES_RESPONSE: | |
102 | - ResponseMsg responseMsg = (ResponseMsg) msg; | |
103 | - if (responseMsg.getRequestId() >= 0) { | |
104 | - logger.debug("[{}] Pending request processed: {}", responseMsg.getRequestId(), responseMsg); | |
105 | - pendingMap.remove(responseMsg.getRequestId()); | |
106 | - } | |
107 | - break; | |
108 | - default: | |
109 | - break; | |
110 | - } | |
111 | - sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); | |
112 | - } else { | |
113 | - sessionCtx.onMsg(org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg.onCredentialsRevoked(sessionCtx.getSessionId())); | |
114 | - } | |
115 | - } catch (SessionException e) { | |
116 | - logger.warning("Failed to push session response msg", e); | |
117 | - } | |
118 | - } | |
119 | - | |
120 | - @Override | |
121 | - public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { | |
122 | - // TODO Auto-generated method stub | |
123 | - } | |
124 | - | |
125 | - @Override | |
126 | - protected void cleanupSession(ActorContext ctx) { | |
127 | - toDeviceMsg(new SessionCloseMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); | |
128 | - } | |
129 | - | |
130 | - @Override | |
131 | - public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { | |
132 | - if (pendingMap.size() > 0 || subscribedToAttributeUpdates || subscribedToRpcCommands) { | |
133 | - Optional<ServerAddress> newTargetServer = systemContext.getRoutingService().resolveById(getDeviceId()); | |
134 | - if (!newTargetServer.equals(currentTargetServer)) { | |
135 | - firstMsg = true; | |
136 | - currentTargetServer = newTargetServer; | |
137 | - pendingMap.values().forEach(v -> { | |
138 | - forwardToAppActor(context, v, currentTargetServer); | |
139 | - if (currentTargetServer.isPresent()) { | |
140 | - logger.debug("[{}] Forwarded msg to new server: {}", sessionId, currentTargetServer.get()); | |
141 | - } else { | |
142 | - logger.debug("[{}] Forwarded msg to local server.", sessionId); | |
143 | - } | |
144 | - }); | |
145 | - if (subscribedToAttributeUpdates) { | |
146 | - toDeviceMsg(new AttributesSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); | |
147 | - logger.debug("[{}] Forwarded attributes subscription.", sessionId); | |
148 | - } | |
149 | - if (subscribedToRpcCommands) { | |
150 | - toDeviceMsg(new RpcSubscribeMsg()).ifPresent(m -> forwardToAppActor(context, m, currentTargetServer)); | |
151 | - logger.debug("[{}] Forwarded rpc commands subscription.", sessionId); | |
152 | - } | |
153 | - } | |
154 | - } | |
155 | - } | |
156 | -} |
application/src/main/java/org/thingsboard/server/actors/session/AbstractSessionActorMsgProcessor.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 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.session; | |
17 | - | |
18 | -import akka.actor.ActorContext; | |
19 | -import akka.actor.ActorRef; | |
20 | -import akka.event.LoggingAdapter; | |
21 | -import org.thingsboard.server.actors.ActorSystemContext; | |
22 | -import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; | |
23 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | |
24 | -import org.thingsboard.server.common.data.id.DeviceId; | |
25 | -import org.thingsboard.server.common.data.id.SessionId; | |
26 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
27 | -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | |
28 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
29 | -import org.thingsboard.server.common.msg.device.BasicDeviceToDeviceActorMsg; | |
30 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
31 | -import org.thingsboard.server.common.msg.session.AdaptorToSessionActorMsg; | |
32 | -import org.thingsboard.server.common.msg.session.FromDeviceMsg; | |
33 | -import org.thingsboard.server.common.msg.session.SessionContext; | |
34 | -import org.thingsboard.server.common.msg.session.SessionCtrlMsg; | |
35 | -import org.thingsboard.server.common.msg.session.SessionType; | |
36 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | |
37 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | |
38 | -import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; | |
39 | - | |
40 | -import java.util.Optional; | |
41 | - | |
42 | -abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgProcessor { | |
43 | - | |
44 | - protected final SessionId sessionId; | |
45 | - protected SessionContext sessionCtx; | |
46 | - protected DeviceToDeviceActorMsg deviceToDeviceActorMsgPrototype; | |
47 | - | |
48 | - protected AbstractSessionActorMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { | |
49 | - super(ctx, logger); | |
50 | - this.sessionId = sessionId; | |
51 | - } | |
52 | - | |
53 | - protected abstract void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg); | |
54 | - | |
55 | - protected abstract void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg); | |
56 | - | |
57 | - protected abstract void processToDeviceMsg(ActorContext context, ToDeviceMsg msg); | |
58 | - | |
59 | - public abstract void processClusterEvent(ActorContext context, ClusterEventMsg msg); | |
60 | - | |
61 | - protected void processSessionCtrlMsg(ActorContext ctx, SessionCtrlMsg msg) { | |
62 | - if (msg instanceof SessionCloseMsg) { | |
63 | - cleanupSession(ctx); | |
64 | - terminateSession(ctx, sessionId); | |
65 | - } | |
66 | - } | |
67 | - | |
68 | - protected void cleanupSession(ActorContext ctx) { | |
69 | - } | |
70 | - | |
71 | - protected void updateSessionCtx(TransportToDeviceSessionActorMsg msg, SessionType type) { | |
72 | - sessionCtx = msg.getSessionMsg().getSessionContext(); | |
73 | - deviceToDeviceActorMsgPrototype = new BasicDeviceToDeviceActorMsg(msg, type); | |
74 | - } | |
75 | - | |
76 | - protected DeviceToDeviceActorMsg toDeviceMsg(TransportToDeviceSessionActorMsg msg) { | |
77 | - AdaptorToSessionActorMsg adaptorMsg = msg.getSessionMsg(); | |
78 | - return new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, adaptorMsg.getMsg()); | |
79 | - } | |
80 | - | |
81 | - protected Optional<DeviceToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) { | |
82 | - if (deviceToDeviceActorMsgPrototype != null) { | |
83 | - return Optional.of(new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, msg)); | |
84 | - } else { | |
85 | - return Optional.empty(); | |
86 | - } | |
87 | - } | |
88 | - | |
89 | - protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward) { | |
90 | - Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); | |
91 | - forwardToAppActor(ctx, toForward, address); | |
92 | - return address; | |
93 | - } | |
94 | - | |
95 | - protected Optional<ServerAddress> forwardToAppActorIfAddressChanged(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) { | |
96 | - | |
97 | - Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); | |
98 | - if (!newAddress.equals(oldAddress)) { | |
99 | - getAppActor().tell(new SendToClusterMsg(toForward.getDeviceId(), toForward | |
100 | - .toOtherAddress(systemContext.getRoutingService().getCurrentServer())), ctx.self()); | |
101 | - } | |
102 | - return newAddress; | |
103 | - } | |
104 | - | |
105 | - protected void forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> address) { | |
106 | - if (address.isPresent()) { | |
107 | - systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(address.get(), | |
108 | - toForward.toOtherAddress(systemContext.getRoutingService().getCurrentServer()))); | |
109 | - } else { | |
110 | - getAppActor().tell(toForward, ctx.self()); | |
111 | - } | |
112 | - } | |
113 | - | |
114 | - public static void terminateSession(ActorContext ctx, SessionId sessionId) { | |
115 | - ctx.parent().tell(new SessionTerminationMsg(sessionId), ActorRef.noSender()); | |
116 | - ctx.stop(ctx.self()); | |
117 | - } | |
118 | - | |
119 | - public DeviceId getDeviceId() { | |
120 | - return deviceToDeviceActorMsgPrototype.getDeviceId(); | |
121 | - } | |
122 | -} |
application/src/main/java/org/thingsboard/server/actors/session/SessionActor.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 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.session; | |
17 | - | |
18 | -import akka.actor.OneForOneStrategy; | |
19 | -import akka.actor.SupervisorStrategy; | |
20 | -import akka.event.Logging; | |
21 | -import akka.event.LoggingAdapter; | |
22 | -import org.thingsboard.server.actors.ActorSystemContext; | |
23 | -import org.thingsboard.server.actors.service.ContextAwareActor; | |
24 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | |
25 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | |
26 | -import org.thingsboard.server.common.data.id.SessionId; | |
27 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
28 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
29 | -import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; | |
30 | -import org.thingsboard.server.common.msg.session.SessionCtrlMsg; | |
31 | -import org.thingsboard.server.common.msg.session.SessionMsg; | |
32 | -import org.thingsboard.server.common.msg.session.SessionType; | |
33 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | |
34 | -import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; | |
35 | -import scala.concurrent.duration.Duration; | |
36 | - | |
37 | -public class SessionActor extends ContextAwareActor { | |
38 | - | |
39 | - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
40 | - | |
41 | - private final SessionId sessionId; | |
42 | - private AbstractSessionActorMsgProcessor processor; | |
43 | - | |
44 | - private SessionActor(ActorSystemContext systemContext, SessionId sessionId) { | |
45 | - super(systemContext); | |
46 | - this.sessionId = sessionId; | |
47 | - } | |
48 | - | |
49 | - @Override | |
50 | - public SupervisorStrategy supervisorStrategy() { | |
51 | - return new OneForOneStrategy(-1, Duration.Inf(), | |
52 | - throwable -> { | |
53 | - logger.error(throwable, "Unknown session error"); | |
54 | - if (throwable instanceof Error) { | |
55 | - return OneForOneStrategy.escalate(); | |
56 | - } else { | |
57 | - return OneForOneStrategy.resume(); | |
58 | - } | |
59 | - }); | |
60 | - } | |
61 | - | |
62 | - @Override | |
63 | - protected boolean process(TbActorMsg msg) { | |
64 | - switch (msg.getMsgType()) { | |
65 | - case TRANSPORT_TO_DEVICE_SESSION_ACTOR_MSG: | |
66 | - processTransportToSessionMsg((TransportToDeviceSessionActorMsg) msg); | |
67 | - break; | |
68 | - case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG: | |
69 | - processActorsToSessionMsg((ActorSystemToDeviceSessionActorMsg) msg); | |
70 | - break; | |
71 | - case SESSION_TIMEOUT_MSG: | |
72 | - processTimeoutMsg((SessionTimeoutMsg) msg); | |
73 | - break; | |
74 | - case SESSION_CTRL_MSG: | |
75 | - processSessionCloseMsg((SessionCtrlMsg) msg); | |
76 | - break; | |
77 | - case CLUSTER_EVENT_MSG: | |
78 | - processClusterEvent((ClusterEventMsg) msg); | |
79 | - break; | |
80 | - default: return false; | |
81 | - } | |
82 | - return true; | |
83 | - } | |
84 | - | |
85 | - private void processClusterEvent(ClusterEventMsg msg) { | |
86 | - processor.processClusterEvent(context(), msg); | |
87 | - } | |
88 | - | |
89 | - private void processTransportToSessionMsg(TransportToDeviceSessionActorMsg msg) { | |
90 | - initProcessor(msg); | |
91 | - processor.processToDeviceActorMsg(context(), msg); | |
92 | - } | |
93 | - | |
94 | - private void processActorsToSessionMsg(ActorSystemToDeviceSessionActorMsg msg) { | |
95 | - processor.processToDeviceMsg(context(), msg.getMsg()); | |
96 | - } | |
97 | - | |
98 | - private void processTimeoutMsg(SessionTimeoutMsg msg) { | |
99 | - if (processor != null) { | |
100 | - processor.processTimeoutMsg(context(), msg); | |
101 | - } else { | |
102 | - logger.warning("[{}] Can't process timeout msg: {} without processor", sessionId, msg); | |
103 | - } | |
104 | - } | |
105 | - | |
106 | - private void processSessionCloseMsg(SessionCtrlMsg msg) { | |
107 | - if (processor != null) { | |
108 | - processor.processSessionCtrlMsg(context(), msg); | |
109 | - } else if (msg instanceof SessionCloseMsg) { | |
110 | - AbstractSessionActorMsgProcessor.terminateSession(context(), sessionId); | |
111 | - } else { | |
112 | - logger.warning("[{}] Can't process session ctrl msg: {} without processor", sessionId, msg); | |
113 | - } | |
114 | - } | |
115 | - | |
116 | - private void initProcessor(TransportToDeviceSessionActorMsg msg) { | |
117 | - if (processor == null) { | |
118 | - SessionMsg sessionMsg = (SessionMsg) msg.getSessionMsg(); | |
119 | - if (sessionMsg.getSessionContext().getSessionType() == SessionType.SYNC) { | |
120 | - processor = new SyncMsgProcessor(systemContext, logger, sessionId); | |
121 | - } else { | |
122 | - processor = new ASyncMsgProcessor(systemContext, logger, sessionId); | |
123 | - } | |
124 | - } | |
125 | - } | |
126 | - | |
127 | - public static class ActorCreator extends ContextBasedCreator<SessionActor> { | |
128 | - private static final long serialVersionUID = 1L; | |
129 | - | |
130 | - private final SessionId sessionId; | |
131 | - | |
132 | - public ActorCreator(ActorSystemContext context, SessionId sessionId) { | |
133 | - super(context); | |
134 | - this.sessionId = sessionId; | |
135 | - } | |
136 | - | |
137 | - @Override | |
138 | - public SessionActor create() throws Exception { | |
139 | - return new SessionActor(context, sessionId); | |
140 | - } | |
141 | - } | |
142 | - | |
143 | -} |
application/src/main/java/org/thingsboard/server/actors/session/SessionManagerActor.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 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.session; | |
17 | - | |
18 | -import akka.actor.ActorInitializationException; | |
19 | -import akka.actor.ActorRef; | |
20 | -import akka.actor.InvalidActorNameException; | |
21 | -import akka.actor.LocalActorRef; | |
22 | -import akka.actor.OneForOneStrategy; | |
23 | -import akka.actor.Props; | |
24 | -import akka.actor.SupervisorStrategy; | |
25 | -import akka.actor.Terminated; | |
26 | -import akka.event.Logging; | |
27 | -import akka.event.LoggingAdapter; | |
28 | -import akka.japi.Function; | |
29 | -import org.thingsboard.server.actors.ActorSystemContext; | |
30 | -import org.thingsboard.server.actors.service.ContextAwareActor; | |
31 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | |
32 | -import org.thingsboard.server.actors.service.DefaultActorService; | |
33 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | |
34 | -import org.thingsboard.server.common.data.id.SessionId; | |
35 | -import org.thingsboard.server.common.msg.TbActorMsg; | |
36 | -import org.thingsboard.server.common.msg.aware.SessionAwareMsg; | |
37 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
38 | -import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; | |
39 | -import org.thingsboard.server.common.msg.core.SessionCloseMsg; | |
40 | -import org.thingsboard.server.common.msg.session.SessionCtrlMsg; | |
41 | -import scala.concurrent.duration.Duration; | |
42 | - | |
43 | -import java.util.HashMap; | |
44 | -import java.util.Map; | |
45 | - | |
46 | -public class SessionManagerActor extends ContextAwareActor { | |
47 | - | |
48 | - private static final int INITIAL_SESSION_MAP_SIZE = 1024; | |
49 | - | |
50 | - private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); | |
51 | - | |
52 | - private final Map<String, ActorRef> sessionActors; | |
53 | - | |
54 | - SessionManagerActor(ActorSystemContext systemContext) { | |
55 | - super(systemContext); | |
56 | - this.sessionActors = new HashMap<>(INITIAL_SESSION_MAP_SIZE); | |
57 | - } | |
58 | - | |
59 | - @Override | |
60 | - public SupervisorStrategy supervisorStrategy() { | |
61 | - return strategy; | |
62 | - } | |
63 | - | |
64 | - @Override | |
65 | - protected boolean process(TbActorMsg msg) { | |
66 | - //TODO Move everything here, to work with TbActorMsg | |
67 | - return false; | |
68 | - } | |
69 | - | |
70 | - @Override | |
71 | - public void onReceive(Object msg) throws Exception { | |
72 | - if (msg instanceof SessionCtrlMsg) { | |
73 | - onSessionCtrlMsg((SessionCtrlMsg) msg); | |
74 | - } else if (msg instanceof SessionAwareMsg) { | |
75 | - forwardToSessionActor((SessionAwareMsg) msg); | |
76 | - } else if (msg instanceof SessionTerminationMsg) { | |
77 | - onSessionTermination((SessionTerminationMsg) msg); | |
78 | - } else if (msg instanceof Terminated) { | |
79 | - onTermination((Terminated) msg); | |
80 | - } else if (msg instanceof SessionTimeoutMsg) { | |
81 | - onSessionTimeout((SessionTimeoutMsg) msg); | |
82 | - } else if (msg instanceof ClusterEventMsg) { | |
83 | - broadcast(msg); | |
84 | - } | |
85 | - } | |
86 | - | |
87 | - private void broadcast(Object msg) { | |
88 | - sessionActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | |
89 | - } | |
90 | - | |
91 | - private void onSessionTimeout(SessionTimeoutMsg msg) { | |
92 | - String sessionIdStr = msg.getSessionId().toUidStr(); | |
93 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | |
94 | - if (sessionActor != null) { | |
95 | - sessionActor.tell(msg, ActorRef.noSender()); | |
96 | - } | |
97 | - } | |
98 | - | |
99 | - private void onSessionCtrlMsg(SessionCtrlMsg msg) { | |
100 | - String sessionIdStr = msg.getSessionId().toUidStr(); | |
101 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | |
102 | - if (sessionActor != null) { | |
103 | - sessionActor.tell(msg, ActorRef.noSender()); | |
104 | - } | |
105 | - } | |
106 | - | |
107 | - private void onSessionTermination(SessionTerminationMsg msg) { | |
108 | - String sessionIdStr = msg.getId().toUidStr(); | |
109 | - ActorRef sessionActor = sessionActors.remove(sessionIdStr); | |
110 | - if (sessionActor != null) { | |
111 | - log.debug("[{}] Removed session actor.", sessionIdStr); | |
112 | - //TODO: onSubscriptionUpdate device actor about session close; | |
113 | - } else { | |
114 | - log.debug("[{}] Session actor was already removed.", sessionIdStr); | |
115 | - } | |
116 | - } | |
117 | - | |
118 | - private void forwardToSessionActor(SessionAwareMsg msg) { | |
119 | - if (msg instanceof ActorSystemToDeviceSessionActorMsg || msg instanceof SessionCloseMsg) { | |
120 | - String sessionIdStr = msg.getSessionId().toUidStr(); | |
121 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | |
122 | - if (sessionActor != null) { | |
123 | - sessionActor.tell(msg, ActorRef.noSender()); | |
124 | - } else { | |
125 | - log.debug("[{}] Session actor was already removed.", sessionIdStr); | |
126 | - } | |
127 | - } else { | |
128 | - try { | |
129 | - getOrCreateSessionActor(msg.getSessionId()).tell(msg, self()); | |
130 | - } catch (InvalidActorNameException e) { | |
131 | - log.info("Invalid msg : {}", msg); | |
132 | - } | |
133 | - } | |
134 | - } | |
135 | - | |
136 | - private ActorRef getOrCreateSessionActor(SessionId sessionId) { | |
137 | - String sessionIdStr = sessionId.toUidStr(); | |
138 | - ActorRef sessionActor = sessionActors.get(sessionIdStr); | |
139 | - if (sessionActor == null) { | |
140 | - log.debug("[{}] Creating session actor.", sessionIdStr); | |
141 | - sessionActor = context().actorOf( | |
142 | - Props.create(new SessionActor.ActorCreator(systemContext, sessionId)).withDispatcher(DefaultActorService.SESSION_DISPATCHER_NAME), | |
143 | - sessionIdStr); | |
144 | - sessionActors.put(sessionIdStr, sessionActor); | |
145 | - log.debug("[{}] Created session actor.", sessionIdStr); | |
146 | - } | |
147 | - return sessionActor; | |
148 | - } | |
149 | - | |
150 | - private void onTermination(Terminated message) { | |
151 | - ActorRef terminated = message.actor(); | |
152 | - if (terminated instanceof LocalActorRef) { | |
153 | - log.info("Removed actor: {}.", terminated); | |
154 | - //TODO: cleanup session actors map | |
155 | - } else { | |
156 | - throw new IllegalStateException("Remote actors are not supported!"); | |
157 | - } | |
158 | - } | |
159 | - | |
160 | - public static class ActorCreator extends ContextBasedCreator<SessionManagerActor> { | |
161 | - private static final long serialVersionUID = 1L; | |
162 | - | |
163 | - public ActorCreator(ActorSystemContext context) { | |
164 | - super(context); | |
165 | - } | |
166 | - | |
167 | - @Override | |
168 | - public SessionManagerActor create() throws Exception { | |
169 | - return new SessionManagerActor(context); | |
170 | - } | |
171 | - } | |
172 | - | |
173 | - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() { | |
174 | - @Override | |
175 | - public SupervisorStrategy.Directive apply(Throwable t) { | |
176 | - logger.error(t, "Unknown failure"); | |
177 | - return SupervisorStrategy.stop(); | |
178 | - } | |
179 | - }); | |
180 | -} |
application/src/main/java/org/thingsboard/server/actors/session/SyncMsgProcessor.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 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.session; | |
17 | - | |
18 | -import akka.actor.ActorContext; | |
19 | -import akka.event.LoggingAdapter; | |
20 | -import org.thingsboard.server.actors.ActorSystemContext; | |
21 | -import org.thingsboard.server.actors.shared.SessionTimeoutMsg; | |
22 | -import org.thingsboard.server.common.data.id.SessionId; | |
23 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
24 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
25 | -import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
26 | -import org.thingsboard.server.common.msg.session.BasicSessionActorToAdaptorMsg; | |
27 | -import org.thingsboard.server.common.msg.session.SessionContext; | |
28 | -import org.thingsboard.server.common.msg.session.SessionType; | |
29 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | |
30 | -import org.thingsboard.server.common.msg.session.TransportToDeviceSessionActorMsg; | |
31 | -import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; | |
32 | -import org.thingsboard.server.common.msg.session.ex.SessionException; | |
33 | - | |
34 | -import java.util.Optional; | |
35 | - | |
36 | -class SyncMsgProcessor extends AbstractSessionActorMsgProcessor { | |
37 | - private DeviceToDeviceActorMsg pendingMsg; | |
38 | - private Optional<ServerAddress> currentTargetServer; | |
39 | - private boolean pendingResponse; | |
40 | - | |
41 | - public SyncMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { | |
42 | - super(ctx, logger, sessionId); | |
43 | - } | |
44 | - | |
45 | - @Override | |
46 | - protected void processToDeviceActorMsg(ActorContext ctx, TransportToDeviceSessionActorMsg msg) { | |
47 | - updateSessionCtx(msg, SessionType.SYNC); | |
48 | - pendingMsg = toDeviceMsg(msg); | |
49 | - pendingResponse = true; | |
50 | - currentTargetServer = forwardToAppActor(ctx, pendingMsg); | |
51 | - scheduleMsgWithDelay(ctx, new SessionTimeoutMsg(sessionId), getTimeout(systemContext, msg.getSessionMsg().getSessionContext()), ctx.parent()); | |
52 | - } | |
53 | - | |
54 | - public void processTimeoutMsg(ActorContext context, SessionTimeoutMsg msg) { | |
55 | - if (pendingResponse) { | |
56 | - try { | |
57 | - sessionCtx.onMsg(SessionCloseMsg.onTimeout(sessionId)); | |
58 | - } catch (SessionException e) { | |
59 | - logger.warning("Failed to push session close msg", e); | |
60 | - } | |
61 | - terminateSession(context, this.sessionId); | |
62 | - } | |
63 | - } | |
64 | - | |
65 | - public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { | |
66 | - try { | |
67 | - sessionCtx.onMsg(new BasicSessionActorToAdaptorMsg(this.sessionCtx, msg)); | |
68 | - pendingResponse = false; | |
69 | - } catch (SessionException e) { | |
70 | - logger.warning("Failed to push session response msg", e); | |
71 | - } | |
72 | - terminateSession(context, this.sessionId); | |
73 | - } | |
74 | - | |
75 | - @Override | |
76 | - public void processClusterEvent(ActorContext context, ClusterEventMsg msg) { | |
77 | - if (pendingResponse) { | |
78 | - Optional<ServerAddress> newTargetServer = forwardToAppActorIfAddressChanged(context, pendingMsg, currentTargetServer); | |
79 | - if (logger.isDebugEnabled()) { | |
80 | - if (!newTargetServer.equals(currentTargetServer)) { | |
81 | - if (newTargetServer.isPresent()) { | |
82 | - logger.debug("[{}] Forwarded msg to new server: {}", sessionId, newTargetServer.get()); | |
83 | - } else { | |
84 | - logger.debug("[{}] Forwarded msg to local server.", sessionId); | |
85 | - } | |
86 | - } | |
87 | - } | |
88 | - currentTargetServer = newTargetServer; | |
89 | - } | |
90 | - } | |
91 | - | |
92 | - private long getTimeout(ActorSystemContext ctx, SessionContext sessionCtx) { | |
93 | - return sessionCtx.getTimeout() > 0 ? sessionCtx.getTimeout() : ctx.getSyncSessionTimeout(); | |
94 | - } | |
95 | -} |
application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java
... | ... | @@ -22,61 +22,49 @@ import akka.event.LoggingAdapter; |
22 | 22 | import com.fasterxml.jackson.databind.ObjectMapper; |
23 | 23 | import lombok.AllArgsConstructor; |
24 | 24 | import lombok.Data; |
25 | +import lombok.extern.slf4j.Slf4j; | |
25 | 26 | import org.thingsboard.server.actors.ActorSystemContext; |
26 | 27 | import scala.concurrent.ExecutionContextExecutor; |
27 | 28 | import scala.concurrent.duration.Duration; |
28 | 29 | |
29 | 30 | import java.util.concurrent.TimeUnit; |
30 | 31 | |
32 | +@Slf4j | |
31 | 33 | public abstract class AbstractContextAwareMsgProcessor { |
32 | 34 | |
33 | 35 | protected final ActorSystemContext systemContext; |
34 | - protected final LoggingAdapter logger; | |
35 | 36 | protected final ObjectMapper mapper = new ObjectMapper(); |
36 | 37 | |
37 | - protected AbstractContextAwareMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger) { | |
38 | + protected AbstractContextAwareMsgProcessor(ActorSystemContext systemContext) { | |
38 | 39 | super(); |
39 | 40 | this.systemContext = systemContext; |
40 | - this.logger = logger; | |
41 | 41 | } |
42 | 42 | |
43 | - protected ActorRef getAppActor() { | |
44 | - return systemContext.getAppActor(); | |
45 | - } | |
46 | - | |
47 | - protected Scheduler getScheduler() { | |
43 | + private Scheduler getScheduler() { | |
48 | 44 | return systemContext.getScheduler(); |
49 | 45 | } |
50 | 46 | |
51 | - protected ExecutionContextExecutor getSystemDispatcher() { | |
47 | + private ExecutionContextExecutor getSystemDispatcher() { | |
52 | 48 | return systemContext.getActorSystem().dispatcher(); |
53 | 49 | } |
54 | 50 | |
55 | 51 | protected void schedulePeriodicMsgWithDelay(ActorContext ctx, Object msg, long delayInMs, long periodInMs) { |
56 | - schedulePeriodicMsgWithDelay(ctx, msg, delayInMs, periodInMs, ctx.self()); | |
52 | + schedulePeriodicMsgWithDelay(msg, delayInMs, periodInMs, ctx.self()); | |
57 | 53 | } |
58 | 54 | |
59 | - protected void schedulePeriodicMsgWithDelay(ActorContext ctx, Object msg, long delayInMs, long periodInMs, ActorRef target) { | |
60 | - logger.debug("Scheduling periodic msg {} every {} ms with delay {} ms", msg, periodInMs, delayInMs); | |
55 | + private void schedulePeriodicMsgWithDelay(Object msg, long delayInMs, long periodInMs, ActorRef target) { | |
56 | + log.debug("Scheduling periodic msg {} every {} ms with delay {} ms", msg, periodInMs, delayInMs); | |
61 | 57 | getScheduler().schedule(Duration.create(delayInMs, TimeUnit.MILLISECONDS), Duration.create(periodInMs, TimeUnit.MILLISECONDS), target, msg, getSystemDispatcher(), null); |
62 | 58 | } |
63 | 59 | |
64 | - | |
65 | 60 | protected void scheduleMsgWithDelay(ActorContext ctx, Object msg, long delayInMs) { |
66 | - scheduleMsgWithDelay(ctx, msg, delayInMs, ctx.self()); | |
61 | + scheduleMsgWithDelay(msg, delayInMs, ctx.self()); | |
67 | 62 | } |
68 | 63 | |
69 | - protected void scheduleMsgWithDelay(ActorContext ctx, Object msg, long delayInMs, ActorRef target) { | |
70 | - logger.debug("Scheduling msg {} with delay {} ms", msg, delayInMs); | |
64 | + private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) { | |
65 | + log.debug("Scheduling msg {} with delay {} ms", msg, delayInMs); | |
71 | 66 | getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, getSystemDispatcher(), null); |
72 | 67 | } |
73 | 68 | |
74 | - @Data | |
75 | - @AllArgsConstructor | |
76 | - private static class ComponentConfiguration { | |
77 | - private final String clazz; | |
78 | - private final String name; | |
79 | - private final String configuration; | |
80 | - } | |
81 | 69 | |
82 | 70 | } | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import akka.actor.ActorContext; |
19 | 19 | import akka.event.LoggingAdapter; |
20 | 20 | import com.google.common.util.concurrent.FutureCallback; |
21 | 21 | import com.google.common.util.concurrent.Futures; |
22 | +import lombok.extern.slf4j.Slf4j; | |
22 | 23 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 24 | import org.thingsboard.server.actors.stats.StatsPersistTick; |
24 | 25 | import org.thingsboard.server.common.data.id.EntityId; |
... | ... | @@ -26,25 +27,25 @@ import org.thingsboard.server.common.data.id.TenantId; |
26 | 27 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
27 | 28 | import org.thingsboard.server.common.msg.TbMsg; |
28 | 29 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
29 | -import org.thingsboard.server.service.queue.MsgQueueService; | |
30 | 30 | |
31 | 31 | import javax.annotation.Nullable; |
32 | 32 | import java.util.function.Consumer; |
33 | 33 | |
34 | +@Slf4j | |
34 | 35 | public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor { |
35 | 36 | |
36 | 37 | protected final TenantId tenantId; |
37 | 38 | protected final T entityId; |
38 | - protected final MsgQueueService queue; | |
39 | 39 | protected ComponentLifecycleState state; |
40 | 40 | |
41 | - protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) { | |
42 | - super(systemContext, logger); | |
41 | + protected ComponentMsgProcessor(ActorSystemContext systemContext, TenantId tenantId, T id) { | |
42 | + super(systemContext); | |
43 | 43 | this.tenantId = tenantId; |
44 | 44 | this.entityId = id; |
45 | - this.queue = systemContext.getMsgQueueService(); | |
46 | 45 | } |
47 | 46 | |
47 | + public abstract String getComponentName(); | |
48 | + | |
48 | 49 | public abstract void start(ActorContext context) throws Exception; |
49 | 50 | |
50 | 51 | public abstract void stop(ActorContext context) throws Exception; |
... | ... | @@ -82,22 +83,9 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract |
82 | 83 | |
83 | 84 | protected void checkActive() { |
84 | 85 | if (state != ComponentLifecycleState.ACTIVE) { |
85 | - throw new IllegalStateException("Rule chain is not active!"); | |
86 | + log.warn("Rule chain is not active. Current state [{}] for processor [{}] tenant [{}]", state, tenantId, entityId); | |
87 | + throw new IllegalStateException("Rule chain is not active! " + entityId + " - " + tenantId); | |
86 | 88 | } |
87 | 89 | } |
88 | 90 | |
89 | - protected void putToQueue(final TbMsg tbMsg, final Consumer<TbMsg> onSuccess) { | |
90 | - EntityId entityId = tbMsg.getRuleNodeId() != null ? tbMsg.getRuleNodeId() : tbMsg.getRuleChainId(); | |
91 | - Futures.addCallback(queue.put(this.tenantId, tbMsg, entityId.getId(), tbMsg.getClusterPartition()), new FutureCallback<Void>() { | |
92 | - @Override | |
93 | - public void onSuccess(@Nullable Void result) { | |
94 | - onSuccess.accept(tbMsg); | |
95 | - } | |
96 | - | |
97 | - @Override | |
98 | - public void onFailure(Throwable t) { | |
99 | - logger.debug("Failed to push message [{}] to queue due to [{}]", tbMsg, t); | |
100 | - } | |
101 | - }); | |
102 | - } | |
103 | 91 | } | ... | ... |
... | ... | @@ -20,6 +20,8 @@ import akka.actor.ActorRef; |
20 | 20 | import akka.actor.Props; |
21 | 21 | import akka.actor.UntypedActor; |
22 | 22 | import akka.japi.Creator; |
23 | +import com.google.common.collect.BiMap; | |
24 | +import com.google.common.collect.HashBiMap; | |
23 | 25 | import lombok.extern.slf4j.Slf4j; |
24 | 26 | import org.thingsboard.server.actors.ActorSystemContext; |
25 | 27 | import org.thingsboard.server.actors.service.ContextAwareActor; |
... | ... | @@ -39,11 +41,11 @@ import java.util.Map; |
39 | 41 | public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> { |
40 | 42 | |
41 | 43 | protected final ActorSystemContext systemContext; |
42 | - protected final Map<T, ActorRef> actors; | |
44 | + protected final BiMap<T, ActorRef> actors; | |
43 | 45 | |
44 | 46 | public EntityActorsManager(ActorSystemContext systemContext) { |
45 | 47 | this.systemContext = systemContext; |
46 | - this.actors = new HashMap<>(); | |
48 | + this.actors = HashBiMap.create(); | |
47 | 49 | } |
48 | 50 | |
49 | 51 | protected abstract TenantId getTenantId(); |
... | ... | @@ -65,7 +67,8 @@ public abstract class EntityActorsManager<T extends EntityId, A extends UntypedA |
65 | 67 | } |
66 | 68 | } |
67 | 69 | |
68 | - public void visit(M entity, ActorRef actorRef) {} | |
70 | + public void visit(M entity, ActorRef actorRef) { | |
71 | + } | |
69 | 72 | |
70 | 73 | public ActorRef getOrCreateActor(ActorContext context, T entityId) { |
71 | 74 | return actors.computeIfAbsent(entityId, eId -> | ... | ... |
... | ... | @@ -50,7 +50,7 @@ public abstract class RuleChainManager extends EntityActorsManager<RuleChainId, |
50 | 50 | |
51 | 51 | @Override |
52 | 52 | public void visit(RuleChain entity, ActorRef actorRef) { |
53 | - if (entity.isRoot()) { | |
53 | + if (entity != null && entity.isRoot()) { | |
54 | 54 | rootChain = entity; |
55 | 55 | rootChainActor = actorRef; |
56 | 56 | } | ... | ... |
... | ... | @@ -15,10 +15,9 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.stats; |
17 | 17 | |
18 | -import akka.event.Logging; | |
19 | -import akka.event.LoggingAdapter; | |
20 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
21 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | +import lombok.extern.slf4j.Slf4j; | |
22 | 21 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 22 | import org.thingsboard.server.actors.service.ContextAwareActor; |
24 | 23 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
... | ... | @@ -27,9 +26,9 @@ import org.thingsboard.server.common.data.Event; |
27 | 26 | import org.thingsboard.server.common.msg.TbActorMsg; |
28 | 27 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
29 | 28 | |
29 | +@Slf4j | |
30 | 30 | public class StatsActor extends ContextAwareActor { |
31 | 31 | |
32 | - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
33 | 32 | private final ObjectMapper mapper = new ObjectMapper(); |
34 | 33 | |
35 | 34 | public StatsActor(ActorSystemContext context) { |
... | ... | @@ -43,13 +42,13 @@ public class StatsActor extends ContextAwareActor { |
43 | 42 | } |
44 | 43 | |
45 | 44 | @Override |
46 | - public void onReceive(Object msg) throws Exception { | |
47 | - logger.debug("Received message: {}", msg); | |
45 | + public void onReceive(Object msg) { | |
46 | + log.debug("Received message: {}", msg); | |
48 | 47 | if (msg instanceof StatsPersistMsg) { |
49 | 48 | try { |
50 | 49 | onStatsPersistMsg((StatsPersistMsg) msg); |
51 | 50 | } catch (Exception e) { |
52 | - logger.warning("Failed to persist statistics: {}", msg, e); | |
51 | + log.warn("Failed to persist statistics: {}", msg, e); | |
53 | 52 | } |
54 | 53 | } |
55 | 54 | } |
... | ... | @@ -75,7 +74,7 @@ public class StatsActor extends ContextAwareActor { |
75 | 74 | } |
76 | 75 | |
77 | 76 | @Override |
78 | - public StatsActor create() throws Exception { | |
77 | + public StatsActor create() { | |
79 | 78 | return new StatsActor(context); |
80 | 79 | } |
81 | 80 | } | ... | ... |
... | ... | @@ -17,15 +17,19 @@ package org.thingsboard.server.actors.tenant; |
17 | 17 | |
18 | 18 | import akka.actor.ActorInitializationException; |
19 | 19 | import akka.actor.ActorRef; |
20 | +import akka.actor.LocalActorRef; | |
20 | 21 | import akka.actor.OneForOneStrategy; |
21 | 22 | import akka.actor.Props; |
22 | 23 | import akka.actor.SupervisorStrategy; |
24 | +import akka.actor.Terminated; | |
23 | 25 | import akka.japi.Function; |
26 | +import com.google.common.collect.BiMap; | |
27 | +import com.google.common.collect.HashBiMap; | |
28 | +import lombok.extern.slf4j.Slf4j; | |
24 | 29 | import org.thingsboard.server.actors.ActorSystemContext; |
25 | -import org.thingsboard.server.actors.device.DeviceActor; | |
30 | +import org.thingsboard.server.actors.device.DeviceActorCreator; | |
26 | 31 | import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; |
27 | 32 | import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; |
28 | -import org.thingsboard.server.actors.ruleChain.RuleChainToRuleChainMsg; | |
29 | 33 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
30 | 34 | import org.thingsboard.server.actors.service.DefaultActorService; |
31 | 35 | import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager; |
... | ... | @@ -33,6 +37,7 @@ import org.thingsboard.server.common.data.EntityType; |
33 | 37 | import org.thingsboard.server.common.data.id.DeviceId; |
34 | 38 | import org.thingsboard.server.common.data.id.RuleChainId; |
35 | 39 | import org.thingsboard.server.common.data.id.TenantId; |
40 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
36 | 41 | import org.thingsboard.server.common.data.rule.RuleChain; |
37 | 42 | import org.thingsboard.server.common.msg.TbActorMsg; |
38 | 43 | import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
... | ... | @@ -47,15 +52,14 @@ import java.util.Map; |
47 | 52 | public class TenantActor extends RuleChainManagerActor { |
48 | 53 | |
49 | 54 | private final TenantId tenantId; |
50 | - private final Map<DeviceId, ActorRef> deviceActors; | |
55 | + private final BiMap<DeviceId, ActorRef> deviceActors; | |
51 | 56 | |
52 | 57 | private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { |
53 | 58 | super(systemContext, new TenantRuleChainManager(systemContext, tenantId)); |
54 | 59 | this.tenantId = tenantId; |
55 | - this.deviceActors = new HashMap<>(); | |
60 | + this.deviceActors = HashBiMap.create(); | |
56 | 61 | } |
57 | 62 | |
58 | - | |
59 | 63 | @Override |
60 | 64 | public SupervisorStrategy supervisorStrategy() { |
61 | 65 | return strategy; |
... | ... | @@ -63,16 +67,21 @@ public class TenantActor extends RuleChainManagerActor { |
63 | 67 | |
64 | 68 | @Override |
65 | 69 | public void preStart() { |
66 | - logger.info("[{}] Starting tenant actor.", tenantId); | |
70 | + log.info("[{}] Starting tenant actor.", tenantId); | |
67 | 71 | try { |
68 | 72 | initRuleChains(); |
69 | - logger.info("[{}] Tenant actor started.", tenantId); | |
73 | + log.info("[{}] Tenant actor started.", tenantId); | |
70 | 74 | } catch (Exception e) { |
71 | - logger.error(e, "[{}] Unknown failure", tenantId); | |
75 | + log.warn("[{}] Unknown failure", tenantId, e); | |
72 | 76 | } |
73 | 77 | } |
74 | 78 | |
75 | 79 | @Override |
80 | + public void postStop() { | |
81 | + log.info("[{}] Stopping tenant actor.", tenantId); | |
82 | + } | |
83 | + | |
84 | + @Override | |
76 | 85 | protected boolean process(TbActorMsg msg) { |
77 | 86 | switch (msg.getMsgType()) { |
78 | 87 | case CLUSTER_EVENT_MSG: |
... | ... | @@ -87,7 +96,7 @@ public class TenantActor extends RuleChainManagerActor { |
87 | 96 | case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: |
88 | 97 | onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); |
89 | 98 | break; |
90 | - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | |
99 | + case TRANSPORT_TO_DEVICE_ACTOR_MSG: | |
91 | 100 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
92 | 101 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
93 | 102 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
... | ... | @@ -105,29 +114,26 @@ public class TenantActor extends RuleChainManagerActor { |
105 | 114 | return true; |
106 | 115 | } |
107 | 116 | |
108 | - @Override | |
109 | - protected void broadcast(Object msg) { | |
110 | - super.broadcast(msg); | |
111 | - deviceActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | |
112 | - } | |
113 | - | |
114 | 117 | private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { |
115 | - if (ruleChainManager.getRootChainActor()!=null) | |
116 | - ruleChainManager.getRootChainActor().tell(msg, self()); | |
117 | - else logger.info("[{}] No Root Chain", msg); | |
118 | + if (ruleChainManager.getRootChainActor() != null) { | |
119 | + ruleChainManager.getRootChainActor().tell(msg, self()); | |
120 | + } else { | |
121 | + log.info("[{}] No Root Chain: {}", tenantId, msg); | |
122 | + } | |
118 | 123 | } |
119 | 124 | |
120 | 125 | private void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg msg) { |
121 | - if (ruleChainManager.getRootChainActor()!=null) | |
122 | - ruleChainManager.getRootChainActor().tell(msg, self()); | |
123 | - else logger.info("[{}] No Root Chain", msg); | |
126 | + if (ruleChainManager.getRootChainActor() != null) { | |
127 | + ruleChainManager.getRootChainActor().tell(msg, self()); | |
128 | + } else { | |
129 | + log.info("[{}] No Root Chain: {}", tenantId, msg); | |
130 | + } | |
124 | 131 | } |
125 | 132 | |
126 | 133 | private void onRuleChainMsg(RuleChainAwareMsg msg) { |
127 | 134 | ruleChainManager.getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self()); |
128 | 135 | } |
129 | 136 | |
130 | - | |
131 | 137 | private void onToDeviceActorMsg(DeviceAwareMsg msg) { |
132 | 138 | getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); |
133 | 139 | } |
... | ... | @@ -142,13 +148,35 @@ public class TenantActor extends RuleChainManagerActor { |
142 | 148 | } |
143 | 149 | target.tell(msg, ActorRef.noSender()); |
144 | 150 | } else { |
145 | - logger.debug("Invalid component lifecycle msg: {}", msg); | |
151 | + log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg); | |
146 | 152 | } |
147 | 153 | } |
148 | 154 | |
149 | 155 | private ActorRef getOrCreateDeviceActor(DeviceId deviceId) { |
150 | - return deviceActors.computeIfAbsent(deviceId, k -> context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId)) | |
151 | - .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), deviceId.toString())); | |
156 | + return deviceActors.computeIfAbsent(deviceId, k -> { | |
157 | + log.debug("[{}][{}] Creating device actor.", tenantId, deviceId); | |
158 | + ActorRef deviceActor = context().actorOf(Props.create(new DeviceActorCreator(systemContext, tenantId, deviceId)) | |
159 | + .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME) | |
160 | + , deviceId.toString()); | |
161 | + context().watch(deviceActor); | |
162 | + log.debug("[{}][{}] Created device actor: {}.", tenantId, deviceId, deviceActor); | |
163 | + return deviceActor; | |
164 | + }); | |
165 | + } | |
166 | + | |
167 | + @Override | |
168 | + protected void processTermination(Terminated message) { | |
169 | + ActorRef terminated = message.actor(); | |
170 | + if (terminated instanceof LocalActorRef) { | |
171 | + boolean removed = deviceActors.inverse().remove(terminated) != null; | |
172 | + if (removed) { | |
173 | + log.debug("[{}] Removed actor:", terminated); | |
174 | + } else { | |
175 | + log.warn("[{}] Removed actor was not found in the device map!"); | |
176 | + } | |
177 | + } else { | |
178 | + throw new IllegalStateException("Remote actors are not supported!"); | |
179 | + } | |
152 | 180 | } |
153 | 181 | |
154 | 182 | public static class ActorCreator extends ContextBasedCreator<TenantActor> { |
... | ... | @@ -162,7 +190,7 @@ public class TenantActor extends RuleChainManagerActor { |
162 | 190 | } |
163 | 191 | |
164 | 192 | @Override |
165 | - public TenantActor create() throws Exception { | |
193 | + public TenantActor create() { | |
166 | 194 | return new TenantActor(context, tenantId); |
167 | 195 | } |
168 | 196 | } |
... | ... | @@ -170,8 +198,8 @@ public class TenantActor extends RuleChainManagerActor { |
170 | 198 | private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() { |
171 | 199 | @Override |
172 | 200 | public SupervisorStrategy.Directive apply(Throwable t) { |
173 | - logger.error(t, "Unknown failure"); | |
174 | - if(t instanceof ActorInitializationException){ | |
201 | + log.warn("[{}] Unknown failure", tenantId, t); | |
202 | + if (t instanceof ActorInitializationException) { | |
175 | 203 | return SupervisorStrategy.stop(); |
176 | 204 | } else { |
177 | 205 | return SupervisorStrategy.resume(); | ... | ... |
... | ... | @@ -83,7 +83,7 @@ public class AlarmController extends BaseController { |
83 | 83 | Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm)); |
84 | 84 | logEntityAction(savedAlarm.getId(), savedAlarm, |
85 | 85 | getCurrentUser().getCustomerId(), |
86 | - savedAlarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | |
86 | + alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | |
87 | 87 | return savedAlarm; |
88 | 88 | } catch (Exception e) { |
89 | 89 | logEntityAction(emptyId(EntityType.ALARM), alarm, | ... | ... |
... | ... | @@ -19,9 +19,11 @@ import com.datastax.driver.core.utils.UUIDs; |
19 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | 20 | import com.fasterxml.jackson.databind.node.ArrayNode; |
21 | 21 | import com.fasterxml.jackson.databind.node.ObjectNode; |
22 | +import lombok.Getter; | |
22 | 23 | import lombok.extern.slf4j.Slf4j; |
23 | 24 | import org.apache.commons.lang3.StringUtils; |
24 | 25 | import org.springframework.beans.factory.annotation.Autowired; |
26 | +import org.springframework.beans.factory.annotation.Value; | |
25 | 27 | import org.springframework.security.core.Authentication; |
26 | 28 | import org.springframework.security.core.context.SecurityContextHolder; |
27 | 29 | import org.springframework.web.bind.annotation.ExceptionHandler; |
... | ... | @@ -48,14 +50,17 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle; |
48 | 50 | import org.thingsboard.server.common.msg.TbMsg; |
49 | 51 | import org.thingsboard.server.common.msg.TbMsgDataType; |
50 | 52 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
53 | +import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | |
51 | 54 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
52 | 55 | import org.thingsboard.server.dao.alarm.AlarmService; |
53 | 56 | import org.thingsboard.server.dao.asset.AssetService; |
57 | +import org.thingsboard.server.dao.attributes.AttributesService; | |
54 | 58 | import org.thingsboard.server.dao.audit.AuditLogService; |
55 | 59 | import org.thingsboard.server.dao.customer.CustomerService; |
56 | 60 | import org.thingsboard.server.dao.dashboard.DashboardService; |
57 | 61 | import org.thingsboard.server.dao.device.DeviceCredentialsService; |
58 | 62 | import org.thingsboard.server.dao.device.DeviceService; |
63 | +import org.thingsboard.server.dao.entityview.EntityViewService; | |
59 | 64 | import org.thingsboard.server.dao.exception.DataValidationException; |
60 | 65 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
61 | 66 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -69,6 +74,7 @@ import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; |
69 | 74 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
70 | 75 | import org.thingsboard.server.service.security.model.SecurityUser; |
71 | 76 | import org.thingsboard.server.service.state.DeviceStateService; |
77 | +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | |
72 | 78 | |
73 | 79 | import javax.mail.MessagingException; |
74 | 80 | import javax.servlet.http.HttpServletRequest; |
... | ... | @@ -139,6 +145,20 @@ public abstract class BaseController { |
139 | 145 | @Autowired |
140 | 146 | protected DeviceStateService deviceStateService; |
141 | 147 | |
148 | + @Autowired | |
149 | + protected EntityViewService entityViewService; | |
150 | + | |
151 | + @Autowired | |
152 | + protected TelemetrySubscriptionService tsSubService; | |
153 | + | |
154 | + @Autowired | |
155 | + protected AttributesService attributesService; | |
156 | + | |
157 | + @Value("${server.log_controller_error_stack_trace}") | |
158 | + @Getter | |
159 | + private boolean logControllerErrorStackTrace; | |
160 | + | |
161 | + | |
142 | 162 | @ExceptionHandler(ThingsboardException.class) |
143 | 163 | public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { |
144 | 164 | errorResponseHandler.handle(ex, response); |
... | ... | @@ -149,7 +169,7 @@ public abstract class BaseController { |
149 | 169 | } |
150 | 170 | |
151 | 171 | private ThingsboardException handleException(Exception exception, boolean logException) { |
152 | - if (logException) { | |
172 | + if (logException && logControllerErrorStackTrace) { | |
153 | 173 | log.error("Error [{}]", exception.getMessage(), exception); |
154 | 174 | } |
155 | 175 | |
... | ... | @@ -247,7 +267,6 @@ public abstract class BaseController { |
247 | 267 | |
248 | 268 | Customer checkCustomerId(CustomerId customerId) throws ThingsboardException { |
249 | 269 | try { |
250 | - validateId(customerId, "Incorrect customerId " + customerId); | |
251 | 270 | SecurityUser authUser = getCurrentUser(); |
252 | 271 | if (authUser.getAuthority() == Authority.SYS_ADMIN || |
253 | 272 | (authUser.getAuthority() != Authority.TENANT_ADMIN && |
... | ... | @@ -255,9 +274,13 @@ public abstract class BaseController { |
255 | 274 | throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION, |
256 | 275 | ThingsboardErrorCode.PERMISSION_DENIED); |
257 | 276 | } |
258 | - Customer customer = customerService.findCustomerById(customerId); | |
259 | - checkCustomer(customer); | |
260 | - return customer; | |
277 | + if (customerId != null && !customerId.isNullUid()) { | |
278 | + Customer customer = customerService.findCustomerById(customerId); | |
279 | + checkCustomer(customer); | |
280 | + return customer; | |
281 | + } else { | |
282 | + return null; | |
283 | + } | |
261 | 284 | } catch (Exception e) { |
262 | 285 | throw handleException(e, false); |
263 | 286 | } |
... | ... | @@ -313,6 +336,9 @@ public abstract class BaseController { |
313 | 336 | case USER: |
314 | 337 | checkUserId(new UserId(entityId.getId())); |
315 | 338 | return; |
339 | + case ENTITY_VIEW: | |
340 | + checkEntityViewId(new EntityViewId(entityId.getId())); | |
341 | + return; | |
316 | 342 | default: |
317 | 343 | throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); |
318 | 344 | } |
... | ... | @@ -335,11 +361,26 @@ public abstract class BaseController { |
335 | 361 | protected void checkDevice(Device device) throws ThingsboardException { |
336 | 362 | checkNotNull(device); |
337 | 363 | checkTenantId(device.getTenantId()); |
338 | - if (device.getCustomerId() != null && !device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
339 | - checkCustomerId(device.getCustomerId()); | |
364 | + checkCustomerId(device.getCustomerId()); | |
365 | + } | |
366 | + | |
367 | + protected EntityView checkEntityViewId(EntityViewId entityViewId) throws ThingsboardException { | |
368 | + try { | |
369 | + validateId(entityViewId, "Incorrect entityViewId " + entityViewId); | |
370 | + EntityView entityView = entityViewService.findEntityViewById(entityViewId); | |
371 | + checkEntityView(entityView); | |
372 | + return entityView; | |
373 | + } catch (Exception e) { | |
374 | + throw handleException(e, false); | |
340 | 375 | } |
341 | 376 | } |
342 | 377 | |
378 | + protected void checkEntityView(EntityView entityView) throws ThingsboardException { | |
379 | + checkNotNull(entityView); | |
380 | + checkTenantId(entityView.getTenantId()); | |
381 | + checkCustomerId(entityView.getCustomerId()); | |
382 | + } | |
383 | + | |
343 | 384 | Asset checkAssetId(AssetId assetId) throws ThingsboardException { |
344 | 385 | try { |
345 | 386 | validateId(assetId, "Incorrect assetId " + assetId); |
... | ... | @@ -354,9 +395,7 @@ public abstract class BaseController { |
354 | 395 | protected void checkAsset(Asset asset) throws ThingsboardException { |
355 | 396 | checkNotNull(asset); |
356 | 397 | checkTenantId(asset.getTenantId()); |
357 | - if (asset.getCustomerId() != null && !asset.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
358 | - checkCustomerId(asset.getCustomerId()); | |
359 | - } | |
398 | + checkCustomerId(asset.getCustomerId()); | |
360 | 399 | } |
361 | 400 | |
362 | 401 | Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException { |
... | ... | @@ -465,8 +504,7 @@ public abstract class BaseController { |
465 | 504 | ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException { |
466 | 505 | try { |
467 | 506 | log.debug("[{}] Lookup component descriptor", clazz); |
468 | - ComponentDescriptor componentDescriptor = checkNotNull(componentDescriptorService.getComponent(clazz)); | |
469 | - return componentDescriptor; | |
507 | + return checkNotNull(componentDescriptorService.getComponent(clazz)); | |
470 | 508 | } catch (Exception e) { |
471 | 509 | throw handleException(e, false); |
472 | 510 | } |
... | ... | @@ -530,16 +568,16 @@ public abstract class BaseController { |
530 | 568 | } |
531 | 569 | |
532 | 570 | protected <I extends EntityId> I emptyId(EntityType entityType) { |
533 | - return (I)EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); | |
571 | + return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); | |
534 | 572 | } |
535 | 573 | |
536 | 574 | protected <E extends HasName, I extends EntityId> void logEntityAction(I entityId, E entity, CustomerId customerId, |
537 | - ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException { | |
575 | + ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException { | |
538 | 576 | logEntityAction(getCurrentUser(), entityId, entity, customerId, actionType, e, additionalInfo); |
539 | 577 | } |
540 | 578 | |
541 | 579 | protected <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId, |
542 | - ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException { | |
580 | + ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException { | |
543 | 581 | if (customerId == null || customerId.isNullUid()) { |
544 | 582 | customerId = user.getCustomerId(); |
545 | 583 | } |
... | ... | @@ -555,7 +593,7 @@ public abstract class BaseController { |
555 | 593 | } |
556 | 594 | |
557 | 595 | private <E extends HasName, I extends EntityId> void pushEntityActionToRuleEngine(I entityId, E entity, User user, CustomerId customerId, |
558 | - ActionType actionType, Object... additionalInfo) { | |
596 | + ActionType actionType, Object... additionalInfo) { | |
559 | 597 | String msgType = null; |
560 | 598 | switch (actionType) { |
561 | 599 | case ADDED: |
... | ... | @@ -579,6 +617,12 @@ public abstract class BaseController { |
579 | 617 | case ATTRIBUTES_DELETED: |
580 | 618 | msgType = DataConstants.ATTRIBUTES_DELETED; |
581 | 619 | break; |
620 | + case ALARM_ACK: | |
621 | + msgType = DataConstants.ALARM_ACK; | |
622 | + break; | |
623 | + case ALARM_CLEAR: | |
624 | + msgType = DataConstants.ALARM_CLEAR; | |
625 | + break; | |
582 | 626 | } |
583 | 627 | if (!StringUtils.isEmpty(msgType)) { |
584 | 628 | try { |
... | ... | @@ -628,7 +672,7 @@ public abstract class BaseController { |
628 | 672 | String scope = extractParameter(String.class, 0, additionalInfo); |
629 | 673 | List<String> keys = extractParameter(List.class, 1, additionalInfo); |
630 | 674 | metaData.putValue("scope", scope); |
631 | - ArrayNode attrsArrayNode = entityNode.putArray("attributes"); | |
675 | + ArrayNode attrsArrayNode = entityNode.putArray("attributes"); | |
632 | 676 | if (keys != null) { |
633 | 677 | keys.forEach(attrsArrayNode::add); |
634 | 678 | } |
... | ... | @@ -637,7 +681,7 @@ public abstract class BaseController { |
637 | 681 | TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), msgType, entityId, metaData, TbMsgDataType.JSON |
638 | 682 | , json.writeValueAsString(entityNode) |
639 | 683 | , null, null, 0L); |
640 | - actorService.onMsg(new ServiceToRuleEngineMsg(user.getTenantId(), tbMsg)); | |
684 | + actorService.onMsg(new SendToClusterMsg(entityId, new ServiceToRuleEngineMsg(user.getTenantId(), tbMsg))); | |
641 | 685 | } catch (Exception e) { |
642 | 686 | log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); |
643 | 687 | } | ... | ... |
... | ... | @@ -15,6 +15,8 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | +import lombok.Getter; | |
19 | +import org.springframework.beans.factory.annotation.Value; | |
18 | 20 | import org.springframework.http.HttpStatus; |
19 | 21 | import org.springframework.security.access.prepost.PreAuthorize; |
20 | 22 | import org.springframework.web.bind.annotation.PathVariable; |
... | ... | @@ -49,6 +51,10 @@ public class DashboardController extends BaseController { |
49 | 51 | |
50 | 52 | public static final String DASHBOARD_ID = "dashboardId"; |
51 | 53 | |
54 | + @Value("${dashboard.max_datapoints_limit}") | |
55 | + private long maxDatapointsLimit; | |
56 | + | |
57 | + | |
52 | 58 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
53 | 59 | @RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET) |
54 | 60 | @ResponseBody |
... | ... | @@ -57,6 +63,13 @@ public class DashboardController extends BaseController { |
57 | 63 | } |
58 | 64 | |
59 | 65 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
66 | + @RequestMapping(value = "/dashboard/maxDatapointsLimit", method = RequestMethod.GET) | |
67 | + @ResponseBody | |
68 | + public long getMaxDatapointsLimit() throws ThingsboardException { | |
69 | + return maxDatapointsLimit; | |
70 | + } | |
71 | + | |
72 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
60 | 73 | @RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET) |
61 | 74 | @ResponseBody |
62 | 75 | public DashboardInfo getDashboardInfoById(@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 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.controller; | |
17 | + | |
18 | +import com.google.common.util.concurrent.FutureCallback; | |
19 | +import com.google.common.util.concurrent.Futures; | |
20 | +import com.google.common.util.concurrent.ListenableFuture; | |
21 | +import lombok.extern.slf4j.Slf4j; | |
22 | +import org.springframework.http.HttpStatus; | |
23 | +import org.springframework.security.access.prepost.PreAuthorize; | |
24 | +import org.springframework.web.bind.annotation.PathVariable; | |
25 | +import org.springframework.web.bind.annotation.RequestBody; | |
26 | +import org.springframework.web.bind.annotation.RequestMapping; | |
27 | +import org.springframework.web.bind.annotation.RequestMethod; | |
28 | +import org.springframework.web.bind.annotation.RequestParam; | |
29 | +import org.springframework.web.bind.annotation.ResponseBody; | |
30 | +import org.springframework.web.bind.annotation.ResponseStatus; | |
31 | +import org.springframework.web.bind.annotation.RestController; | |
32 | +import org.thingsboard.server.common.data.Customer; | |
33 | +import org.thingsboard.server.common.data.DataConstants; | |
34 | +import org.thingsboard.server.common.data.EntitySubtype; | |
35 | +import org.thingsboard.server.common.data.EntityType; | |
36 | +import org.thingsboard.server.common.data.EntityView; | |
37 | +import org.thingsboard.server.common.data.audit.ActionType; | |
38 | +import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; | |
39 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
40 | +import org.thingsboard.server.common.data.id.CustomerId; | |
41 | +import org.thingsboard.server.common.data.id.EntityId; | |
42 | +import org.thingsboard.server.common.data.id.EntityViewId; | |
43 | +import org.thingsboard.server.common.data.id.TenantId; | |
44 | +import org.thingsboard.server.common.data.id.UUIDBased; | |
45 | +import org.thingsboard.server.common.data.kv.AttributeKvEntry; | |
46 | +import org.thingsboard.server.common.data.page.TextPageData; | |
47 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
48 | +import org.thingsboard.server.dao.exception.IncorrectParameterException; | |
49 | +import org.thingsboard.server.dao.model.ModelConstants; | |
50 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
51 | + | |
52 | +import javax.annotation.Nullable; | |
53 | +import java.util.ArrayList; | |
54 | +import java.util.Collection; | |
55 | +import java.util.List; | |
56 | +import java.util.concurrent.ExecutionException; | |
57 | +import java.util.stream.Collectors; | |
58 | + | |
59 | +import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; | |
60 | + | |
61 | +/** | |
62 | + * Created by Victor Basanets on 8/28/2017. | |
63 | + */ | |
64 | +@RestController | |
65 | +@RequestMapping("/api") | |
66 | +@Slf4j | |
67 | +public class EntityViewController extends BaseController { | |
68 | + | |
69 | + public static final String ENTITY_VIEW_ID = "entityViewId"; | |
70 | + | |
71 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
72 | + @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET) | |
73 | + @ResponseBody | |
74 | + public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { | |
75 | + checkParameter(ENTITY_VIEW_ID, strEntityViewId); | |
76 | + try { | |
77 | + return checkEntityViewId(new EntityViewId(toUUID(strEntityViewId))); | |
78 | + } catch (Exception e) { | |
79 | + throw handleException(e); | |
80 | + } | |
81 | + } | |
82 | + | |
83 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
84 | + @RequestMapping(value = "/entityView", method = RequestMethod.POST) | |
85 | + @ResponseBody | |
86 | + public EntityView saveEntityView(@RequestBody EntityView entityView) throws ThingsboardException { | |
87 | + try { | |
88 | + entityView.setTenantId(getCurrentUser().getTenantId()); | |
89 | + EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); | |
90 | + List<ListenableFuture<List<Void>>> futures = new ArrayList<>(); | |
91 | + if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) { | |
92 | + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), getCurrentUser())); | |
93 | + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), getCurrentUser())); | |
94 | + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), getCurrentUser())); | |
95 | + } | |
96 | + for (ListenableFuture<List<Void>> future : futures) { | |
97 | + try { | |
98 | + future.get(); | |
99 | + } catch (InterruptedException | ExecutionException e) { | |
100 | + throw new RuntimeException("Failed to copy attributes to entity view", e); | |
101 | + } | |
102 | + } | |
103 | + | |
104 | + logEntityAction(savedEntityView.getId(), savedEntityView, null, | |
105 | + entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | |
106 | + return savedEntityView; | |
107 | + } catch (Exception e) { | |
108 | + logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, | |
109 | + entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); | |
110 | + throw handleException(e); | |
111 | + } | |
112 | + } | |
113 | + | |
114 | + private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys, SecurityUser user) throws ThingsboardException { | |
115 | + EntityViewId entityId = entityView.getId(); | |
116 | + if (keys != null && !keys.isEmpty()) { | |
117 | + ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); | |
118 | + return Futures.transform(getAttrFuture, attributeKvEntries -> { | |
119 | + List<AttributeKvEntry> attributes; | |
120 | + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { | |
121 | + attributes = | |
122 | + attributeKvEntries.stream() | |
123 | + .filter(attributeKvEntry -> { | |
124 | + long startTime = entityView.getStartTimeMs(); | |
125 | + long endTime = entityView.getEndTimeMs(); | |
126 | + long lastUpdateTs = attributeKvEntry.getLastUpdateTs(); | |
127 | + return startTime == 0 && endTime == 0 || | |
128 | + (endTime == 0 && startTime < lastUpdateTs) || | |
129 | + (startTime == 0 && endTime > lastUpdateTs) | |
130 | + ? true : startTime < lastUpdateTs && endTime > lastUpdateTs; | |
131 | + }).collect(Collectors.toList()); | |
132 | + tsSubService.saveAndNotify(entityId, scope, attributes, new FutureCallback<Void>() { | |
133 | + @Override | |
134 | + public void onSuccess(@Nullable Void tmp) { | |
135 | + try { | |
136 | + logAttributesUpdated(user, entityId, scope, attributes, null); | |
137 | + } catch (ThingsboardException e) { | |
138 | + log.error("Failed to log attribute updates", e); | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + @Override | |
143 | + public void onFailure(Throwable t) { | |
144 | + try { | |
145 | + logAttributesUpdated(user, entityId, scope, attributes, t); | |
146 | + } catch (ThingsboardException e) { | |
147 | + log.error("Failed to log attribute updates", e); | |
148 | + } | |
149 | + } | |
150 | + }); | |
151 | + } | |
152 | + return null; | |
153 | + }); | |
154 | + } else { | |
155 | + return Futures.immediateFuture(null); | |
156 | + } | |
157 | + } | |
158 | + | |
159 | + private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) throws ThingsboardException { | |
160 | + logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e), | |
161 | + scope, attributes); | |
162 | + } | |
163 | + | |
164 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
165 | + @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE) | |
166 | + @ResponseStatus(value = HttpStatus.OK) | |
167 | + public void deleteEntityView(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { | |
168 | + checkParameter(ENTITY_VIEW_ID, strEntityViewId); | |
169 | + try { | |
170 | + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); | |
171 | + EntityView entityView = checkEntityViewId(entityViewId); | |
172 | + entityViewService.deleteEntityView(entityViewId); | |
173 | + logEntityAction(entityViewId, entityView, entityView.getCustomerId(), | |
174 | + ActionType.DELETED, null, strEntityViewId); | |
175 | + } catch (Exception e) { | |
176 | + logEntityAction(emptyId(EntityType.ENTITY_VIEW), | |
177 | + null, | |
178 | + null, | |
179 | + ActionType.DELETED, e, strEntityViewId); | |
180 | + throw handleException(e); | |
181 | + } | |
182 | + } | |
183 | + | |
184 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
185 | + @RequestMapping(value = "/tenant/entityViews", params = {"entityViewName"}, method = RequestMethod.GET) | |
186 | + @ResponseBody | |
187 | + public EntityView getTenantEntityView( | |
188 | + @RequestParam String entityViewName) throws ThingsboardException { | |
189 | + try { | |
190 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
191 | + return checkNotNull(entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName)); | |
192 | + } catch (Exception e) { | |
193 | + throw handleException(e); | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
198 | + @RequestMapping(value = "/customer/{customerId}/entityView/{entityViewId}", method = RequestMethod.POST) | |
199 | + @ResponseBody | |
200 | + public EntityView assignEntityViewToCustomer(@PathVariable(CUSTOMER_ID) String strCustomerId, | |
201 | + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { | |
202 | + checkParameter(CUSTOMER_ID, strCustomerId); | |
203 | + checkParameter(ENTITY_VIEW_ID, strEntityViewId); | |
204 | + try { | |
205 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
206 | + Customer customer = checkCustomerId(customerId); | |
207 | + | |
208 | + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); | |
209 | + checkEntityViewId(entityViewId); | |
210 | + | |
211 | + EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(entityViewId, customerId)); | |
212 | + logEntityAction(entityViewId, savedEntityView, | |
213 | + savedEntityView.getCustomerId(), | |
214 | + ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName()); | |
215 | + return savedEntityView; | |
216 | + } catch (Exception e) { | |
217 | + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, | |
218 | + null, | |
219 | + ActionType.ASSIGNED_TO_CUSTOMER, e, strEntityViewId, strCustomerId); | |
220 | + throw handleException(e); | |
221 | + } | |
222 | + } | |
223 | + | |
224 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
225 | + @RequestMapping(value = "/customer/entityView/{entityViewId}", method = RequestMethod.DELETE) | |
226 | + @ResponseBody | |
227 | + public EntityView unassignEntityViewFromCustomer(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { | |
228 | + checkParameter(ENTITY_VIEW_ID, strEntityViewId); | |
229 | + try { | |
230 | + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); | |
231 | + EntityView entityView = checkEntityViewId(entityViewId); | |
232 | + if (entityView.getCustomerId() == null || entityView.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | |
233 | + throw new IncorrectParameterException("Entity View isn't assigned to any customer!"); | |
234 | + } | |
235 | + Customer customer = checkCustomerId(entityView.getCustomerId()); | |
236 | + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(entityViewId)); | |
237 | + logEntityAction(entityViewId, entityView, | |
238 | + entityView.getCustomerId(), | |
239 | + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName()); | |
240 | + | |
241 | + return savedEntityView; | |
242 | + } catch (Exception e) { | |
243 | + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, | |
244 | + null, | |
245 | + ActionType.UNASSIGNED_FROM_CUSTOMER, e, strEntityViewId); | |
246 | + throw handleException(e); | |
247 | + } | |
248 | + } | |
249 | + | |
250 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
251 | + @RequestMapping(value = "/customer/{customerId}/entityViews", params = {"limit"}, method = RequestMethod.GET) | |
252 | + @ResponseBody | |
253 | + public TextPageData<EntityView> getCustomerEntityViews( | |
254 | + @PathVariable("customerId") String strCustomerId, | |
255 | + @RequestParam int limit, | |
256 | + @RequestParam(required = false) String type, | |
257 | + @RequestParam(required = false) String textSearch, | |
258 | + @RequestParam(required = false) String idOffset, | |
259 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
260 | + checkParameter("customerId", strCustomerId); | |
261 | + try { | |
262 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
263 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | |
264 | + checkCustomerId(customerId); | |
265 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
266 | + if (type != null && type.trim().length() > 0) { | |
267 | + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerIdAndType(tenantId, customerId, pageLink, type)); | |
268 | + } else { | |
269 | + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | |
270 | + } | |
271 | + } catch (Exception e) { | |
272 | + throw handleException(e); | |
273 | + } | |
274 | + } | |
275 | + | |
276 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
277 | + @RequestMapping(value = "/tenant/entityViews", params = {"limit"}, method = RequestMethod.GET) | |
278 | + @ResponseBody | |
279 | + public TextPageData<EntityView> getTenantEntityViews( | |
280 | + @RequestParam int limit, | |
281 | + @RequestParam(required = false) String type, | |
282 | + @RequestParam(required = false) String textSearch, | |
283 | + @RequestParam(required = false) String idOffset, | |
284 | + @RequestParam(required = false) String textOffset) throws ThingsboardException { | |
285 | + try { | |
286 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
287 | + TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); | |
288 | + | |
289 | + if (type != null && type.trim().length() > 0) { | |
290 | + return checkNotNull(entityViewService.findEntityViewByTenantIdAndType(tenantId, pageLink, type)); | |
291 | + } else { | |
292 | + return checkNotNull(entityViewService.findEntityViewByTenantId(tenantId, pageLink)); | |
293 | + } | |
294 | + } catch (Exception e) { | |
295 | + throw handleException(e); | |
296 | + } | |
297 | + } | |
298 | + | |
299 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
300 | + @RequestMapping(value = "/entityViews", method = RequestMethod.POST) | |
301 | + @ResponseBody | |
302 | + public List<EntityView> findByQuery(@RequestBody EntityViewSearchQuery query) throws ThingsboardException { | |
303 | + checkNotNull(query); | |
304 | + checkNotNull(query.getParameters()); | |
305 | + checkNotNull(query.getEntityViewTypes()); | |
306 | + checkEntityId(query.getParameters().getEntityId()); | |
307 | + try { | |
308 | + List<EntityView> entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(query).get()); | |
309 | + entityViews = entityViews.stream().filter(entityView -> { | |
310 | + try { | |
311 | + checkEntityView(entityView); | |
312 | + return true; | |
313 | + } catch (ThingsboardException e) { | |
314 | + return false; | |
315 | + } | |
316 | + }).collect(Collectors.toList()); | |
317 | + return entityViews; | |
318 | + } catch (Exception e) { | |
319 | + throw handleException(e); | |
320 | + } | |
321 | + } | |
322 | + | |
323 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
324 | + @RequestMapping(value = "/entityView/types", method = RequestMethod.GET) | |
325 | + @ResponseBody | |
326 | + public List<EntitySubtype> getEntityViewTypes() throws ThingsboardException { | |
327 | + try { | |
328 | + SecurityUser user = getCurrentUser(); | |
329 | + TenantId tenantId = user.getTenantId(); | |
330 | + ListenableFuture<List<EntitySubtype>> entityViewTypes = entityViewService.findEntityViewTypesByTenantId(tenantId); | |
331 | + return checkNotNull(entityViewTypes.get()); | |
332 | + } catch (Exception e) { | |
333 | + throw handleException(e); | |
334 | + } | |
335 | + } | |
336 | +} | ... | ... |
... | ... | @@ -50,7 +50,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
50 | 50 | import org.thingsboard.server.common.msg.TbMsg; |
51 | 51 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
52 | 52 | import org.thingsboard.server.dao.event.EventService; |
53 | -import org.thingsboard.server.service.script.JsSandboxService; | |
53 | +import org.thingsboard.server.service.script.JsInvokeService; | |
54 | 54 | import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; |
55 | 55 | |
56 | 56 | import java.util.List; |
... | ... | @@ -71,7 +71,7 @@ public class RuleChainController extends BaseController { |
71 | 71 | private EventService eventService; |
72 | 72 | |
73 | 73 | @Autowired |
74 | - private JsSandboxService jsSandboxService; | |
74 | + private JsInvokeService jsInvokeService; | |
75 | 75 | |
76 | 76 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
77 | 77 | @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET) |
... | ... | @@ -276,7 +276,7 @@ public class RuleChainController extends BaseController { |
276 | 276 | String errorText = ""; |
277 | 277 | ScriptEngine engine = null; |
278 | 278 | try { |
279 | - engine = new RuleNodeJsScriptEngine(jsSandboxService, script, argNames); | |
279 | + engine = new RuleNodeJsScriptEngine(jsInvokeService, getCurrentUser().getId(), script, argNames); | |
280 | 280 | TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L); |
281 | 281 | switch (scriptType) { |
282 | 282 | case "update": | ... | ... |
... | ... | @@ -49,9 +49,11 @@ import org.thingsboard.server.common.data.kv.Aggregation; |
49 | 49 | import org.thingsboard.server.common.data.kv.AttributeKey; |
50 | 50 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
51 | 51 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
52 | +import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery; | |
52 | 53 | import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; |
53 | 54 | import org.thingsboard.server.common.data.kv.BasicTsKvEntry; |
54 | 55 | import org.thingsboard.server.common.data.kv.BooleanDataEntry; |
56 | +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; | |
55 | 57 | import org.thingsboard.server.common.data.kv.DoubleDataEntry; |
56 | 58 | import org.thingsboard.server.common.data.kv.KvEntry; |
57 | 59 | import org.thingsboard.server.common.data.kv.LongDataEntry; |
... | ... | @@ -59,14 +61,11 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; |
59 | 61 | import org.thingsboard.server.common.data.kv.StringDataEntry; |
60 | 62 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
61 | 63 | import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; |
62 | -import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | |
63 | 64 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
64 | -import org.thingsboard.server.dao.attributes.AttributesService; | |
65 | 65 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
66 | 66 | import org.thingsboard.server.service.security.AccessValidator; |
67 | 67 | import org.thingsboard.server.service.security.model.SecurityUser; |
68 | 68 | import org.thingsboard.server.service.telemetry.AttributeData; |
69 | -import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | |
70 | 69 | import org.thingsboard.server.service.telemetry.TsData; |
71 | 70 | import org.thingsboard.server.service.telemetry.exception.InvalidParametersException; |
72 | 71 | import org.thingsboard.server.service.telemetry.exception.UncheckedApiException; |
... | ... | @@ -94,15 +93,9 @@ import java.util.stream.Collectors; |
94 | 93 | public class TelemetryController extends BaseController { |
95 | 94 | |
96 | 95 | @Autowired |
97 | - private AttributesService attributesService; | |
98 | - | |
99 | - @Autowired | |
100 | 96 | private TimeseriesService tsService; |
101 | 97 | |
102 | 98 | @Autowired |
103 | - private TelemetrySubscriptionService tsSubService; | |
104 | - | |
105 | - @Autowired | |
106 | 99 | private AccessValidator accessValidator; |
107 | 100 | |
108 | 101 | private ExecutorService executor; |
... | ... | @@ -257,6 +250,60 @@ public class TelemetryController extends BaseController { |
257 | 250 | } |
258 | 251 | |
259 | 252 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
253 | + @RequestMapping(value = "/{entityType}/{entityId}/timeseries/delete", method = RequestMethod.DELETE) | |
254 | + @ResponseBody | |
255 | + public DeferredResult<ResponseEntity> deleteEntityTimeseries(@PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, | |
256 | + @RequestParam(name = "keys") String keysStr, | |
257 | + @RequestParam(name = "deleteAllDataForKeys", defaultValue = "false") boolean deleteAllDataForKeys, | |
258 | + @RequestParam(name = "startTs", required = false) Long startTs, | |
259 | + @RequestParam(name = "endTs", required = false) Long endTs, | |
260 | + @RequestParam(name = "rewriteLatestIfDeleted", defaultValue = "false") boolean rewriteLatestIfDeleted) throws ThingsboardException { | |
261 | + EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr); | |
262 | + return deleteTimeseries(entityId, keysStr, deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted); | |
263 | + } | |
264 | + | |
265 | + private DeferredResult<ResponseEntity> deleteTimeseries(EntityId entityIdStr, String keysStr, boolean deleteAllDataForKeys, | |
266 | + Long startTs, Long endTs, boolean rewriteLatestIfDeleted) throws ThingsboardException { | |
267 | + List<String> keys = toKeysList(keysStr); | |
268 | + if (keys.isEmpty()) { | |
269 | + return getImmediateDeferredResult("Empty keys: " + keysStr, HttpStatus.BAD_REQUEST); | |
270 | + } | |
271 | + SecurityUser user = getCurrentUser(); | |
272 | + | |
273 | + long deleteFromTs; | |
274 | + long deleteToTs; | |
275 | + if (deleteAllDataForKeys) { | |
276 | + deleteFromTs = 0L; | |
277 | + deleteToTs = System.currentTimeMillis(); | |
278 | + } else { | |
279 | + deleteFromTs = startTs; | |
280 | + deleteToTs = endTs; | |
281 | + } | |
282 | + | |
283 | + return accessValidator.validateEntityAndCallback(user, entityIdStr, (result, entityId) -> { | |
284 | + List<DeleteTsKvQuery> deleteTsKvQueries = new ArrayList<>(); | |
285 | + for (String key : keys) { | |
286 | + deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted)); | |
287 | + } | |
288 | + | |
289 | + ListenableFuture<List<Void>> future = tsService.remove(entityId, deleteTsKvQueries); | |
290 | + Futures.addCallback(future, new FutureCallback<List<Void>>() { | |
291 | + @Override | |
292 | + public void onSuccess(@Nullable List<Void> tmp) { | |
293 | + logTimeseriesDeleted(user, entityId, keys, null); | |
294 | + result.setResult(new ResponseEntity<>(HttpStatus.OK)); | |
295 | + } | |
296 | + | |
297 | + @Override | |
298 | + public void onFailure(Throwable t) { | |
299 | + logTimeseriesDeleted(user, entityId, keys, t); | |
300 | + result.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); | |
301 | + } | |
302 | + }, executor); | |
303 | + }); | |
304 | + } | |
305 | + | |
306 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
260 | 307 | @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE) |
261 | 308 | @ResponseBody |
262 | 309 | public DeferredResult<ResponseEntity> deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr, |
... | ... | @@ -352,7 +399,7 @@ public class TelemetryController extends BaseController { |
352 | 399 | } |
353 | 400 | |
354 | 401 | private DeferredResult<ResponseEntity> saveTelemetry(EntityId entityIdSrc, String requestBody, long ttl) throws ThingsboardException { |
355 | - TelemetryUploadRequest telemetryRequest; | |
402 | + Map<Long, List<KvEntry>> telemetryRequest; | |
356 | 403 | JsonElement telemetryJson; |
357 | 404 | try { |
358 | 405 | telemetryJson = new JsonParser().parse(requestBody); |
... | ... | @@ -360,12 +407,12 @@ public class TelemetryController extends BaseController { |
360 | 407 | return getImmediateDeferredResult("Unable to parse timeseries payload: Invalid JSON body!", HttpStatus.BAD_REQUEST); |
361 | 408 | } |
362 | 409 | try { |
363 | - telemetryRequest = JsonConverter.convertToTelemetry(telemetryJson); | |
410 | + telemetryRequest = JsonConverter.convertToTelemetry(telemetryJson, System.currentTimeMillis()); | |
364 | 411 | } catch (Exception e) { |
365 | 412 | return getImmediateDeferredResult("Unable to parse timeseries payload. Invalid JSON body: " + e.getMessage(), HttpStatus.BAD_REQUEST); |
366 | 413 | } |
367 | 414 | List<TsKvEntry> entries = new ArrayList<>(); |
368 | - for (Map.Entry<Long, List<KvEntry>> entry : telemetryRequest.getData().entrySet()) { | |
415 | + for (Map.Entry<Long, List<KvEntry>> entry : telemetryRequest.entrySet()) { | |
369 | 416 | for (KvEntry kv : entry.getValue()) { |
370 | 417 | entries.add(new BasicTsKvEntry(entry.getKey(), kv)); |
371 | 418 | } |
... | ... | @@ -513,6 +560,15 @@ public class TelemetryController extends BaseController { |
513 | 560 | }; |
514 | 561 | } |
515 | 562 | |
563 | + private void logTimeseriesDeleted(SecurityUser user, EntityId entityId, List<String> keys, Throwable e) { | |
564 | + try { | |
565 | + logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.TIMESERIES_DELETED, toException(e), | |
566 | + keys); | |
567 | + } catch (ThingsboardException te) { | |
568 | + log.warn("Failed to log timeseries delete", te); | |
569 | + } | |
570 | + } | |
571 | + | |
516 | 572 | private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) { |
517 | 573 | try { |
518 | 574 | logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_DELETED, toException(e), | ... | ... |
... | ... | @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; |
32 | 32 | import org.thingsboard.server.common.data.id.TenantId; |
33 | 33 | import org.thingsboard.server.common.data.page.TextPageData; |
34 | 34 | import org.thingsboard.server.common.data.page.TextPageLink; |
35 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
35 | 36 | import org.thingsboard.server.dao.tenant.TenantService; |
36 | 37 | import org.thingsboard.server.service.install.InstallScripts; |
37 | 38 | |
... | ... | @@ -84,6 +85,8 @@ public class TenantController extends BaseController { |
84 | 85 | try { |
85 | 86 | TenantId tenantId = new TenantId(toUUID(strTenantId)); |
86 | 87 | tenantService.deleteTenant(tenantId); |
88 | + | |
89 | + actorService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED); | |
87 | 90 | } catch (Exception e) { |
88 | 91 | throw handleException(e); |
89 | 92 | } | ... | ... |
... | ... | @@ -24,9 +24,10 @@ import org.springframework.context.annotation.Profile; |
24 | 24 | import org.springframework.stereotype.Service; |
25 | 25 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
26 | 26 | import org.thingsboard.server.service.install.DataUpdateService; |
27 | -import org.thingsboard.server.service.install.DatabaseSchemaService; | |
28 | 27 | import org.thingsboard.server.service.install.DatabaseUpgradeService; |
28 | +import org.thingsboard.server.service.install.EntityDatabaseSchemaService; | |
29 | 29 | import org.thingsboard.server.service.install.SystemDataLoaderService; |
30 | +import org.thingsboard.server.service.install.TsDatabaseSchemaService; | |
30 | 31 | |
31 | 32 | @Service |
32 | 33 | @Profile("install") |
... | ... | @@ -43,7 +44,10 @@ public class ThingsboardInstallService { |
43 | 44 | private Boolean loadDemo; |
44 | 45 | |
45 | 46 | @Autowired |
46 | - private DatabaseSchemaService databaseSchemaService; | |
47 | + private EntityDatabaseSchemaService entityDatabaseSchemaService; | |
48 | + | |
49 | + @Autowired | |
50 | + private TsDatabaseSchemaService tsDatabaseSchemaService; | |
47 | 51 | |
48 | 52 | @Autowired |
49 | 53 | private DatabaseUpgradeService databaseUpgradeService; |
... | ... | @@ -88,6 +92,20 @@ public class ThingsboardInstallService { |
88 | 92 | |
89 | 93 | dataUpdateService.updateData("1.4.0"); |
90 | 94 | |
95 | + case "2.0.0": | |
96 | + log.info("Upgrading ThingsBoard from version 2.0.0 to 2.1.1 ..."); | |
97 | + | |
98 | + databaseUpgradeService.upgradeDatabase("2.0.0"); | |
99 | + | |
100 | + case "2.1.1": | |
101 | + log.info("Upgrading ThingsBoard from version 2.1.1 to 2.1.2 ..."); | |
102 | + | |
103 | + databaseUpgradeService.upgradeDatabase("2.1.1"); | |
104 | + case "2.1.3": | |
105 | + log.info("Upgrading ThingsBoard from version 2.1.3 to 2.2.0 ..."); | |
106 | + | |
107 | + databaseUpgradeService.upgradeDatabase("2.1.3"); | |
108 | + | |
91 | 109 | log.info("Updating system data..."); |
92 | 110 | |
93 | 111 | systemDataLoaderService.deleteSystemWidgetBundle("charts"); |
... | ... | @@ -114,9 +132,13 @@ public class ThingsboardInstallService { |
114 | 132 | |
115 | 133 | log.info("Starting ThingsBoard Installation..."); |
116 | 134 | |
117 | - log.info("Installing DataBase schema..."); | |
135 | + log.info("Installing DataBase schema for entities..."); | |
136 | + | |
137 | + entityDatabaseSchemaService.createDatabaseSchema(); | |
138 | + | |
139 | + log.info("Installing DataBase schema for timeseries..."); | |
118 | 140 | |
119 | - databaseSchemaService.createDatabaseSchema(); | |
141 | + tsDatabaseSchemaService.createDatabaseSchema(); | |
120 | 142 | |
121 | 143 | log.info("Loading system data..."); |
122 | 144 | ... | ... |
... | ... | @@ -19,7 +19,8 @@ import lombok.extern.slf4j.Slf4j; |
19 | 19 | import org.springframework.beans.factory.annotation.Value; |
20 | 20 | import org.springframework.stereotype.Service; |
21 | 21 | import org.springframework.util.Assert; |
22 | -import org.thingsboard.server.gen.discovery.ServerInstanceProtos; | |
22 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
23 | +import org.thingsboard.server.common.msg.cluster.ServerType; | |
23 | 24 | |
24 | 25 | import javax.annotation.PostConstruct; |
25 | 26 | |
... | ... | @@ -43,8 +44,7 @@ public class CurrentServerInstanceService implements ServerInstanceService { |
43 | 44 | public void init() { |
44 | 45 | Assert.hasLength(rpcHost, missingProperty("rpc.bind_host")); |
45 | 46 | Assert.notNull(rpcPort, missingProperty("rpc.bind_port")); |
46 | - | |
47 | - self = new ServerInstance(ServerInstanceProtos.ServerInfo.newBuilder().setHost(rpcHost).setPort(rpcPort).setTs(System.currentTimeMillis()).build()); | |
47 | + self = new ServerInstance(new ServerAddress(rpcHost, rpcPort, ServerType.CORE)); | |
48 | 48 | log.info("Current server instance: [{};{}]", self.getHost(), self.getPort()); |
49 | 49 | } |
50 | 50 | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.service.cluster.discovery; |
17 | 17 | |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.apache.commons.lang3.RandomStringUtils; | |
19 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
20 | 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
21 | 22 | import org.springframework.context.annotation.DependsOn; |
... | ... | @@ -62,13 +63,5 @@ public class DummyDiscoveryService implements DiscoveryService { |
62 | 63 | return Collections.emptyList(); |
63 | 64 | } |
64 | 65 | |
65 | - @Override | |
66 | - public boolean addListener(DiscoveryServiceListener listener) { | |
67 | - return false; | |
68 | - } | |
69 | 66 | |
70 | - @Override | |
71 | - public boolean removeListener(DiscoveryServiceListener listener) { | |
72 | - return false; | |
73 | - } | |
74 | 67 | } | ... | ... |
... | ... | @@ -19,7 +19,6 @@ import lombok.EqualsAndHashCode; |
19 | 19 | import lombok.Getter; |
20 | 20 | import lombok.ToString; |
21 | 21 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
22 | -import org.thingsboard.server.gen.discovery.ServerInstanceProtos; | |
23 | 22 | |
24 | 23 | /** |
25 | 24 | * @author Andrew Shvayka |
... | ... | @@ -41,12 +40,6 @@ public final class ServerInstance implements Comparable<ServerInstance> { |
41 | 40 | this.port = serverAddress.getPort(); |
42 | 41 | } |
43 | 42 | |
44 | - public ServerInstance(ServerInstanceProtos.ServerInfo serverInfo) { | |
45 | - this.host = serverInfo.getHost(); | |
46 | - this.port = serverInfo.getPort(); | |
47 | - this.serverAddress = new ServerAddress(host, port); | |
48 | - } | |
49 | - | |
50 | 43 | @Override |
51 | 44 | public int compareTo(ServerInstance o) { |
52 | 45 | return this.serverAddress.compareTo(o.serverAddress); | ... | ... |