Commit ae91c85e1b802f242f3d5a13e944809131caaef5

Authored by ShvaykaD
2 parents 24165326 766a56fa

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.

@@ -32,3 +32,4 @@ pom.xml.versionsBackup @@ -32,3 +32,4 @@ pom.xml.versionsBackup
32 **/Californium.properties 32 **/Californium.properties
33 **/.env 33 **/.env
34 .instance_id 34 .instance_id
  35 +rebuild-docker.sh
@@ -2,6 +2,7 @@ before_install: @@ -2,6 +2,7 @@ before_install:
2 - sudo rm -f /etc/mavenrc 2 - sudo rm -f /etc/mavenrc
3 - export M2_HOME=/usr/local/maven 3 - export M2_HOME=/usr/local/maven
4 - export MAVEN_OPTS="-Dmaven.repo.local=$HOME/.m2/repository -Xms1024m -Xmx3072m" 4 - export MAVEN_OPTS="-Dmaven.repo.local=$HOME/.m2/repository -Xms1024m -Xmx3072m"
  5 + - export HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE=false
5 jdk: 6 jdk:
6 - oraclejdk8 7 - oraclejdk8
7 language: java 8 language: java
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.1.1-SNAPSHOT</version> 23 + <version>2.2.0-SNAPSHOT</version>
24 <artifactId>thingsboard</artifactId> 24 <artifactId>thingsboard</artifactId>
25 </parent> 25 </parent>
26 <artifactId>application</artifactId> 26 <artifactId>application</artifactId>
@@ -57,26 +57,30 @@ @@ -57,26 +57,30 @@
57 <artifactId>rule-engine-components</artifactId> 57 <artifactId>rule-engine-components</artifactId>
58 </dependency> 58 </dependency>
59 <dependency> 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 </dependency> 62 </dependency>
63 <dependency> 63 <dependency>
64 - <groupId>org.thingsboard.transport</groupId>  
65 - <artifactId>http</artifactId> 64 + <groupId>org.thingsboard.common.transport</groupId>
  65 + <artifactId>mqtt</artifactId>
66 </dependency> 66 </dependency>
67 <dependency> 67 <dependency>
68 - <groupId>org.thingsboard.transport</groupId>  
69 - <artifactId>coap</artifactId> 68 + <groupId>org.thingsboard.common.transport</groupId>
  69 + <artifactId>http</artifactId>
70 </dependency> 70 </dependency>
71 <dependency> 71 <dependency>
72 - <groupId>org.thingsboard.transport</groupId>  
73 - <artifactId>mqtt</artifactId> 72 + <groupId>org.thingsboard.common.transport</groupId>
  73 + <artifactId>coap</artifactId>
74 </dependency> 74 </dependency>
75 <dependency> 75 <dependency>
76 <groupId>org.thingsboard</groupId> 76 <groupId>org.thingsboard</groupId>
77 <artifactId>dao</artifactId> 77 <artifactId>dao</artifactId>
78 </dependency> 78 </dependency>
79 <dependency> 79 <dependency>
  80 + <groupId>org.thingsboard.common</groupId>
  81 + <artifactId>queue</artifactId>
  82 + </dependency>
  83 + <dependency>
80 <groupId>org.thingsboard</groupId> 84 <groupId>org.thingsboard</groupId>
81 <artifactId>dao</artifactId> 85 <artifactId>dao</artifactId>
82 <type>test-jar</type> 86 <type>test-jar</type>
@@ -538,7 +542,8 @@ @@ -538,7 +542,8 @@
538 <args> 542 <args>
539 <arg>-PprojectBuildDir=${project.build.directory}</arg> 543 <arg>-PprojectBuildDir=${project.build.directory}</arg>
540 <arg>-PprojectVersion=${project.version}</arg> 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 <arg>-PpkgName=${pkg.name}</arg> 547 <arg>-PpkgName=${pkg.name}</arg>
543 <arg>-PpkgInstallFolder=${pkg.installFolder}</arg> 548 <arg>-PpkgInstallFolder=${pkg.installFolder}</arg>
544 <arg>-PpkgLogFolder=${pkg.unixLogFolder}</arg> 549 <arg>-PpkgLogFolder=${pkg.unixLogFolder}</arg>
@@ -573,6 +578,27 @@ @@ -573,6 +578,27 @@
573 </executions> 578 </executions>
574 </plugin> 579 </plugin>
575 <plugin> 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 <groupId>org.xolstice.maven.plugins</groupId> 602 <groupId>org.xolstice.maven.plugins</groupId>
577 <artifactId>protobuf-maven-plugin</artifactId> 603 <artifactId>protobuf-maven-plugin</artifactId>
578 </plugin> 604 </plugin>
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 "resources": [], 15 "resources": [],
16 "templateHtml": "", 16 "templateHtml": "",
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}", 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 "settingsSchema": "{}", 19 "settingsSchema": "{}",
20 "dataKeySettingsSchema": "{}\n", 20 "dataKeySettingsSchema": "{}\n",
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\"}" 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,7 +27,7 @@
27 "descriptor": { 27 "descriptor": {
28 "type": "latest", 28 "type": "latest",
29 "sizeX": 7.5, 29 "sizeX": 7.5,
30 - "sizeY": 4.5, 30 + "sizeY": 6.5,
31 "resources": [], 31 "resources": [],
32 "templateHtml": "<tb-entities-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-entities-table-widget>", 32 "templateHtml": "<tb-entities-table-widget \n table-id=\"tableId\"\n ctx=\"ctx\">\n</tb-entities-table-widget>",
33 "templateCss": "", 33 "templateCss": "",
@@ -95,7 +95,7 @@ @@ -95,7 +95,7 @@
95 "resources": [], 95 "resources": [],
96 "templateHtml": "", 96 "templateHtml": "",
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}", 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 "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}", 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 "dataKeySettingsSchema": "{}\n", 100 "dataKeySettingsSchema": "{}\n",
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\":{}}" 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,7 +35,7 @@
35 "resources": [], 35 "resources": [],
36 "templateHtml": "", 36 "templateHtml": "",
37 "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", 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 "settingsSchema": "{}", 39 "settingsSchema": "{}",
40 "dataKeySettingsSchema": "{}", 40 "dataKeySettingsSchema": "{}",
41 "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Timeseries - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" 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,10 +147,10 @@
147 "resources": [], 147 "resources": [],
148 "templateHtml": "", 148 "templateHtml": "",
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", 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 "settingsSchema": "{}", 151 "settingsSchema": "{}",
152 "dataKeySettingsSchema": "{}", 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,7 +163,7 @@
163 "resources": [], 163 "resources": [],
164 "templateHtml": "", 164 "templateHtml": "",
165 "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", 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 "settingsSchema": "{}", 167 "settingsSchema": "{}",
168 "dataKeySettingsSchema": "{}", 168 "dataKeySettingsSchema": "{}",
169 "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\",\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"stack\":false,\"tooltipIndividual\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"smoothLines\":false},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" 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);
  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);
  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,6 +31,7 @@ import lombok.Setter;
31 import lombok.extern.slf4j.Slf4j; 31 import lombok.extern.slf4j.Slf4j;
32 import org.springframework.beans.factory.annotation.Autowired; 32 import org.springframework.beans.factory.annotation.Autowired;
33 import org.springframework.beans.factory.annotation.Value; 33 import org.springframework.beans.factory.annotation.Value;
  34 +import org.springframework.context.annotation.Lazy;
34 import org.springframework.stereotype.Component; 35 import org.springframework.stereotype.Component;
35 import org.thingsboard.rule.engine.api.MailService; 36 import org.thingsboard.rule.engine.api.MailService;
36 import org.thingsboard.server.actors.service.ActorService; 37 import org.thingsboard.server.actors.service.ActorService;
@@ -48,6 +49,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; @@ -48,6 +49,7 @@ import org.thingsboard.server.dao.attributes.AttributesService;
48 import org.thingsboard.server.dao.audit.AuditLogService; 49 import org.thingsboard.server.dao.audit.AuditLogService;
49 import org.thingsboard.server.dao.customer.CustomerService; 50 import org.thingsboard.server.dao.customer.CustomerService;
50 import org.thingsboard.server.dao.device.DeviceService; 51 import org.thingsboard.server.dao.device.DeviceService;
  52 +import org.thingsboard.server.dao.entityview.EntityViewService;
51 import org.thingsboard.server.dao.event.EventService; 53 import org.thingsboard.server.dao.event.EventService;
52 import org.thingsboard.server.dao.relation.RelationService; 54 import org.thingsboard.server.dao.relation.RelationService;
53 import org.thingsboard.server.dao.rule.RuleChainService; 55 import org.thingsboard.server.dao.rule.RuleChainService;
@@ -62,12 +64,13 @@ import org.thingsboard.server.service.encoding.DataDecodingEncodingService; @@ -62,12 +64,13 @@ import org.thingsboard.server.service.encoding.DataDecodingEncodingService;
62 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 64 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
63 import org.thingsboard.server.service.executors.ExternalCallExecutorService; 65 import org.thingsboard.server.service.executors.ExternalCallExecutorService;
64 import org.thingsboard.server.service.mail.MailExecutorService; 66 import org.thingsboard.server.service.mail.MailExecutorService;
65 -import org.thingsboard.server.service.queue.MsgQueueService;  
66 import org.thingsboard.server.service.rpc.DeviceRpcService; 67 import org.thingsboard.server.service.rpc.DeviceRpcService;
67 import org.thingsboard.server.service.script.JsExecutorService; 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 import org.thingsboard.server.service.state.DeviceStateService; 71 import org.thingsboard.server.service.state.DeviceStateService;
70 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; 72 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
  73 +import org.thingsboard.server.service.transport.RuleEngineTransportService;
71 74
72 import javax.annotation.Nullable; 75 import javax.annotation.Nullable;
73 import java.io.IOException; 76 import java.io.IOException;
@@ -161,6 +164,10 @@ public class ActorSystemContext { @@ -161,6 +164,10 @@ public class ActorSystemContext {
161 164
162 @Autowired 165 @Autowired
163 @Getter 166 @Getter
  167 + private EntityViewService entityViewService;
  168 +
  169 + @Autowired
  170 + @Getter
164 private TelemetrySubscriptionService tsSubService; 171 private TelemetrySubscriptionService tsSubService;
165 172
166 @Autowired 173 @Autowired
@@ -169,7 +176,7 @@ public class ActorSystemContext { @@ -169,7 +176,7 @@ public class ActorSystemContext {
169 176
170 @Autowired 177 @Autowired
171 @Getter 178 @Getter
172 - private JsSandboxService jsSandbox; 179 + private JsInvokeService jsSandbox;
173 180
174 @Autowired 181 @Autowired
175 @Getter 182 @Getter
@@ -193,11 +200,16 @@ public class ActorSystemContext { @@ -193,11 +200,16 @@ public class ActorSystemContext {
193 200
194 @Autowired 201 @Autowired
195 @Getter 202 @Getter
196 - private MsgQueueService msgQueueService; 203 + private DeviceStateService deviceStateService;
  204 +
  205 + @Autowired
  206 + @Getter
  207 + private DeviceSessionCacheService deviceSessionCacheService;
197 208
  209 + @Lazy
198 @Autowired 210 @Autowired
199 @Getter 211 @Getter
200 - private DeviceStateService deviceStateService; 212 + private RuleEngineTransportService ruleEngineTransportService;
201 213
202 @Value("${cluster.partition_id}") 214 @Value("${cluster.partition_id}")
203 @Getter 215 @Getter
@@ -247,17 +259,21 @@ public class ActorSystemContext { @@ -247,17 +259,21 @@ public class ActorSystemContext {
247 @Getter 259 @Getter
248 private boolean allowSystemMailService; 260 private boolean allowSystemMailService;
249 261
  262 + @Value("${transport.sessions.inactivity_timeout}")
250 @Getter 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 @Getter 270 @Getter
255 @Setter 271 @Setter
256 - private ActorRef appActor; 272 + private ActorSystem actorSystem;
257 273
258 @Getter 274 @Getter
259 @Setter 275 @Setter
260 - private ActorRef sessionManagerActor; 276 + private ActorRef appActor;
261 277
262 @Getter 278 @Getter
263 @Setter 279 @Setter
@@ -25,21 +25,24 @@ import akka.actor.Terminated; @@ -25,21 +25,24 @@ import akka.actor.Terminated;
25 import akka.event.Logging; 25 import akka.event.Logging;
26 import akka.event.LoggingAdapter; 26 import akka.event.LoggingAdapter;
27 import akka.japi.Function; 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 import org.thingsboard.server.actors.ActorSystemContext; 31 import org.thingsboard.server.actors.ActorSystemContext;
29 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; 32 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
30 import org.thingsboard.server.actors.service.ContextBasedCreator; 33 import org.thingsboard.server.actors.service.ContextBasedCreator;
31 import org.thingsboard.server.actors.service.DefaultActorService; 34 import org.thingsboard.server.actors.service.DefaultActorService;
32 import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager; 35 import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager;
33 import org.thingsboard.server.actors.tenant.TenantActor; 36 import org.thingsboard.server.actors.tenant.TenantActor;
  37 +import org.thingsboard.server.common.data.EntityType;
34 import org.thingsboard.server.common.data.Tenant; 38 import org.thingsboard.server.common.data.Tenant;
35 import org.thingsboard.server.common.data.id.TenantId; 39 import org.thingsboard.server.common.data.id.TenantId;
36 import org.thingsboard.server.common.data.page.PageDataIterable; 40 import org.thingsboard.server.common.data.page.PageDataIterable;
  41 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
37 import org.thingsboard.server.common.msg.TbActorMsg; 42 import org.thingsboard.server.common.msg.TbActorMsg;
38 import org.thingsboard.server.common.msg.aware.TenantAwareMsg; 43 import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
39 import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; 44 import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
40 import org.thingsboard.server.common.msg.cluster.ServerAddress; 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 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 46 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
44 import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; 47 import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
45 import org.thingsboard.server.dao.model.ModelConstants; 48 import org.thingsboard.server.dao.model.ModelConstants;
@@ -52,16 +55,14 @@ import java.util.Optional; @@ -52,16 +55,14 @@ import java.util.Optional;
52 55
53 public class AppActor extends RuleChainManagerActor { 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 private final TenantService tenantService; 59 private final TenantService tenantService;
59 - private final Map<TenantId, ActorRef> tenantActors; 60 + private final BiMap<TenantId, ActorRef> tenantActors;
60 61
61 private AppActor(ActorSystemContext systemContext) { 62 private AppActor(ActorSystemContext systemContext) {
62 super(systemContext, new SystemRuleChainManager(systemContext)); 63 super(systemContext, new SystemRuleChainManager(systemContext));
63 this.tenantService = systemContext.getTenantService(); 64 this.tenantService = systemContext.getTenantService();
64 - this.tenantActors = new HashMap<>(); 65 + this.tenantActors = HashBiMap.create();
65 } 66 }
66 67
67 @Override 68 @Override
@@ -71,22 +72,20 @@ public class AppActor extends RuleChainManagerActor { @@ -71,22 +72,20 @@ public class AppActor extends RuleChainManagerActor {
71 72
72 @Override 73 @Override
73 public void preStart() { 74 public void preStart() {
74 - logger.info("Starting main system actor."); 75 + log.info("Starting main system actor.");
75 try { 76 try {
76 initRuleChains(); 77 initRuleChains();
77 -  
78 if (systemContext.isTenantComponentsInitEnabled()) { 78 if (systemContext.isTenantComponentsInitEnabled()) {
79 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); 79 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);
80 for (Tenant tenant : tenantIterator) { 80 for (Tenant tenant : tenantIterator) {
81 - logger.debug("[{}] Creating tenant actor", tenant.getId()); 81 + log.debug("[{}] Creating tenant actor", tenant.getId());
82 getOrCreateTenantActor(tenant.getId()); 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 } catch (Exception e) { 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,7 +104,7 @@ public class AppActor extends RuleChainManagerActor {
105 case SERVICE_TO_RULE_ENGINE_MSG: 104 case SERVICE_TO_RULE_ENGINE_MSG:
106 onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); 105 onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
107 break; 106 break;
108 - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: 107 + case TRANSPORT_TO_DEVICE_ACTOR_MSG:
109 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 108 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
110 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: 109 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
111 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: 110 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
@@ -114,19 +113,12 @@ public class AppActor extends RuleChainManagerActor { @@ -114,19 +113,12 @@ public class AppActor extends RuleChainManagerActor {
114 case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG: 113 case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:
115 onToDeviceActorMsg((TenantAwareMsg) msg); 114 onToDeviceActorMsg((TenantAwareMsg) msg);
116 break; 115 break;
117 - case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG:  
118 - onToDeviceSessionMsg((BasicActorSystemToDeviceSessionActorMsg) msg);  
119 - break;  
120 default: 116 default:
121 return false; 117 return false;
122 } 118 }
123 return true; 119 return true;
124 } 120 }
125 121
126 - private void onToDeviceSessionMsg(BasicActorSystemToDeviceSessionActorMsg msg) {  
127 - systemContext.getSessionManagerActor().tell(msg, self());  
128 - }  
129 -  
130 private void onPossibleClusterMsg(SendToClusterMsg msg) { 122 private void onPossibleClusterMsg(SendToClusterMsg msg) {
131 Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId()); 123 Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId());
132 if (address.isPresent()) { 124 if (address.isPresent()) {
@@ -139,7 +131,8 @@ public class AppActor extends RuleChainManagerActor { @@ -139,7 +131,8 @@ public class AppActor extends RuleChainManagerActor {
139 131
140 private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { 132 private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) {
141 if (SYSTEM_TENANT.equals(msg.getTenantId())) { 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 } else { 136 } else {
144 getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); 137 getOrCreateTenantActor(msg.getTenantId()).tell(msg, self());
145 } 138 }
@@ -152,16 +145,26 @@ public class AppActor extends RuleChainManagerActor { @@ -152,16 +145,26 @@ public class AppActor extends RuleChainManagerActor {
152 } 145 }
153 146
154 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 147 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
155 - ActorRef target; 148 + ActorRef target = null;
156 if (SYSTEM_TENANT.equals(msg.getTenantId())) { 149 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
157 target = getEntityActorRef(msg.getEntityId()); 150 target = getEntityActorRef(msg.getEntityId());
158 } else { 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 if (target != null) { 164 if (target != null) {
162 target.tell(msg, ActorRef.noSender()); 165 target.tell(msg, ActorRef.noSender());
163 } else { 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,25 +172,25 @@ public class AppActor extends RuleChainManagerActor {
169 getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); 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 private ActorRef getOrCreateTenantActor(TenantId tenantId) { 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 ActorRef terminated = message.actor(); 188 ActorRef terminated = message.actor();
189 if (terminated instanceof LocalActorRef) { 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 } else { 194 } else {
192 throw new IllegalStateException("Remote actors are not supported!"); 195 throw new IllegalStateException("Remote actors are not supported!");
193 } 196 }
@@ -201,20 +204,17 @@ public class AppActor extends RuleChainManagerActor { @@ -201,20 +204,17 @@ public class AppActor extends RuleChainManagerActor {
201 } 204 }
202 205
203 @Override 206 @Override
204 - public AppActor create() throws Exception { 207 + public AppActor create() {
205 return new AppActor(context); 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,43 +15,44 @@
15 */ 15 */
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 -import akka.event.Logging;  
19 -import akka.event.LoggingAdapter;  
20 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; 18 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
21 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; 19 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
22 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.actors.service.ContextAwareActor; 21 import org.thingsboard.server.actors.service.ContextAwareActor;
24 -import org.thingsboard.server.actors.service.ContextBasedCreator;  
25 import org.thingsboard.server.common.data.id.DeviceId; 22 import org.thingsboard.server.common.data.id.DeviceId;
26 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.common.msg.TbActorMsg; 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 import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; 25 import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;
31 -import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg;  
32 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; 26 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
33 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 27 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
34 import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; 28 import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;
  29 +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
35 30
36 public class DeviceActor extends ContextAwareActor { 31 public class DeviceActor extends ContextAwareActor {
37 32
38 - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);  
39 -  
40 private final DeviceActorMessageProcessor processor; 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 super(systemContext); 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 @Override 51 @Override
48 protected boolean process(TbActorMsg msg) { 52 protected boolean process(TbActorMsg msg) {
49 switch (msg.getMsgType()) { 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 break; 56 break;
56 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 57 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
57 processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); 58 processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg);
@@ -74,11 +75,8 @@ public class DeviceActor extends ContextAwareActor { @@ -74,11 +75,8 @@ public class DeviceActor extends ContextAwareActor {
74 case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG: 75 case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG:
75 processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg); 76 processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg);
76 break; 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 break; 80 break;
83 default: 81 default:
84 return false; 82 return false;
@@ -86,22 +84,4 @@ public class DeviceActor extends ContextAwareActor { @@ -86,22 +84,4 @@ public class DeviceActor extends ContextAwareActor {
86 return true; 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,26 +13,27 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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 private static final long serialVersionUID = 1L; 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,7 +16,6 @@
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 import akka.actor.ActorContext; 18 import akka.actor.ActorContext;
19 -import akka.actor.ActorRef;  
20 import akka.event.LoggingAdapter; 19 import akka.event.LoggingAdapter;
21 import com.datastax.driver.core.utils.UUIDs; 20 import com.datastax.driver.core.utils.UUIDs;
22 import com.google.common.util.concurrent.FutureCallback; 21 import com.google.common.util.concurrent.FutureCallback;
@@ -25,6 +24,7 @@ import com.google.common.util.concurrent.ListenableFuture; @@ -25,6 +24,7 @@ import com.google.common.util.concurrent.ListenableFuture;
25 import com.google.gson.Gson; 24 import com.google.gson.Gson;
26 import com.google.gson.JsonObject; 25 import com.google.gson.JsonObject;
27 import com.google.gson.JsonParser; 26 import com.google.gson.JsonParser;
  27 +import lombok.extern.slf4j.Slf4j;
28 import org.thingsboard.rule.engine.api.RpcError; 28 import org.thingsboard.rule.engine.api.RpcError;
29 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; 29 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
30 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; 30 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
@@ -33,7 +33,6 @@ import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; @@ -33,7 +33,6 @@ import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
33 import org.thingsboard.server.common.data.DataConstants; 33 import org.thingsboard.server.common.data.DataConstants;
34 import org.thingsboard.server.common.data.Device; 34 import org.thingsboard.server.common.data.Device;
35 import org.thingsboard.server.common.data.id.DeviceId; 35 import org.thingsboard.server.common.data.id.DeviceId;
36 -import org.thingsboard.server.common.data.id.SessionId;  
37 import org.thingsboard.server.common.data.id.TenantId; 36 import org.thingsboard.server.common.data.id.TenantId;
38 import org.thingsboard.server.common.data.kv.AttributeKey; 37 import org.thingsboard.server.common.data.kv.AttributeKey;
39 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 38 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@@ -43,37 +42,34 @@ import org.thingsboard.server.common.msg.TbMsg; @@ -43,37 +42,34 @@ import org.thingsboard.server.common.msg.TbMsg;
43 import org.thingsboard.server.common.msg.TbMsgDataType; 42 import org.thingsboard.server.common.msg.TbMsgDataType;
44 import org.thingsboard.server.common.msg.TbMsgMetaData; 43 import org.thingsboard.server.common.msg.TbMsgMetaData;
45 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 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 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 45 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
67 -import org.thingsboard.server.common.msg.session.FromDeviceMsg;  
68 import org.thingsboard.server.common.msg.session.SessionMsgType; 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 import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; 47 import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;
72 -import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg;  
73 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; 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 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 69 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
75 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 70 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
76 import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; 71 import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;
  72 +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
77 73
78 import javax.annotation.Nullable; 74 import javax.annotation.Nullable;
79 import java.util.ArrayList; 75 import java.util.ArrayList;
@@ -87,24 +83,22 @@ import java.util.Map; @@ -87,24 +83,22 @@ import java.util.Map;
87 import java.util.Optional; 83 import java.util.Optional;
88 import java.util.Set; 84 import java.util.Set;
89 import java.util.UUID; 85 import java.util.UUID;
90 -import java.util.concurrent.TimeoutException;  
91 import java.util.function.Consumer; 86 import java.util.function.Consumer;
92 -import java.util.function.Predicate;  
93 import java.util.stream.Collectors; 87 import java.util.stream.Collectors;
94 88
95 /** 89 /**
96 * @author Andrew Shvayka 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 private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; 100 private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap;
106 private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap; 101 private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap;
107 - private final Map<UUID, PendingSessionMsgData> pendingMsgs;  
108 102
109 private final Gson gson = new Gson(); 103 private final Gson gson = new Gson();
110 private final JsonParser jsonParser = new JsonParser(); 104 private final JsonParser jsonParser = new JsonParser();
@@ -114,8 +108,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -114,8 +108,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
114 private String deviceType; 108 private String deviceType;
115 private TbMsgMetaData defaultMetaData; 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 this.tenantId = tenantId; 113 this.tenantId = tenantId;
120 this.deviceId = deviceId; 114 this.deviceId = deviceId;
121 this.sessions = new LinkedHashMap<>(); 115 this.sessions = new LinkedHashMap<>();
@@ -123,8 +117,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -123,8 +117,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
123 this.rpcSubscriptions = new HashMap<>(); 117 this.rpcSubscriptions = new HashMap<>();
124 this.toDeviceRpcPendingMap = new HashMap<>(); 118 this.toDeviceRpcPendingMap = new HashMap<>();
125 this.toServerRpcPendingMap = new HashMap<>(); 119 this.toServerRpcPendingMap = new HashMap<>();
126 - this.pendingMsgs = new HashMap<>();  
127 initAttributes(); 120 initAttributes();
  121 + restoreSessions();
128 } 122 }
129 123
130 private void initAttributes() { 124 private void initAttributes() {
@@ -139,41 +133,36 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -139,41 +133,36 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
139 void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) { 133 void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) {
140 ToDeviceRpcRequest request = msg.getMsg(); 134 ToDeviceRpcRequest request = msg.getMsg();
141 ToDeviceRpcRequestBody body = request.getBody(); 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 long timeout = request.getExpirationTime() - System.currentTimeMillis(); 139 long timeout = request.getExpirationTime() - System.currentTimeMillis();
149 if (timeout <= 0) { 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 return; 142 return;
152 } 143 }
153 144
154 boolean sent = rpcSubscriptions.size() > 0; 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 syncSessionSet.forEach(rpcSubscriptions::remove); 153 syncSessionSet.forEach(rpcSubscriptions::remove);
164 154
165 if (request.isOneway() && sent) { 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 } else { 158 } else {
169 registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); 159 registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout);
170 } 160 }
171 if (sent) { 161 if (sent) {
172 - logger.debug("[{}] RPC request {} is sent!", deviceId, request.getId()); 162 + log.debug("[{}] RPC request {} is sent!", deviceId, request.getId());
173 } else { 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 private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { 168 private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) {
@@ -185,101 +174,82 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -185,101 +174,82 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
185 void processServerSideRpcTimeout(ActorContext context, DeviceActorServerSideRpcTimeoutMsg msg) { 174 void processServerSideRpcTimeout(ActorContext context, DeviceActorServerSideRpcTimeoutMsg msg) {
186 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); 175 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId());
187 if (requestMd != null) { 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 if (!toDeviceRpcPendingMap.isEmpty()) { 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 rpcSubscriptions.remove(sessionId); 189 rpcSubscriptions.remove(sessionId);
222 } 190 }
223 } else { 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 Set<Integer> sentOneWayIds = new HashSet<>(); 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 } else { 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 sentOneWayIds.forEach(toDeviceRpcPendingMap::remove); 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 return entry -> { 205 return entry -> {
238 - ToDeviceRpcRequestActorMsg requestActorMsg = entry.getValue().getMsg();  
239 ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg(); 206 ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg();
240 ToDeviceRpcRequestBody body = request.getBody(); 207 ToDeviceRpcRequestBody body = request.getBody();
241 if (request.isOneway()) { 208 if (request.isOneway()) {
242 sentOneWayIds.add(entry.getKey()); 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 systemContext.getDeviceStateService().onDeviceActivity(deviceId); 253 systemContext.getDeviceStateService().onDeviceActivity(deviceId);
284 } 254 }
285 255
@@ -291,27 +261,27 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -291,27 +261,27 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
291 systemContext.getDeviceStateService().onDeviceDisconnect(deviceId); 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 Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() { 268 Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() {
300 @Override 269 @Override
301 public void onSuccess(@Nullable List<List<AttributeKvEntry>> result) { 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 @Override 279 @Override
308 public void onFailure(Throwable t) { 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,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 TbMsgMetaData metaData = defaultMetaData.copy(); 311 TbMsgMetaData metaData = defaultMetaData.copy();
365 - metaData.putValue("ts", entry.getKey() + ""); 312 + metaData.putValue("ts", tsKv.getTs() + "");
366 TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); 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 JsonObject json = new JsonObject(); 320 JsonObject json = new JsonObject();
375 - json.addProperty("method", request.getMethod()); 321 + json.addProperty("method", request.getMethodName());
376 json.add("params", jsonParser.parse(request.getParams())); 322 json.add("params", jsonParser.parse(request.getParams()));
377 323
378 TbMsgMetaData requestMetaData = defaultMetaData.copy(); 324 TbMsgMetaData requestMetaData = defaultMetaData.copy();
379 requestMetaData.putValue("requestId", Integer.toString(request.getRequestId())); 325 requestMetaData.putValue("requestId", Integer.toString(request.getRequestId()));
380 TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); 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 scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout()); 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 ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId()); 338 ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId());
390 if (data != null) { 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 void processToServerRPCResponse(ActorContext context, ToServerRpcResponseActorMsg msg) { 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 if (data != null) { 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 context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); 361 context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self());
415 } 362 }
416 363
417 void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { 364 void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) {
418 if (attributeSubscriptions.size() > 0) { 365 if (attributeSubscriptions.size() > 0) {
419 - ToDeviceMsg notification = null; 366 + boolean hasNotificationData = false;
  367 + AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder();
420 if (msg.isDeleted()) { 368 if (msg.isDeleted()) {
421 - List<AttributeKey> sharedKeys = msg.getDeletedKeys().stream() 369 + List<String> sharedKeys = msg.getDeletedKeys().stream()
422 .filter(key -> DataConstants.SHARED_SCOPE.equals(key.getScope())) 370 .filter(key -> DataConstants.SHARED_SCOPE.equals(key.getScope()))
  371 + .map(AttributeKey::getAttributeKey)
423 .collect(Collectors.toList()); 372 .collect(Collectors.toList());
424 - notification = new AttributesUpdateNotification(BasicAttributeKVMsg.fromDeleted(sharedKeys)); 373 + if (!sharedKeys.isEmpty()) {
  374 + notification.addAllSharedDeleted(sharedKeys);
  375 + hasNotificationData = true;
  376 + }
425 } else { 377 } else {
426 if (DataConstants.SHARED_SCOPE.equals(msg.getScope())) { 378 if (DataConstants.SHARED_SCOPE.equals(msg.getScope())) {
427 List<AttributeKvEntry> attributes = new ArrayList<>(msg.getValues()); 379 List<AttributeKvEntry> attributes = new ArrayList<>(msg.getValues());
428 if (attributes.size() > 0) { 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 } else { 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 attributeSubscriptions.entrySet().forEach(sub -> { 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 } else { 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 rpcSubscriptions.remove(sessionId); 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 if (sessions.size() >= systemContext.getMaxConcurrentSessionsPerDevice()) { 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 if (sessionIdToRemove != null) { 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 if (sessions.size() == 1) { 470 if (sessions.size() == 1) {
513 reportSessionOpen(); 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 sessions.remove(sessionId); 476 sessions.remove(sessionId);
518 attributeSubscriptions.remove(sessionId); 477 attributeSubscriptions.remove(sessionId);
519 rpcSubscriptions.remove(sessionId); 478 rpcSubscriptions.remove(sessionId);
520 if (sessions.isEmpty()) { 479 if (sessions.isEmpty()) {
521 reportSessionClose(); 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 void processCredentialsUpdate() { 503 void processCredentialsUpdate() {
538 - sessions.forEach(this::closeSession); 504 + sessions.forEach(this::notifyTransportAboutClosedSession);
539 attributeSubscriptions.clear(); 505 attributeSubscriptions.clear();
540 rpcSubscriptions.clear(); 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 void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { 518 void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) {
@@ -552,4 +523,178 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -552,4 +523,178 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
552 this.defaultMetaData.putValue("deviceType", deviceType); 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,10 +16,7 @@
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 import lombok.Data; 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 * @author Andrew Shvayka 22 * @author Andrew Shvayka
@@ -27,5 +24,6 @@ import java.util.Optional; @@ -27,5 +24,6 @@ import java.util.Optional;
27 @Data 24 @Data
28 public class SessionInfo { 25 public class SessionInfo {
29 private final SessionType type; 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,24 +13,27 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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.Data; 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 * @author Andrew Shvayka 22 * @author Andrew Shvayka
25 */ 23 */
26 @Data 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,22 +15,25 @@
15 */ 15 */
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 -import lombok.Data;  
19 import org.thingsboard.server.common.msg.MsgType; 18 import org.thingsboard.server.common.msg.MsgType;
20 import org.thingsboard.server.common.msg.TbActorMsg; 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 @Override 35 @Override
33 public MsgType getMsgType() { 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,18 +16,16 @@
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 import lombok.Data; 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 * @author Andrew Shvayka 24 * @author Andrew Shvayka
27 */ 25 */
28 @Data 26 @Data
29 public class ToServerRpcRequestMetadata { 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,7 +32,7 @@ public class BasicRpcSessionListener implements GrpcSessionListener {
32 private final ActorRef manager; 32 private final ActorRef manager;
33 private final ActorRef self; 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 this.service = service; 36 this.service = service;
37 this.manager = manager; 37 this.manager = manager;
38 this.self = self; 38 this.self = self;
@@ -40,7 +40,7 @@ public class BasicRpcSessionListener implements GrpcSessionListener { @@ -40,7 +40,7 @@ public class BasicRpcSessionListener implements GrpcSessionListener {
40 40
41 @Override 41 @Override
42 public void onConnected(GrpcSession session) { 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 if (!session.isClient()) { 44 if (!session.isClient()) {
45 manager.tell(new RpcSessionConnectedMsg(session.getRemoteServer(), session.getSessionId()), self); 45 manager.tell(new RpcSessionConnectedMsg(session.getRemoteServer(), session.getSessionId()), self);
46 } 46 }
@@ -48,21 +48,19 @@ public class BasicRpcSessionListener implements GrpcSessionListener { @@ -48,21 +48,19 @@ public class BasicRpcSessionListener implements GrpcSessionListener {
48 48
49 @Override 49 @Override
50 public void onDisconnected(GrpcSession session) { 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 manager.tell(new RpcSessionDisconnectedMsg(session.isClient(), session.getRemoteServer()), self); 52 manager.tell(new RpcSessionDisconnectedMsg(session.isClient(), session.getRemoteServer()), self);
53 } 53 }
54 54
55 @Override 55 @Override
56 public void onReceiveClusterGrpcMsg(GrpcSession session, ClusterAPIProtos.ClusterMessage clusterMessage) { 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 service.onReceivedMsg(session.getRemoteServer(), clusterMessage); 58 service.onReceivedMsg(session.getRemoteServer(), clusterMessage);
61 } 59 }
62 60
63 @Override 61 @Override
64 public void onError(GrpcSession session, Throwable t) { 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 manager.tell(new RpcSessionClosedMsg(session.isClient(), session.getRemoteServer()), self); 64 manager.tell(new RpcSessionClosedMsg(session.isClient(), session.getRemoteServer()), self);
67 session.close(); 65 session.close();
68 } 66 }
@@ -19,6 +19,7 @@ import akka.actor.ActorRef; @@ -19,6 +19,7 @@ import akka.actor.ActorRef;
19 import akka.actor.Props; 19 import akka.actor.Props;
20 import akka.event.Logging; 20 import akka.event.Logging;
21 import akka.event.LoggingAdapter; 21 import akka.event.LoggingAdapter;
  22 +import lombok.extern.slf4j.Slf4j;
22 import org.thingsboard.server.actors.ActorSystemContext; 23 import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.actors.service.ContextAwareActor; 24 import org.thingsboard.server.actors.service.ContextAwareActor;
24 import org.thingsboard.server.actors.service.ContextBasedCreator; 25 import org.thingsboard.server.actors.service.ContextBasedCreator;
@@ -26,6 +27,7 @@ import org.thingsboard.server.actors.service.DefaultActorService; @@ -26,6 +27,7 @@ import org.thingsboard.server.actors.service.DefaultActorService;
26 import org.thingsboard.server.common.msg.TbActorMsg; 27 import org.thingsboard.server.common.msg.TbActorMsg;
27 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 28 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
28 import org.thingsboard.server.common.msg.cluster.ServerAddress; 29 import org.thingsboard.server.common.msg.cluster.ServerAddress;
  30 +import org.thingsboard.server.common.msg.cluster.ServerType;
29 import org.thingsboard.server.gen.cluster.ClusterAPIProtos; 31 import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
30 import org.thingsboard.server.service.cluster.discovery.ServerInstance; 32 import org.thingsboard.server.service.cluster.discovery.ServerInstance;
31 33
@@ -36,15 +38,13 @@ import java.util.*; @@ -36,15 +38,13 @@ import java.util.*;
36 */ 38 */
37 public class RpcManagerActor extends ContextAwareActor { 39 public class RpcManagerActor extends ContextAwareActor {
38 40
39 - private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);  
40 -  
41 private final Map<ServerAddress, SessionActorInfo> sessionActors; 41 private final Map<ServerAddress, SessionActorInfo> sessionActors;
42 42
43 private final Map<ServerAddress, Queue<ClusterAPIProtos.ClusterMessage>> pendingMsgs; 43 private final Map<ServerAddress, Queue<ClusterAPIProtos.ClusterMessage>> pendingMsgs;
44 44
45 private final ServerAddress instance; 45 private final ServerAddress instance;
46 46
47 - public RpcManagerActor(ActorSystemContext systemContext) { 47 + private RpcManagerActor(ActorSystemContext systemContext) {
48 super(systemContext); 48 super(systemContext);
49 this.sessionActors = new HashMap<>(); 49 this.sessionActors = new HashMap<>();
50 this.pendingMsgs = new HashMap<>(); 50 this.pendingMsgs = new HashMap<>();
@@ -54,7 +54,6 @@ public class RpcManagerActor extends ContextAwareActor { @@ -54,7 +54,6 @@ public class RpcManagerActor extends ContextAwareActor {
54 .filter(otherServer -> otherServer.getServerAddress().compareTo(instance) > 0) 54 .filter(otherServer -> otherServer.getServerAddress().compareTo(instance) > 0)
55 .forEach(otherServer -> onCreateSessionRequest( 55 .forEach(otherServer -> onCreateSessionRequest(
56 new RpcSessionCreateRequestMsg(UUID.randomUUID(), otherServer.getServerAddress(), null))); 56 new RpcSessionCreateRequestMsg(UUID.randomUUID(), otherServer.getServerAddress(), null)));
57 -  
58 } 57 }
59 58
60 @Override 59 @Override
@@ -100,24 +99,23 @@ public class RpcManagerActor extends ContextAwareActor { @@ -100,24 +99,23 @@ public class RpcManagerActor extends ContextAwareActor {
100 99
101 private void onMsg(ClusterAPIProtos.ClusterMessage msg) { 100 private void onMsg(ClusterAPIProtos.ClusterMessage msg) {
102 if (msg.hasServerAddress()) { 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 SessionActorInfo session = sessionActors.get(address); 103 SessionActorInfo session = sessionActors.get(address);
106 if (session != null) { 104 if (session != null) {
107 - log.debug("{} Forwarding msg to session actor", address); 105 + log.debug("{} Forwarding msg to session actor: {}", address, msg);
108 session.getActor().tell(msg, ActorRef.noSender()); 106 session.getActor().tell(msg, ActorRef.noSender());
109 } else { 107 } else {
110 - log.debug("{} Storing msg to pending queue", address); 108 + log.debug("{} Storing msg to pending queue: {}", address, msg);
111 Queue<ClusterAPIProtos.ClusterMessage> queue = pendingMsgs.get(address); 109 Queue<ClusterAPIProtos.ClusterMessage> queue = pendingMsgs.get(address);
112 if (queue == null) { 110 if (queue == null) {
113 queue = new LinkedList<>(); 111 queue = new LinkedList<>();
114 pendingMsgs.put(new ServerAddress( 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 queue.add(msg); 115 queue.add(msg);
118 } 116 }
119 } else { 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,9 +160,9 @@ public class RpcManagerActor extends ContextAwareActor {
162 } 160 }
163 161
164 private void onSessionClose(boolean reconnect, ServerAddress remoteAddress) { 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 SessionActorInfo sessionRef = sessionActors.get(remoteAddress); 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 sessionActors.remove(remoteAddress); 166 sessionActors.remove(remoteAddress);
169 pendingMsgs.remove(remoteAddress); 167 pendingMsgs.remove(remoteAddress);
170 if (reconnect) { 168 if (reconnect) {
@@ -182,18 +180,18 @@ public class RpcManagerActor extends ContextAwareActor { @@ -182,18 +180,18 @@ public class RpcManagerActor extends ContextAwareActor {
182 180
183 private void register(ServerAddress remoteAddress, UUID uuid, ActorRef sender) { 181 private void register(ServerAddress remoteAddress, UUID uuid, ActorRef sender) {
184 sessionActors.put(remoteAddress, new SessionActorInfo(uuid, sender)); 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 Queue<ClusterAPIProtos.ClusterMessage> data = pendingMsgs.remove(remoteAddress); 184 Queue<ClusterAPIProtos.ClusterMessage> data = pendingMsgs.remove(remoteAddress);
187 if (data != null) { 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 data.forEach(msg -> sender.tell(new RpcSessionTellMsg(msg), ActorRef.noSender())); 187 data.forEach(msg -> sender.tell(new RpcSessionTellMsg(msg), ActorRef.noSender()));
190 } else { 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 private ActorRef createSessionActor(RpcSessionCreateRequestMsg msg) { 193 private ActorRef createSessionActor(RpcSessionCreateRequestMsg msg) {
196 - log.debug("[{}] Creating session actor.", msg.getMsgUid()); 194 + log.info("[{}] Creating session actor.", msg.getMsgUid());
197 ActorRef actor = context().actorOf( 195 ActorRef actor = context().actorOf(
198 Props.create(new RpcSessionActor.ActorCreator(systemContext, msg.getMsgUid())).withDispatcher(DefaultActorService.RPC_DISPATCHER_NAME)); 196 Props.create(new RpcSessionActor.ActorCreator(systemContext, msg.getMsgUid())).withDispatcher(DefaultActorService.RPC_DISPATCHER_NAME));
199 actor.tell(msg, context().self()); 197 actor.tell(msg, context().self());
@@ -208,7 +206,7 @@ public class RpcManagerActor extends ContextAwareActor { @@ -208,7 +206,7 @@ public class RpcManagerActor extends ContextAwareActor {
208 } 206 }
209 207
210 @Override 208 @Override
211 - public RpcManagerActor create() throws Exception { 209 + public RpcManagerActor create() {
212 return new RpcManagerActor(context); 210 return new RpcManagerActor(context);
213 } 211 }
214 } 212 }
@@ -18,6 +18,7 @@ package org.thingsboard.server.actors.rpc; @@ -18,6 +18,7 @@ package org.thingsboard.server.actors.rpc;
18 import akka.event.Logging; 18 import akka.event.Logging;
19 import akka.event.LoggingAdapter; 19 import akka.event.LoggingAdapter;
20 import io.grpc.Channel; 20 import io.grpc.Channel;
  21 +import io.grpc.ManagedChannel;
21 import io.grpc.ManagedChannelBuilder; 22 import io.grpc.ManagedChannelBuilder;
22 import io.grpc.stub.StreamObserver; 23 import io.grpc.stub.StreamObserver;
23 import org.thingsboard.server.actors.ActorSystemContext; 24 import org.thingsboard.server.actors.ActorSystemContext;
@@ -88,8 +89,8 @@ public class RpcSessionActor extends ContextAwareActor { @@ -88,8 +89,8 @@ public class RpcSessionActor extends ContextAwareActor {
88 systemContext.getRpcService().onSessionCreated(msg.getMsgUid(), session.getInputStream()); 89 systemContext.getRpcService().onSessionCreated(msg.getMsgUid(), session.getInputStream());
89 } else { 90 } else {
90 // Client session 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 session.initInputStream(); 94 session.initInputStream();
94 95
95 ClusterRpcServiceGrpc.ClusterRpcServiceStub stub = ClusterRpcServiceGrpc.newStub(channel); 96 ClusterRpcServiceGrpc.ClusterRpcServiceStub stub = ClusterRpcServiceGrpc.newStub(channel);
@@ -17,6 +17,7 @@ package org.thingsboard.server.actors.ruleChain; @@ -17,6 +17,7 @@ package org.thingsboard.server.actors.ruleChain;
17 17
18 import akka.actor.ActorRef; 18 import akka.actor.ActorRef;
19 import com.datastax.driver.core.utils.UUIDs; 19 import com.datastax.driver.core.utils.UUIDs;
  20 +import org.springframework.util.StringUtils;
20 import org.thingsboard.rule.engine.api.ListeningExecutor; 21 import org.thingsboard.rule.engine.api.ListeningExecutor;
21 import org.thingsboard.rule.engine.api.MailService; 22 import org.thingsboard.rule.engine.api.MailService;
22 import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest; 23 import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
@@ -35,12 +36,15 @@ import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; @@ -35,12 +36,15 @@ import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
35 import org.thingsboard.server.common.data.rule.RuleNode; 36 import org.thingsboard.server.common.data.rule.RuleNode;
36 import org.thingsboard.server.common.msg.TbMsg; 37 import org.thingsboard.server.common.msg.TbMsg;
37 import org.thingsboard.server.common.msg.TbMsgMetaData; 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 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 41 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
39 import org.thingsboard.server.dao.alarm.AlarmService; 42 import org.thingsboard.server.dao.alarm.AlarmService;
40 import org.thingsboard.server.dao.asset.AssetService; 43 import org.thingsboard.server.dao.asset.AssetService;
41 import org.thingsboard.server.dao.attributes.AttributesService; 44 import org.thingsboard.server.dao.attributes.AttributesService;
42 import org.thingsboard.server.dao.customer.CustomerService; 45 import org.thingsboard.server.dao.customer.CustomerService;
43 import org.thingsboard.server.dao.device.DeviceService; 46 import org.thingsboard.server.dao.device.DeviceService;
  47 +import org.thingsboard.server.dao.entityview.EntityViewService;
44 import org.thingsboard.server.dao.relation.RelationService; 48 import org.thingsboard.server.dao.relation.RelationService;
45 import org.thingsboard.server.dao.rule.RuleChainService; 49 import org.thingsboard.server.dao.rule.RuleChainService;
46 import org.thingsboard.server.dao.tenant.TenantService; 50 import org.thingsboard.server.dao.tenant.TenantService;
@@ -154,7 +158,7 @@ class DefaultTbContext implements TbContext { @@ -154,7 +158,7 @@ class DefaultTbContext implements TbContext {
154 158
155 @Override 159 @Override
156 public ScriptEngine createJsScriptEngine(String script, String... argNames) { 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 @Override 164 @Override
@@ -213,6 +217,11 @@ class DefaultTbContext implements TbContext { @@ -213,6 +217,11 @@ class DefaultTbContext implements TbContext {
213 } 217 }
214 218
215 @Override 219 @Override
  220 + public EntityViewService getEntityViewService() {
  221 + return mainCtx.getEntityViewService();
  222 + }
  223 +
  224 + @Override
216 public MailService getMailService() { 225 public MailService getMailService() {
217 if (mainCtx.isAllowSystemMailService()) { 226 if (mainCtx.isAllowSystemMailService()) {
218 return mainCtx.getMailService(); 227 return mainCtx.getMailService();
@@ -226,16 +235,22 @@ class DefaultTbContext implements TbContext { @@ -226,16 +235,22 @@ class DefaultTbContext implements TbContext {
226 return new RuleEngineRpcService() { 235 return new RuleEngineRpcService() {
227 @Override 236 @Override
228 public void sendRpcReply(DeviceId deviceId, int requestId, String body) { 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 @Override 241 @Override
233 public void sendRpcRequest(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) { 242 public void sendRpcRequest(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) {
234 ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), nodeCtx.getTenantId(), src.getDeviceId(), 243 ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), nodeCtx.getTenantId(), src.getDeviceId(),
235 src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody())); 244 src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody()));
236 - mainCtx.getDeviceRpcService().processRpcRequestToDevice(request, response -> { 245 + mainCtx.getDeviceRpcService().forwardServerSideRPCRequestToDeviceActor(request, response -> {
237 if (src.isRestApiCall()) { 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 consumer.accept(RuleEngineDeviceRpcResponse.builder() 255 consumer.accept(RuleEngineDeviceRpcResponse.builder()
241 .deviceId(src.getDeviceId()) 256 .deviceId(src.getDeviceId())
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
  18 +import akka.actor.ActorInitializationException;
18 import akka.actor.OneForOneStrategy; 19 import akka.actor.OneForOneStrategy;
19 import akka.actor.SupervisorStrategy; 20 import akka.actor.SupervisorStrategy;
20 import org.thingsboard.server.actors.ActorSystemContext; 21 import org.thingsboard.server.actors.ActorSystemContext;
@@ -33,7 +34,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe @@ -33,7 +34,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
33 private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) { 34 private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) {
34 super(systemContext, tenantId, ruleChainId); 35 super(systemContext, tenantId, ruleChainId);
35 setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext, 36 setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext,
36 - logger, context().parent(), context().self())); 37 + context().parent(), context().self()));
37 } 38 }
38 39
39 @Override 40 @Override
@@ -79,7 +80,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe @@ -79,7 +80,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
79 } 80 }
80 81
81 @Override 82 @Override
82 - public RuleChainActor create() throws Exception { 83 + public RuleChainActor create() {
83 return new RuleChainActor(context, tenantId, ruleChainId); 84 return new RuleChainActor(context, tenantId, ruleChainId);
84 } 85 }
85 } 86 }
@@ -23,9 +23,9 @@ import com.datastax.driver.core.utils.UUIDs; @@ -23,9 +23,9 @@ import com.datastax.driver.core.utils.UUIDs;
23 23
24 import java.util.Optional; 24 import java.util.Optional;
25 25
  26 +import lombok.extern.slf4j.Slf4j;
26 import org.thingsboard.server.actors.ActorSystemContext; 27 import org.thingsboard.server.actors.ActorSystemContext;
27 import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; 28 import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;
28 -import org.thingsboard.server.actors.device.RuleEngineQueuePutAckMsg;  
29 import org.thingsboard.server.actors.service.DefaultActorService; 29 import org.thingsboard.server.actors.service.DefaultActorService;
30 import org.thingsboard.server.actors.shared.ComponentMsgProcessor; 30 import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
31 import org.thingsboard.server.common.data.EntityType; 31 import org.thingsboard.server.common.data.EntityType;
@@ -56,6 +56,7 @@ import java.util.stream.Collectors; @@ -56,6 +56,7 @@ import java.util.stream.Collectors;
56 /** 56 /**
57 * @author Andrew Shvayka 57 * @author Andrew Shvayka
58 */ 58 */
  59 +@Slf4j
59 public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { 60 public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> {
60 61
61 private static final long DEFAULT_CLUSTER_PARTITION = 0L; 62 private static final long DEFAULT_CLUSTER_PARTITION = 0L;
@@ -68,59 +69,58 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -68,59 +69,58 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
68 private RuleNodeId firstId; 69 private RuleNodeId firstId;
69 private RuleNodeCtx firstNode; 70 private RuleNodeCtx firstNode;
70 private boolean started; 71 private boolean started;
  72 + private String ruleChainName;
71 73
72 RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext 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 this.parent = parent; 77 this.parent = parent;
76 this.self = self; 78 this.self = self;
77 this.nodeActors = new HashMap<>(); 79 this.nodeActors = new HashMap<>();
78 this.nodeRoutes = new HashMap<>(); 80 this.nodeRoutes = new HashMap<>();
79 this.service = systemContext.getRuleChainService(); 81 this.service = systemContext.getRuleChainService();
  82 + this.ruleChainName = ruleChainId.toString();
80 } 83 }
81 84
82 @Override 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 if (!started) { 92 if (!started) {
85 RuleChain ruleChain = service.findRuleChainById(entityId); 93 RuleChain ruleChain = service.findRuleChainById(entityId);
  94 + ruleChainName = ruleChain.getName();
86 List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId); 95 List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId);
  96 + log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
87 // Creating and starting the actors; 97 // Creating and starting the actors;
88 for (RuleNode ruleNode : ruleNodeList) { 98 for (RuleNode ruleNode : ruleNodeList) {
  99 + log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode);
89 ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); 100 ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
90 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); 101 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
91 } 102 }
92 initRoutes(ruleChain, ruleNodeList); 103 initRoutes(ruleChain, ruleNodeList);
93 - reprocess(ruleNodeList);  
94 started = true; 104 started = true;
95 } else { 105 } else {
96 onUpdate(context); 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 @Override 110 @Override
114 - public void onUpdate(ActorContext context) throws Exception { 111 + public void onUpdate(ActorContext context) {
115 RuleChain ruleChain = service.findRuleChainById(entityId); 112 RuleChain ruleChain = service.findRuleChainById(entityId);
  113 + ruleChainName = ruleChain.getName();
116 List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId); 114 List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId);
117 - 115 + log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
118 for (RuleNode ruleNode : ruleNodeList) { 116 for (RuleNode ruleNode : ruleNodeList) {
119 RuleNodeCtx existing = nodeActors.get(ruleNode.getId()); 117 RuleNodeCtx existing = nodeActors.get(ruleNode.getId());
120 if (existing == null) { 118 if (existing == null) {
  119 + log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode);
121 ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); 120 ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
122 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); 121 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
123 } else { 122 } else {
  123 + log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode);
124 existing.setSelf(ruleNode); 124 existing.setSelf(ruleNode);
125 existing.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self); 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,16 +129,17 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
129 Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet()); 129 Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet());
130 List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList()); 130 List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList());
131 removedRules.forEach(ruleNodeId -> { 131 removedRules.forEach(ruleNodeId -> {
  132 + log.trace("[{}][{}] Removing rule node [{}]", tenantId, entityId, ruleNodeId);
132 RuleNodeCtx removed = nodeActors.remove(ruleNodeId); 133 RuleNodeCtx removed = nodeActors.remove(ruleNodeId);
133 removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self); 134 removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self);
134 }); 135 });
135 136
136 initRoutes(ruleChain, ruleNodeList); 137 initRoutes(ruleChain, ruleNodeList);
137 - reprocess(ruleNodeList);  
138 } 138 }
139 139
140 @Override 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 nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(context::stop); 143 nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(context::stop);
143 nodeActors.clear(); 144 nodeActors.clear();
144 nodeRoutes.clear(); 145 nodeRoutes.clear();
@@ -147,7 +148,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -147,7 +148,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
147 } 148 }
148 149
149 @Override 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,10 +165,12 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
164 // Populating the routes map; 165 // Populating the routes map;
165 for (RuleNode ruleNode : ruleNodeList) { 166 for (RuleNode ruleNode : ruleNodeList) {
166 List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId()); 167 List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId());
  168 + log.trace("[{}][{}][{}] Processing rule node relations [{}]", tenantId, entityId, ruleNode.getId(), relations.size());
167 if (relations.size() == 0) { 169 if (relations.size() == 0) {
168 nodeRoutes.put(ruleNode.getId(), Collections.emptyList()); 170 nodeRoutes.put(ruleNode.getId(), Collections.emptyList());
169 } else { 171 } else {
170 for (EntityRelation relation : relations) { 172 for (EntityRelation relation : relations) {
  173 + log.trace("[{}][{}][{}] Processing rule node relation [{}]", tenantId, entityId, ruleNode.getId(), relation.getTo());
171 if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { 174 if (relation.getTo().getEntityType() == EntityType.RULE_NODE) {
172 RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId())); 175 RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId()));
173 if (ruleNodeCtx == null) { 176 if (ruleNodeCtx == null) {
@@ -181,24 +184,23 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -181,24 +184,23 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
181 } 184 }
182 185
183 firstId = ruleChain.getFirstRuleNodeId(); 186 firstId = ruleChain.getFirstRuleNodeId();
184 - firstNode = nodeActors.get(ruleChain.getFirstRuleNodeId()); 187 + firstNode = nodeActors.get(firstId);
185 state = ComponentLifecycleState.ACTIVE; 188 state = ComponentLifecycleState.ACTIVE;
186 } 189 }
187 190
188 void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) { 191 void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) {
  192 + log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, envelope.getTbMsg().getId(), envelope.getTbMsg());
189 checkActive(); 193 checkActive();
190 if (firstNode != null) { 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 void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) { 200 void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) {
196 checkActive(); 201 checkActive();
197 if (firstNode != null) { 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,15 +208,16 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
206 checkActive(); 208 checkActive();
207 if (envelope.isEnqueue()) { 209 if (envelope.isEnqueue()) {
208 if (firstNode != null) { 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 } else { 213 } else {
212 if (firstNode != null) { 214 if (firstNode != null) {
213 pushMsgToNode(firstNode, envelope.getMsg(), envelope.getFromRelationType()); 215 pushMsgToNode(firstNode, envelope.getMsg(), envelope.getFromRelationType());
214 } else { 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,7 +237,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
234 237
235 private void onRemoteTellNext(ServerAddress serverAddress, RuleNodeToRuleChainTellNextMsg envelope) { 238 private void onRemoteTellNext(ServerAddress serverAddress, RuleNodeToRuleChainTellNextMsg envelope) {
236 TbMsg msg = envelope.getMsg(); 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 envelope = new RemoteToRuleChainTellNextMsg(envelope, tenantId, entityId); 241 envelope = new RemoteToRuleChainTellNextMsg(envelope, tenantId, entityId);
239 systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(serverAddress, envelope)); 242 systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(serverAddress, envelope));
240 } 243 }
@@ -248,16 +251,20 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -248,16 +251,20 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
248 int relationsCount = relations.size(); 251 int relationsCount = relations.size();
249 EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId(); 252 EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId();
250 if (relationsCount == 0) { 253 if (relationsCount == 0) {
  254 + log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId());
251 if (ackId != null) { 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 } else if (relationsCount == 1) { 259 } else if (relationsCount == 1) {
255 for (RuleNodeRelation relation : relations) { 260 for (RuleNodeRelation relation : relations) {
  261 + log.trace("[{}][{}][{}] Pushing message to single target: [{}]", tenantId, entityId, msg.getId(), relation.getOut());
256 pushToTarget(msg, relation.getOut(), relation.getType()); 262 pushToTarget(msg, relation.getOut(), relation.getType());
257 } 263 }
258 } else { 264 } else {
259 for (RuleNodeRelation relation : relations) { 265 for (RuleNodeRelation relation : relations) {
260 EntityId target = relation.getOut(); 266 EntityId target = relation.getOut();
  267 + log.trace("[{}][{}][{}] Pushing message to multiple targets: [{}]", tenantId, entityId, msg.getId(), relation.getOut());
261 switch (target.getEntityType()) { 268 switch (target.getEntityType()) {
262 case RULE_NODE: 269 case RULE_NODE:
263 enqueueAndForwardMsgCopyToNode(msg, target, relation.getType()); 270 enqueueAndForwardMsgCopyToNode(msg, target, relation.getType());
@@ -269,7 +276,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -269,7 +276,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
269 } 276 }
270 //TODO: Ideally this should happen in async way when all targets confirm that the copied messages are successfully written to corresponding target queues. 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 if (ackId != null) { 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,7 +304,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
296 RuleNodeId targetId = new RuleNodeId(target.getId()); 304 RuleNodeId targetId = new RuleNodeId(target.getId());
297 RuleNodeCtx targetNodeCtx = nodeActors.get(targetId); 305 RuleNodeCtx targetNodeCtx = nodeActors.get(targetId);
298 TbMsg copy = msg.copy(UUIDs.timeBased(), entityId, targetId, DEFAULT_CLUSTER_PARTITION); 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 private void pushToTarget(TbMsg msg, EntityId target, String fromRelationType) { 310 private void pushToTarget(TbMsg msg, EntityId target, String fromRelationType) {
@@ -32,7 +32,7 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa @@ -32,7 +32,7 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
32 super(systemContext, tenantId, ruleNodeId); 32 super(systemContext, tenantId, ruleNodeId);
33 this.ruleChainId = ruleChainId; 33 this.ruleChainId = ruleChainId;
34 setProcessor(new RuleNodeActorMessageProcessor(tenantId, ruleChainId, ruleNodeId, systemContext, 34 setProcessor(new RuleNodeActorMessageProcessor(tenantId, ruleChainId, ruleNodeId, systemContext,
35 - logger, context().parent(), context().self())); 35 + context().parent(), context().self()));
36 } 36 }
37 37
38 @Override 38 @Override
@@ -60,7 +60,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa @@ -60,7 +60,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
60 } 60 }
61 61
62 private void onRuleNodeToSelfMsg(RuleNodeToSelfMsg msg) { 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 try { 66 try {
65 processor.onRuleToSelfMsg(msg); 67 processor.onRuleToSelfMsg(msg);
66 increaseMessagesProcessedCount(); 68 increaseMessagesProcessedCount();
@@ -70,7 +72,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa @@ -70,7 +72,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
70 } 72 }
71 73
72 private void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) { 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 try { 78 try {
75 processor.onRuleChainToRuleNodeMsg(msg); 79 processor.onRuleChainToRuleNodeMsg(msg);
76 increaseMessagesProcessedCount(); 80 increaseMessagesProcessedCount();
@@ -44,8 +44,8 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -44,8 +44,8 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
44 private TbContext defaultCtx; 44 private TbContext defaultCtx;
45 45
46 RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext 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 this.parent = parent; 49 this.parent = parent;
50 this.self = self; 50 this.self = self;
51 this.service = systemContext.getRuleChainService(); 51 this.service = systemContext.getRuleChainService();
@@ -75,7 +75,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -75,7 +75,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
75 } 75 }
76 76
77 @Override 77 @Override
78 - public void stop(ActorContext context) throws Exception { 78 + public void stop(ActorContext context) {
79 if (tbNode != null) { 79 if (tbNode != null) {
80 tbNode.destroy(); 80 tbNode.destroy();
81 } 81 }
@@ -83,7 +83,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -83,7 +83,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
83 } 83 }
84 84
85 @Override 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,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 private TbNode initComponent(RuleNode ruleNode) throws Exception { 119 private TbNode initComponent(RuleNode ruleNode) throws Exception {
115 Class<?> componentClazz = Class.forName(ruleNode.getType()); 120 Class<?> componentClazz = Class.forName(ruleNode.getType());
116 TbNode tbNode = (TbNode) (componentClazz.newInstance()); 121 TbNode tbNode = (TbNode) (componentClazz.newInstance());
@@ -35,5 +35,4 @@ public interface ActorService extends SessionMsgProcessor, RpcMsgListener, Disco @@ -35,5 +35,4 @@ public interface ActorService extends SessionMsgProcessor, RpcMsgListener, Disco
35 35
36 void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType); 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,6 +18,7 @@ package org.thingsboard.server.actors.service;
18 import akka.actor.ActorRef; 18 import akka.actor.ActorRef;
19 import akka.event.Logging; 19 import akka.event.Logging;
20 import akka.event.LoggingAdapter; 20 import akka.event.LoggingAdapter;
  21 +import lombok.extern.slf4j.Slf4j;
21 import org.thingsboard.server.actors.ActorSystemContext; 22 import org.thingsboard.server.actors.ActorSystemContext;
22 import org.thingsboard.server.actors.shared.ComponentMsgProcessor; 23 import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
23 import org.thingsboard.server.actors.stats.StatsPersistMsg; 24 import org.thingsboard.server.actors.stats.StatsPersistMsg;
@@ -32,8 +33,6 @@ import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; @@ -32,8 +33,6 @@ import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
32 */ 33 */
33 public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ContextAwareActor { 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 private long lastPersistedErrorTs = 0L; 36 private long lastPersistedErrorTs = 0L;
38 protected final TenantId tenantId; 37 protected final TenantId tenantId;
39 protected final T id; 38 protected final T id;
@@ -54,13 +53,14 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -54,13 +53,14 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
54 @Override 53 @Override
55 public void preStart() { 54 public void preStart() {
56 try { 55 try {
  56 + log.debug("[{}][{}][{}] Starting processor.", tenantId, id, id.getEntityType());
57 processor.start(context()); 57 processor.start(context());
58 logLifecycleEvent(ComponentLifecycleEvent.STARTED); 58 logLifecycleEvent(ComponentLifecycleEvent.STARTED);
59 if (systemContext.isStatisticsEnabled()) { 59 if (systemContext.isStatisticsEnabled()) {
60 scheduleStatsPersistTick(); 60 scheduleStatsPersistTick();
61 } 61 }
62 } catch (Exception e) { 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 logAndPersist("OnStart", e, true); 64 logAndPersist("OnStart", e, true);
65 logLifecycleEvent(ComponentLifecycleEvent.STARTED, e); 65 logLifecycleEvent(ComponentLifecycleEvent.STARTED, e);
66 } 66 }
@@ -70,7 +70,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -70,7 +70,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
70 try { 70 try {
71 processor.scheduleStatsPersistTick(context(), systemContext.getStatisticsPersistFrequency()); 71 processor.scheduleStatsPersistTick(context(), systemContext.getStatisticsPersistFrequency());
72 } catch (Exception e) { 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 logAndPersist("onScheduleStatsPersistMsg", e); 74 logAndPersist("onScheduleStatsPersistMsg", e);
75 } 75 }
76 } 76 }
@@ -78,16 +78,18 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -78,16 +78,18 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
78 @Override 78 @Override
79 public void postStop() { 79 public void postStop() {
80 try { 80 try {
  81 + log.debug("[{}][{}] Stopping processor.", tenantId, id, id.getEntityType());
81 processor.stop(context()); 82 processor.stop(context());
82 logLifecycleEvent(ComponentLifecycleEvent.STOPPED); 83 logLifecycleEvent(ComponentLifecycleEvent.STOPPED);
83 } catch (Exception e) { 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 logAndPersist("OnStop", e, true); 86 logAndPersist("OnStop", e, true);
86 logLifecycleEvent(ComponentLifecycleEvent.STOPPED, e); 87 logLifecycleEvent(ComponentLifecycleEvent.STOPPED, e);
87 } 88 }
88 } 89 }
89 90
90 protected void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 91 protected void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
  92 + log.debug("[{}][{}][{}] onComponentLifecycleMsg: [{}]", tenantId, id, id.getEntityType(), msg.getEvent());
91 try { 93 try {
92 switch (msg.getEvent()) { 94 switch (msg.getEvent()) {
93 case CREATED: 95 case CREATED:
@@ -148,9 +150,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -148,9 +150,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
148 private void logAndPersist(String method, Exception e, boolean critical) { 150 private void logAndPersist(String method, Exception e, boolean critical) {
149 errorsOccurred++; 151 errorsOccurred++;
150 if (critical) { 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 } else { 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 long ts = System.currentTimeMillis(); 157 long ts = System.currentTimeMillis();
156 if (ts - lastPersistedErrorTs > getErrorPersistFrequency()) { 158 if (ts - lastPersistedErrorTs > getErrorPersistFrequency()) {
@@ -15,14 +15,17 @@ @@ -15,14 +15,17 @@
15 */ 15 */
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
  18 +import akka.actor.Terminated;
18 import akka.actor.UntypedActor; 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 import org.thingsboard.server.actors.ActorSystemContext; 22 import org.thingsboard.server.actors.ActorSystemContext;
22 import org.thingsboard.server.common.msg.TbActorMsg; 23 import org.thingsboard.server.common.msg.TbActorMsg;
23 24
  25 +
24 public abstract class ContextAwareActor extends UntypedActor { 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 public static final int ENTITY_PACK_LIMIT = 1024; 30 public static final int ENTITY_PACK_LIMIT = 1024;
28 31
@@ -35,21 +38,26 @@ public abstract class ContextAwareActor extends UntypedActor { @@ -35,21 +38,26 @@ public abstract class ContextAwareActor extends UntypedActor {
35 38
36 @Override 39 @Override
37 public void onReceive(Object msg) throws Exception { 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 if (msg instanceof TbActorMsg) { 44 if (msg instanceof TbActorMsg) {
42 try { 45 try {
43 if (!process((TbActorMsg) msg)) { 46 if (!process((TbActorMsg) msg)) {
44 - logger.warning("Unknown message: {}!", msg); 47 + log.warn("Unknown message: {}!", msg);
45 } 48 }
46 } catch (Exception e) { 49 } catch (Exception e) {
47 throw e; 50 throw e;
48 } 51 }
  52 + } else if (msg instanceof Terminated) {
  53 + processTermination((Terminated) msg);
49 } else { 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 protected abstract boolean process(TbActorMsg msg); 62 protected abstract boolean process(TbActorMsg msg);
55 } 63 }
@@ -30,7 +30,6 @@ import org.thingsboard.server.actors.app.AppActor; @@ -30,7 +30,6 @@ import org.thingsboard.server.actors.app.AppActor;
30 import org.thingsboard.server.actors.rpc.RpcBroadcastMsg; 30 import org.thingsboard.server.actors.rpc.RpcBroadcastMsg;
31 import org.thingsboard.server.actors.rpc.RpcManagerActor; 31 import org.thingsboard.server.actors.rpc.RpcManagerActor;
32 import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; 32 import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg;
33 -import org.thingsboard.server.actors.session.SessionManagerActor;  
34 import org.thingsboard.server.actors.stats.StatsActor; 33 import org.thingsboard.server.actors.stats.StatsActor;
35 import org.thingsboard.server.common.data.Device; 34 import org.thingsboard.server.common.data.Device;
36 import org.thingsboard.server.common.data.id.DeviceId; 35 import org.thingsboard.server.common.data.id.DeviceId;
@@ -38,13 +37,11 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -38,13 +37,11 @@ import org.thingsboard.server.common.data.id.EntityId;
38 import org.thingsboard.server.common.data.id.TenantId; 37 import org.thingsboard.server.common.data.id.TenantId;
39 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 38 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
40 import org.thingsboard.server.common.msg.TbActorMsg; 39 import org.thingsboard.server.common.msg.TbActorMsg;
41 -import org.thingsboard.server.common.msg.aware.SessionAwareMsg;  
42 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 40 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
43 import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; 41 import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
44 import org.thingsboard.server.common.msg.cluster.ServerAddress; 42 import org.thingsboard.server.common.msg.cluster.ServerAddress;
45 import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; 43 import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
46 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 44 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
47 -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;  
48 import org.thingsboard.server.gen.cluster.ClusterAPIProtos; 45 import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
49 import org.thingsboard.server.service.cluster.discovery.DiscoveryService; 46 import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
50 import org.thingsboard.server.service.cluster.discovery.ServerInstance; 47 import org.thingsboard.server.service.cluster.discovery.ServerInstance;
@@ -68,10 +65,7 @@ public class DefaultActorService implements ActorService { @@ -68,10 +65,7 @@ public class DefaultActorService implements ActorService {
68 public static final String APP_DISPATCHER_NAME = "app-dispatcher"; 65 public static final String APP_DISPATCHER_NAME = "app-dispatcher";
69 public static final String CORE_DISPATCHER_NAME = "core-dispatcher"; 66 public static final String CORE_DISPATCHER_NAME = "core-dispatcher";
70 public static final String SYSTEM_RULE_DISPATCHER_NAME = "system-rule-dispatcher"; 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 public static final String TENANT_RULE_DISPATCHER_NAME = "rule-dispatcher"; 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 public static final String RPC_DISPATCHER_NAME = "rpc-dispatcher"; 69 public static final String RPC_DISPATCHER_NAME = "rpc-dispatcher";
76 70
77 @Autowired 71 @Autowired
@@ -90,8 +84,6 @@ public class DefaultActorService implements ActorService { @@ -90,8 +84,6 @@ public class DefaultActorService implements ActorService {
90 84
91 private ActorRef appActor; 85 private ActorRef appActor;
92 86
93 - private ActorRef sessionManagerActor;  
94 -  
95 private ActorRef rpcManagerActor; 87 private ActorRef rpcManagerActor;
96 88
97 @PostConstruct 89 @PostConstruct
@@ -104,10 +96,6 @@ public class DefaultActorService implements ActorService { @@ -104,10 +96,6 @@ public class DefaultActorService implements ActorService {
104 appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor"); 96 appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor");
105 actorContext.setAppActor(appActor); 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 rpcManagerActor = system.actorOf(Props.create(new RpcManagerActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), 99 rpcManagerActor = system.actorOf(Props.create(new RpcManagerActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME),
112 "rpcManagerActor"); 100 "rpcManagerActor");
113 101
@@ -115,8 +103,6 @@ public class DefaultActorService implements ActorService { @@ -115,8 +103,6 @@ public class DefaultActorService implements ActorService {
115 actorContext.setStatsActor(statsActor); 103 actorContext.setStatsActor(statsActor);
116 104
117 rpcService.init(this); 105 rpcService.init(this);
118 -  
119 - discoveryService.addListener(this);  
120 log.info("Actor system initialized."); 106 log.info("Actor system initialized.");
121 } 107 }
122 108
@@ -137,12 +123,6 @@ public class DefaultActorService implements ActorService { @@ -137,12 +123,6 @@ public class DefaultActorService implements ActorService {
137 } 123 }
138 124
139 @Override 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 public void onServerAdded(ServerInstance server) { 126 public void onServerAdded(ServerInstance server) {
147 log.trace("Processing onServerAdded msg: {}", server); 127 log.trace("Processing onServerAdded msg: {}", server);
148 broadcast(new ClusterEventMsg(server.getServerAddress(), true)); 128 broadcast(new ClusterEventMsg(server.getServerAddress(), true));
@@ -178,11 +158,6 @@ public class DefaultActorService implements ActorService { @@ -178,11 +158,6 @@ public class DefaultActorService implements ActorService {
178 appActor.tell(new SendToClusterMsg(deviceId, msg), ActorRef.noSender()); 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 public void broadcast(ToAllNodesMsg msg) { 161 public void broadcast(ToAllNodesMsg msg) {
187 actorContext.getEncodingService().encode(msg); 162 actorContext.getEncodingService().encode(msg);
188 rpcService.broadcast(new RpcBroadcastMsg(ClusterAPIProtos.ClusterMessage 163 rpcService.broadcast(new RpcBroadcastMsg(ClusterAPIProtos.ClusterMessage
@@ -196,16 +171,15 @@ public class DefaultActorService implements ActorService { @@ -196,16 +171,15 @@ public class DefaultActorService implements ActorService {
196 171
197 private void broadcast(ClusterEventMsg msg) { 172 private void broadcast(ClusterEventMsg msg) {
198 this.appActor.tell(msg, ActorRef.noSender()); 173 this.appActor.tell(msg, ActorRef.noSender());
199 - this.sessionManagerActor.tell(msg, ActorRef.noSender());  
200 this.rpcManagerActor.tell(msg, ActorRef.noSender()); 174 this.rpcManagerActor.tell(msg, ActorRef.noSender());
201 } 175 }
202 176
203 @Override 177 @Override
204 public void onReceivedMsg(ServerAddress source, ClusterAPIProtos.ClusterMessage msg) { 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 if (log.isDebugEnabled()) { 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 switch (msg.getMessageType()) { 184 switch (msg.getMessageType()) {
211 case CLUSTER_ACTOR_MESSAGE: 185 case CLUSTER_ACTOR_MESSAGE:
@@ -239,7 +213,7 @@ public class DefaultActorService implements ActorService { @@ -239,7 +213,7 @@ public class DefaultActorService implements ActorService {
239 actorContext.getTsSubService().onRemoteTsUpdate(serverAddress, msg.getPayload().toByteArray()); 213 actorContext.getTsSubService().onRemoteTsUpdate(serverAddress, msg.getPayload().toByteArray());
240 break; 214 break;
241 case CLUSTER_RPC_FROM_DEVICE_RESPONSE_MESSAGE: 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 break; 217 break;
244 case CLUSTER_DEVICE_STATE_SERVICE_MESSAGE: 218 case CLUSTER_DEVICE_STATE_SERVICE_MESSAGE:
245 actorContext.getDeviceStateService().onRemoteMsg(serverAddress, msg.getPayload().toByteArray()); 219 actorContext.getDeviceStateService().onRemoteMsg(serverAddress, msg.getPayload().toByteArray());
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 -}  
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 -}  
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 -}  
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 -}  
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 -}  
@@ -22,61 +22,49 @@ import akka.event.LoggingAdapter; @@ -22,61 +22,49 @@ import akka.event.LoggingAdapter;
22 import com.fasterxml.jackson.databind.ObjectMapper; 22 import com.fasterxml.jackson.databind.ObjectMapper;
23 import lombok.AllArgsConstructor; 23 import lombok.AllArgsConstructor;
24 import lombok.Data; 24 import lombok.Data;
  25 +import lombok.extern.slf4j.Slf4j;
25 import org.thingsboard.server.actors.ActorSystemContext; 26 import org.thingsboard.server.actors.ActorSystemContext;
26 import scala.concurrent.ExecutionContextExecutor; 27 import scala.concurrent.ExecutionContextExecutor;
27 import scala.concurrent.duration.Duration; 28 import scala.concurrent.duration.Duration;
28 29
29 import java.util.concurrent.TimeUnit; 30 import java.util.concurrent.TimeUnit;
30 31
  32 +@Slf4j
31 public abstract class AbstractContextAwareMsgProcessor { 33 public abstract class AbstractContextAwareMsgProcessor {
32 34
33 protected final ActorSystemContext systemContext; 35 protected final ActorSystemContext systemContext;
34 - protected final LoggingAdapter logger;  
35 protected final ObjectMapper mapper = new ObjectMapper(); 36 protected final ObjectMapper mapper = new ObjectMapper();
36 37
37 - protected AbstractContextAwareMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger) { 38 + protected AbstractContextAwareMsgProcessor(ActorSystemContext systemContext) {
38 super(); 39 super();
39 this.systemContext = systemContext; 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 return systemContext.getScheduler(); 44 return systemContext.getScheduler();
49 } 45 }
50 46
51 - protected ExecutionContextExecutor getSystemDispatcher() { 47 + private ExecutionContextExecutor getSystemDispatcher() {
52 return systemContext.getActorSystem().dispatcher(); 48 return systemContext.getActorSystem().dispatcher();
53 } 49 }
54 50
55 protected void schedulePeriodicMsgWithDelay(ActorContext ctx, Object msg, long delayInMs, long periodInMs) { 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 getScheduler().schedule(Duration.create(delayInMs, TimeUnit.MILLISECONDS), Duration.create(periodInMs, TimeUnit.MILLISECONDS), target, msg, getSystemDispatcher(), null); 57 getScheduler().schedule(Duration.create(delayInMs, TimeUnit.MILLISECONDS), Duration.create(periodInMs, TimeUnit.MILLISECONDS), target, msg, getSystemDispatcher(), null);
62 } 58 }
63 59
64 -  
65 protected void scheduleMsgWithDelay(ActorContext ctx, Object msg, long delayInMs) { 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 getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, getSystemDispatcher(), null); 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,6 +19,7 @@ import akka.actor.ActorContext;
19 import akka.event.LoggingAdapter; 19 import akka.event.LoggingAdapter;
20 import com.google.common.util.concurrent.FutureCallback; 20 import com.google.common.util.concurrent.FutureCallback;
21 import com.google.common.util.concurrent.Futures; 21 import com.google.common.util.concurrent.Futures;
  22 +import lombok.extern.slf4j.Slf4j;
22 import org.thingsboard.server.actors.ActorSystemContext; 23 import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.actors.stats.StatsPersistTick; 24 import org.thingsboard.server.actors.stats.StatsPersistTick;
24 import org.thingsboard.server.common.data.id.EntityId; 25 import org.thingsboard.server.common.data.id.EntityId;
@@ -26,25 +27,25 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -26,25 +27,25 @@ import org.thingsboard.server.common.data.id.TenantId;
26 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; 27 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
27 import org.thingsboard.server.common.msg.TbMsg; 28 import org.thingsboard.server.common.msg.TbMsg;
28 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 29 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
29 -import org.thingsboard.server.service.queue.MsgQueueService;  
30 30
31 import javax.annotation.Nullable; 31 import javax.annotation.Nullable;
32 import java.util.function.Consumer; 32 import java.util.function.Consumer;
33 33
  34 +@Slf4j
34 public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor { 35 public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor {
35 36
36 protected final TenantId tenantId; 37 protected final TenantId tenantId;
37 protected final T entityId; 38 protected final T entityId;
38 - protected final MsgQueueService queue;  
39 protected ComponentLifecycleState state; 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 this.tenantId = tenantId; 43 this.tenantId = tenantId;
44 this.entityId = id; 44 this.entityId = id;
45 - this.queue = systemContext.getMsgQueueService();  
46 } 45 }
47 46
  47 + public abstract String getComponentName();
  48 +
48 public abstract void start(ActorContext context) throws Exception; 49 public abstract void start(ActorContext context) throws Exception;
49 50
50 public abstract void stop(ActorContext context) throws Exception; 51 public abstract void stop(ActorContext context) throws Exception;
@@ -82,22 +83,9 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract @@ -82,22 +83,9 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract
82 83
83 protected void checkActive() { 84 protected void checkActive() {
84 if (state != ComponentLifecycleState.ACTIVE) { 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,6 +20,8 @@ import akka.actor.ActorRef;
20 import akka.actor.Props; 20 import akka.actor.Props;
21 import akka.actor.UntypedActor; 21 import akka.actor.UntypedActor;
22 import akka.japi.Creator; 22 import akka.japi.Creator;
  23 +import com.google.common.collect.BiMap;
  24 +import com.google.common.collect.HashBiMap;
23 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
24 import org.thingsboard.server.actors.ActorSystemContext; 26 import org.thingsboard.server.actors.ActorSystemContext;
25 import org.thingsboard.server.actors.service.ContextAwareActor; 27 import org.thingsboard.server.actors.service.ContextAwareActor;
@@ -39,11 +41,11 @@ import java.util.Map; @@ -39,11 +41,11 @@ import java.util.Map;
39 public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> { 41 public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> {
40 42
41 protected final ActorSystemContext systemContext; 43 protected final ActorSystemContext systemContext;
42 - protected final Map<T, ActorRef> actors; 44 + protected final BiMap<T, ActorRef> actors;
43 45
44 public EntityActorsManager(ActorSystemContext systemContext) { 46 public EntityActorsManager(ActorSystemContext systemContext) {
45 this.systemContext = systemContext; 47 this.systemContext = systemContext;
46 - this.actors = new HashMap<>(); 48 + this.actors = HashBiMap.create();
47 } 49 }
48 50
49 protected abstract TenantId getTenantId(); 51 protected abstract TenantId getTenantId();
@@ -65,7 +67,8 @@ public abstract class EntityActorsManager<T extends EntityId, A extends UntypedA @@ -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 public ActorRef getOrCreateActor(ActorContext context, T entityId) { 73 public ActorRef getOrCreateActor(ActorContext context, T entityId) {
71 return actors.computeIfAbsent(entityId, eId -> 74 return actors.computeIfAbsent(entityId, eId ->
@@ -50,7 +50,7 @@ public abstract class RuleChainManager extends EntityActorsManager<RuleChainId, @@ -50,7 +50,7 @@ public abstract class RuleChainManager extends EntityActorsManager<RuleChainId,
50 50
51 @Override 51 @Override
52 public void visit(RuleChain entity, ActorRef actorRef) { 52 public void visit(RuleChain entity, ActorRef actorRef) {
53 - if (entity.isRoot()) { 53 + if (entity != null && entity.isRoot()) {
54 rootChain = entity; 54 rootChain = entity;
55 rootChainActor = actorRef; 55 rootChainActor = actorRef;
56 } 56 }
@@ -15,10 +15,9 @@ @@ -15,10 +15,9 @@
15 */ 15 */
16 package org.thingsboard.server.actors.stats; 16 package org.thingsboard.server.actors.stats;
17 17
18 -import akka.event.Logging;  
19 -import akka.event.LoggingAdapter;  
20 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
21 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
  20 +import lombok.extern.slf4j.Slf4j;
22 import org.thingsboard.server.actors.ActorSystemContext; 21 import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.actors.service.ContextAwareActor; 22 import org.thingsboard.server.actors.service.ContextAwareActor;
24 import org.thingsboard.server.actors.service.ContextBasedCreator; 23 import org.thingsboard.server.actors.service.ContextBasedCreator;
@@ -27,9 +26,9 @@ import org.thingsboard.server.common.data.Event; @@ -27,9 +26,9 @@ import org.thingsboard.server.common.data.Event;
27 import org.thingsboard.server.common.msg.TbActorMsg; 26 import org.thingsboard.server.common.msg.TbActorMsg;
28 import org.thingsboard.server.common.msg.cluster.ServerAddress; 27 import org.thingsboard.server.common.msg.cluster.ServerAddress;
29 28
  29 +@Slf4j
30 public class StatsActor extends ContextAwareActor { 30 public class StatsActor extends ContextAwareActor {
31 31
32 - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);  
33 private final ObjectMapper mapper = new ObjectMapper(); 32 private final ObjectMapper mapper = new ObjectMapper();
34 33
35 public StatsActor(ActorSystemContext context) { 34 public StatsActor(ActorSystemContext context) {
@@ -43,13 +42,13 @@ public class StatsActor extends ContextAwareActor { @@ -43,13 +42,13 @@ public class StatsActor extends ContextAwareActor {
43 } 42 }
44 43
45 @Override 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 if (msg instanceof StatsPersistMsg) { 47 if (msg instanceof StatsPersistMsg) {
49 try { 48 try {
50 onStatsPersistMsg((StatsPersistMsg) msg); 49 onStatsPersistMsg((StatsPersistMsg) msg);
51 } catch (Exception e) { 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,7 +74,7 @@ public class StatsActor extends ContextAwareActor {
75 } 74 }
76 75
77 @Override 76 @Override
78 - public StatsActor create() throws Exception { 77 + public StatsActor create() {
79 return new StatsActor(context); 78 return new StatsActor(context);
80 } 79 }
81 } 80 }
@@ -17,15 +17,19 @@ package org.thingsboard.server.actors.tenant; @@ -17,15 +17,19 @@ package org.thingsboard.server.actors.tenant;
17 17
18 import akka.actor.ActorInitializationException; 18 import akka.actor.ActorInitializationException;
19 import akka.actor.ActorRef; 19 import akka.actor.ActorRef;
  20 +import akka.actor.LocalActorRef;
20 import akka.actor.OneForOneStrategy; 21 import akka.actor.OneForOneStrategy;
21 import akka.actor.Props; 22 import akka.actor.Props;
22 import akka.actor.SupervisorStrategy; 23 import akka.actor.SupervisorStrategy;
  24 +import akka.actor.Terminated;
23 import akka.japi.Function; 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 import org.thingsboard.server.actors.ActorSystemContext; 29 import org.thingsboard.server.actors.ActorSystemContext;
25 -import org.thingsboard.server.actors.device.DeviceActor; 30 +import org.thingsboard.server.actors.device.DeviceActorCreator;
26 import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; 31 import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;
27 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; 32 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
28 -import org.thingsboard.server.actors.ruleChain.RuleChainToRuleChainMsg;  
29 import org.thingsboard.server.actors.service.ContextBasedCreator; 33 import org.thingsboard.server.actors.service.ContextBasedCreator;
30 import org.thingsboard.server.actors.service.DefaultActorService; 34 import org.thingsboard.server.actors.service.DefaultActorService;
31 import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager; 35 import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager;
@@ -33,6 +37,7 @@ import org.thingsboard.server.common.data.EntityType; @@ -33,6 +37,7 @@ import org.thingsboard.server.common.data.EntityType;
33 import org.thingsboard.server.common.data.id.DeviceId; 37 import org.thingsboard.server.common.data.id.DeviceId;
34 import org.thingsboard.server.common.data.id.RuleChainId; 38 import org.thingsboard.server.common.data.id.RuleChainId;
35 import org.thingsboard.server.common.data.id.TenantId; 39 import org.thingsboard.server.common.data.id.TenantId;
  40 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
36 import org.thingsboard.server.common.data.rule.RuleChain; 41 import org.thingsboard.server.common.data.rule.RuleChain;
37 import org.thingsboard.server.common.msg.TbActorMsg; 42 import org.thingsboard.server.common.msg.TbActorMsg;
38 import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; 43 import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
@@ -47,15 +52,14 @@ import java.util.Map; @@ -47,15 +52,14 @@ import java.util.Map;
47 public class TenantActor extends RuleChainManagerActor { 52 public class TenantActor extends RuleChainManagerActor {
48 53
49 private final TenantId tenantId; 54 private final TenantId tenantId;
50 - private final Map<DeviceId, ActorRef> deviceActors; 55 + private final BiMap<DeviceId, ActorRef> deviceActors;
51 56
52 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { 57 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) {
53 super(systemContext, new TenantRuleChainManager(systemContext, tenantId)); 58 super(systemContext, new TenantRuleChainManager(systemContext, tenantId));
54 this.tenantId = tenantId; 59 this.tenantId = tenantId;
55 - this.deviceActors = new HashMap<>(); 60 + this.deviceActors = HashBiMap.create();
56 } 61 }
57 62
58 -  
59 @Override 63 @Override
60 public SupervisorStrategy supervisorStrategy() { 64 public SupervisorStrategy supervisorStrategy() {
61 return strategy; 65 return strategy;
@@ -63,16 +67,21 @@ public class TenantActor extends RuleChainManagerActor { @@ -63,16 +67,21 @@ public class TenantActor extends RuleChainManagerActor {
63 67
64 @Override 68 @Override
65 public void preStart() { 69 public void preStart() {
66 - logger.info("[{}] Starting tenant actor.", tenantId); 70 + log.info("[{}] Starting tenant actor.", tenantId);
67 try { 71 try {
68 initRuleChains(); 72 initRuleChains();
69 - logger.info("[{}] Tenant actor started.", tenantId); 73 + log.info("[{}] Tenant actor started.", tenantId);
70 } catch (Exception e) { 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 @Override 79 @Override
  80 + public void postStop() {
  81 + log.info("[{}] Stopping tenant actor.", tenantId);
  82 + }
  83 +
  84 + @Override
76 protected boolean process(TbActorMsg msg) { 85 protected boolean process(TbActorMsg msg) {
77 switch (msg.getMsgType()) { 86 switch (msg.getMsgType()) {
78 case CLUSTER_EVENT_MSG: 87 case CLUSTER_EVENT_MSG:
@@ -87,7 +96,7 @@ public class TenantActor extends RuleChainManagerActor { @@ -87,7 +96,7 @@ public class TenantActor extends RuleChainManagerActor {
87 case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: 96 case DEVICE_ACTOR_TO_RULE_ENGINE_MSG:
88 onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); 97 onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg);
89 break; 98 break;
90 - case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: 99 + case TRANSPORT_TO_DEVICE_ACTOR_MSG:
91 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 100 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
92 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: 101 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
93 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: 102 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
@@ -105,29 +114,26 @@ public class TenantActor extends RuleChainManagerActor { @@ -105,29 +114,26 @@ public class TenantActor extends RuleChainManagerActor {
105 return true; 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 private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { 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 private void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg msg) { 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 private void onRuleChainMsg(RuleChainAwareMsg msg) { 133 private void onRuleChainMsg(RuleChainAwareMsg msg) {
127 ruleChainManager.getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self()); 134 ruleChainManager.getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self());
128 } 135 }
129 136
130 -  
131 private void onToDeviceActorMsg(DeviceAwareMsg msg) { 137 private void onToDeviceActorMsg(DeviceAwareMsg msg) {
132 getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); 138 getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender());
133 } 139 }
@@ -142,13 +148,35 @@ public class TenantActor extends RuleChainManagerActor { @@ -142,13 +148,35 @@ public class TenantActor extends RuleChainManagerActor {
142 } 148 }
143 target.tell(msg, ActorRef.noSender()); 149 target.tell(msg, ActorRef.noSender());
144 } else { 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 private ActorRef getOrCreateDeviceActor(DeviceId deviceId) { 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 public static class ActorCreator extends ContextBasedCreator<TenantActor> { 182 public static class ActorCreator extends ContextBasedCreator<TenantActor> {
@@ -162,7 +190,7 @@ public class TenantActor extends RuleChainManagerActor { @@ -162,7 +190,7 @@ public class TenantActor extends RuleChainManagerActor {
162 } 190 }
163 191
164 @Override 192 @Override
165 - public TenantActor create() throws Exception { 193 + public TenantActor create() {
166 return new TenantActor(context, tenantId); 194 return new TenantActor(context, tenantId);
167 } 195 }
168 } 196 }
@@ -170,8 +198,8 @@ public class TenantActor extends RuleChainManagerActor { @@ -170,8 +198,8 @@ public class TenantActor extends RuleChainManagerActor {
170 private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() { 198 private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() {
171 @Override 199 @Override
172 public SupervisorStrategy.Directive apply(Throwable t) { 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 return SupervisorStrategy.stop(); 203 return SupervisorStrategy.stop();
176 } else { 204 } else {
177 return SupervisorStrategy.resume(); 205 return SupervisorStrategy.resume();
@@ -83,7 +83,7 @@ public class AlarmController extends BaseController { @@ -83,7 +83,7 @@ public class AlarmController extends BaseController {
83 Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm)); 83 Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm));
84 logEntityAction(savedAlarm.getId(), savedAlarm, 84 logEntityAction(savedAlarm.getId(), savedAlarm,
85 getCurrentUser().getCustomerId(), 85 getCurrentUser().getCustomerId(),
86 - savedAlarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); 86 + alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
87 return savedAlarm; 87 return savedAlarm;
88 } catch (Exception e) { 88 } catch (Exception e) {
89 logEntityAction(emptyId(EntityType.ALARM), alarm, 89 logEntityAction(emptyId(EntityType.ALARM), alarm,
@@ -19,9 +19,11 @@ import com.datastax.driver.core.utils.UUIDs; @@ -19,9 +19,11 @@ import com.datastax.driver.core.utils.UUIDs;
19 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
20 import com.fasterxml.jackson.databind.node.ArrayNode; 20 import com.fasterxml.jackson.databind.node.ArrayNode;
21 import com.fasterxml.jackson.databind.node.ObjectNode; 21 import com.fasterxml.jackson.databind.node.ObjectNode;
  22 +import lombok.Getter;
22 import lombok.extern.slf4j.Slf4j; 23 import lombok.extern.slf4j.Slf4j;
23 import org.apache.commons.lang3.StringUtils; 24 import org.apache.commons.lang3.StringUtils;
24 import org.springframework.beans.factory.annotation.Autowired; 25 import org.springframework.beans.factory.annotation.Autowired;
  26 +import org.springframework.beans.factory.annotation.Value;
25 import org.springframework.security.core.Authentication; 27 import org.springframework.security.core.Authentication;
26 import org.springframework.security.core.context.SecurityContextHolder; 28 import org.springframework.security.core.context.SecurityContextHolder;
27 import org.springframework.web.bind.annotation.ExceptionHandler; 29 import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -48,14 +50,17 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle; @@ -48,14 +50,17 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
48 import org.thingsboard.server.common.msg.TbMsg; 50 import org.thingsboard.server.common.msg.TbMsg;
49 import org.thingsboard.server.common.msg.TbMsgDataType; 51 import org.thingsboard.server.common.msg.TbMsgDataType;
50 import org.thingsboard.server.common.msg.TbMsgMetaData; 52 import org.thingsboard.server.common.msg.TbMsgMetaData;
  53 +import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
51 import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; 54 import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
52 import org.thingsboard.server.dao.alarm.AlarmService; 55 import org.thingsboard.server.dao.alarm.AlarmService;
53 import org.thingsboard.server.dao.asset.AssetService; 56 import org.thingsboard.server.dao.asset.AssetService;
  57 +import org.thingsboard.server.dao.attributes.AttributesService;
54 import org.thingsboard.server.dao.audit.AuditLogService; 58 import org.thingsboard.server.dao.audit.AuditLogService;
55 import org.thingsboard.server.dao.customer.CustomerService; 59 import org.thingsboard.server.dao.customer.CustomerService;
56 import org.thingsboard.server.dao.dashboard.DashboardService; 60 import org.thingsboard.server.dao.dashboard.DashboardService;
57 import org.thingsboard.server.dao.device.DeviceCredentialsService; 61 import org.thingsboard.server.dao.device.DeviceCredentialsService;
58 import org.thingsboard.server.dao.device.DeviceService; 62 import org.thingsboard.server.dao.device.DeviceService;
  63 +import org.thingsboard.server.dao.entityview.EntityViewService;
59 import org.thingsboard.server.dao.exception.DataValidationException; 64 import org.thingsboard.server.dao.exception.DataValidationException;
60 import org.thingsboard.server.dao.exception.IncorrectParameterException; 65 import org.thingsboard.server.dao.exception.IncorrectParameterException;
61 import org.thingsboard.server.dao.model.ModelConstants; 66 import org.thingsboard.server.dao.model.ModelConstants;
@@ -69,6 +74,7 @@ import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; @@ -69,6 +74,7 @@ import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
69 import org.thingsboard.server.service.component.ComponentDiscoveryService; 74 import org.thingsboard.server.service.component.ComponentDiscoveryService;
70 import org.thingsboard.server.service.security.model.SecurityUser; 75 import org.thingsboard.server.service.security.model.SecurityUser;
71 import org.thingsboard.server.service.state.DeviceStateService; 76 import org.thingsboard.server.service.state.DeviceStateService;
  77 +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
72 78
73 import javax.mail.MessagingException; 79 import javax.mail.MessagingException;
74 import javax.servlet.http.HttpServletRequest; 80 import javax.servlet.http.HttpServletRequest;
@@ -139,6 +145,20 @@ public abstract class BaseController { @@ -139,6 +145,20 @@ public abstract class BaseController {
139 @Autowired 145 @Autowired
140 protected DeviceStateService deviceStateService; 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 @ExceptionHandler(ThingsboardException.class) 162 @ExceptionHandler(ThingsboardException.class)
143 public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { 163 public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) {
144 errorResponseHandler.handle(ex, response); 164 errorResponseHandler.handle(ex, response);
@@ -149,7 +169,7 @@ public abstract class BaseController { @@ -149,7 +169,7 @@ public abstract class BaseController {
149 } 169 }
150 170
151 private ThingsboardException handleException(Exception exception, boolean logException) { 171 private ThingsboardException handleException(Exception exception, boolean logException) {
152 - if (logException) { 172 + if (logException && logControllerErrorStackTrace) {
153 log.error("Error [{}]", exception.getMessage(), exception); 173 log.error("Error [{}]", exception.getMessage(), exception);
154 } 174 }
155 175
@@ -247,7 +267,6 @@ public abstract class BaseController { @@ -247,7 +267,6 @@ public abstract class BaseController {
247 267
248 Customer checkCustomerId(CustomerId customerId) throws ThingsboardException { 268 Customer checkCustomerId(CustomerId customerId) throws ThingsboardException {
249 try { 269 try {
250 - validateId(customerId, "Incorrect customerId " + customerId);  
251 SecurityUser authUser = getCurrentUser(); 270 SecurityUser authUser = getCurrentUser();
252 if (authUser.getAuthority() == Authority.SYS_ADMIN || 271 if (authUser.getAuthority() == Authority.SYS_ADMIN ||
253 (authUser.getAuthority() != Authority.TENANT_ADMIN && 272 (authUser.getAuthority() != Authority.TENANT_ADMIN &&
@@ -255,9 +274,13 @@ public abstract class BaseController { @@ -255,9 +274,13 @@ public abstract class BaseController {
255 throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION, 274 throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
256 ThingsboardErrorCode.PERMISSION_DENIED); 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 } catch (Exception e) { 284 } catch (Exception e) {
262 throw handleException(e, false); 285 throw handleException(e, false);
263 } 286 }
@@ -313,6 +336,9 @@ public abstract class BaseController { @@ -313,6 +336,9 @@ public abstract class BaseController {
313 case USER: 336 case USER:
314 checkUserId(new UserId(entityId.getId())); 337 checkUserId(new UserId(entityId.getId()));
315 return; 338 return;
  339 + case ENTITY_VIEW:
  340 + checkEntityViewId(new EntityViewId(entityId.getId()));
  341 + return;
316 default: 342 default:
317 throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); 343 throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType());
318 } 344 }
@@ -335,11 +361,26 @@ public abstract class BaseController { @@ -335,11 +361,26 @@ public abstract class BaseController {
335 protected void checkDevice(Device device) throws ThingsboardException { 361 protected void checkDevice(Device device) throws ThingsboardException {
336 checkNotNull(device); 362 checkNotNull(device);
337 checkTenantId(device.getTenantId()); 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 Asset checkAssetId(AssetId assetId) throws ThingsboardException { 384 Asset checkAssetId(AssetId assetId) throws ThingsboardException {
344 try { 385 try {
345 validateId(assetId, "Incorrect assetId " + assetId); 386 validateId(assetId, "Incorrect assetId " + assetId);
@@ -354,9 +395,7 @@ public abstract class BaseController { @@ -354,9 +395,7 @@ public abstract class BaseController {
354 protected void checkAsset(Asset asset) throws ThingsboardException { 395 protected void checkAsset(Asset asset) throws ThingsboardException {
355 checkNotNull(asset); 396 checkNotNull(asset);
356 checkTenantId(asset.getTenantId()); 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 Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException { 401 Alarm checkAlarmId(AlarmId alarmId) throws ThingsboardException {
@@ -465,8 +504,7 @@ public abstract class BaseController { @@ -465,8 +504,7 @@ public abstract class BaseController {
465 ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException { 504 ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException {
466 try { 505 try {
467 log.debug("[{}] Lookup component descriptor", clazz); 506 log.debug("[{}] Lookup component descriptor", clazz);
468 - ComponentDescriptor componentDescriptor = checkNotNull(componentDescriptorService.getComponent(clazz));  
469 - return componentDescriptor; 507 + return checkNotNull(componentDescriptorService.getComponent(clazz));
470 } catch (Exception e) { 508 } catch (Exception e) {
471 throw handleException(e, false); 509 throw handleException(e, false);
472 } 510 }
@@ -530,16 +568,16 @@ public abstract class BaseController { @@ -530,16 +568,16 @@ public abstract class BaseController {
530 } 568 }
531 569
532 protected <I extends EntityId> I emptyId(EntityType entityType) { 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 protected <E extends HasName, I extends EntityId> void logEntityAction(I entityId, E entity, CustomerId customerId, 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 logEntityAction(getCurrentUser(), entityId, entity, customerId, actionType, e, additionalInfo); 576 logEntityAction(getCurrentUser(), entityId, entity, customerId, actionType, e, additionalInfo);
539 } 577 }
540 578
541 protected <E extends HasName, I extends EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId, 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 if (customerId == null || customerId.isNullUid()) { 581 if (customerId == null || customerId.isNullUid()) {
544 customerId = user.getCustomerId(); 582 customerId = user.getCustomerId();
545 } 583 }
@@ -555,7 +593,7 @@ public abstract class BaseController { @@ -555,7 +593,7 @@ public abstract class BaseController {
555 } 593 }
556 594
557 private <E extends HasName, I extends EntityId> void pushEntityActionToRuleEngine(I entityId, E entity, User user, CustomerId customerId, 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 String msgType = null; 597 String msgType = null;
560 switch (actionType) { 598 switch (actionType) {
561 case ADDED: 599 case ADDED:
@@ -579,6 +617,12 @@ public abstract class BaseController { @@ -579,6 +617,12 @@ public abstract class BaseController {
579 case ATTRIBUTES_DELETED: 617 case ATTRIBUTES_DELETED:
580 msgType = DataConstants.ATTRIBUTES_DELETED; 618 msgType = DataConstants.ATTRIBUTES_DELETED;
581 break; 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 if (!StringUtils.isEmpty(msgType)) { 627 if (!StringUtils.isEmpty(msgType)) {
584 try { 628 try {
@@ -628,7 +672,7 @@ public abstract class BaseController { @@ -628,7 +672,7 @@ public abstract class BaseController {
628 String scope = extractParameter(String.class, 0, additionalInfo); 672 String scope = extractParameter(String.class, 0, additionalInfo);
629 List<String> keys = extractParameter(List.class, 1, additionalInfo); 673 List<String> keys = extractParameter(List.class, 1, additionalInfo);
630 metaData.putValue("scope", scope); 674 metaData.putValue("scope", scope);
631 - ArrayNode attrsArrayNode = entityNode.putArray("attributes"); 675 + ArrayNode attrsArrayNode = entityNode.putArray("attributes");
632 if (keys != null) { 676 if (keys != null) {
633 keys.forEach(attrsArrayNode::add); 677 keys.forEach(attrsArrayNode::add);
634 } 678 }
@@ -637,7 +681,7 @@ public abstract class BaseController { @@ -637,7 +681,7 @@ public abstract class BaseController {
637 TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), msgType, entityId, metaData, TbMsgDataType.JSON 681 TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), msgType, entityId, metaData, TbMsgDataType.JSON
638 , json.writeValueAsString(entityNode) 682 , json.writeValueAsString(entityNode)
639 , null, null, 0L); 683 , null, null, 0L);
640 - actorService.onMsg(new ServiceToRuleEngineMsg(user.getTenantId(), tbMsg)); 684 + actorService.onMsg(new SendToClusterMsg(entityId, new ServiceToRuleEngineMsg(user.getTenantId(), tbMsg)));
641 } catch (Exception e) { 685 } catch (Exception e) {
642 log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e); 686 log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e);
643 } 687 }
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
  18 +import lombok.Getter;
  19 +import org.springframework.beans.factory.annotation.Value;
18 import org.springframework.http.HttpStatus; 20 import org.springframework.http.HttpStatus;
19 import org.springframework.security.access.prepost.PreAuthorize; 21 import org.springframework.security.access.prepost.PreAuthorize;
20 import org.springframework.web.bind.annotation.PathVariable; 22 import org.springframework.web.bind.annotation.PathVariable;
@@ -49,6 +51,10 @@ public class DashboardController extends BaseController { @@ -49,6 +51,10 @@ public class DashboardController extends BaseController {
49 51
50 public static final String DASHBOARD_ID = "dashboardId"; 52 public static final String DASHBOARD_ID = "dashboardId";
51 53
  54 + @Value("${dashboard.max_datapoints_limit}")
  55 + private long maxDatapointsLimit;
  56 +
  57 +
52 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 58 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
53 @RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET) 59 @RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET)
54 @ResponseBody 60 @ResponseBody
@@ -57,6 +63,13 @@ public class DashboardController extends BaseController { @@ -57,6 +63,13 @@ public class DashboardController extends BaseController {
57 } 63 }
58 64
59 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 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 @RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET) 73 @RequestMapping(value = "/dashboard/info/{dashboardId}", method = RequestMethod.GET)
61 @ResponseBody 74 @ResponseBody
62 public DashboardInfo getDashboardInfoById(@PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { 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,7 +50,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
50 import org.thingsboard.server.common.msg.TbMsg; 50 import org.thingsboard.server.common.msg.TbMsg;
51 import org.thingsboard.server.common.msg.TbMsgMetaData; 51 import org.thingsboard.server.common.msg.TbMsgMetaData;
52 import org.thingsboard.server.dao.event.EventService; 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 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; 54 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
55 55
56 import java.util.List; 56 import java.util.List;
@@ -71,7 +71,7 @@ public class RuleChainController extends BaseController { @@ -71,7 +71,7 @@ public class RuleChainController extends BaseController {
71 private EventService eventService; 71 private EventService eventService;
72 72
73 @Autowired 73 @Autowired
74 - private JsSandboxService jsSandboxService; 74 + private JsInvokeService jsInvokeService;
75 75
76 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") 76 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
77 @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET) 77 @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
@@ -276,7 +276,7 @@ public class RuleChainController extends BaseController { @@ -276,7 +276,7 @@ public class RuleChainController extends BaseController {
276 String errorText = ""; 276 String errorText = "";
277 ScriptEngine engine = null; 277 ScriptEngine engine = null;
278 try { 278 try {
279 - engine = new RuleNodeJsScriptEngine(jsSandboxService, script, argNames); 279 + engine = new RuleNodeJsScriptEngine(jsInvokeService, getCurrentUser().getId(), script, argNames);
280 TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L); 280 TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L);
281 switch (scriptType) { 281 switch (scriptType) {
282 case "update": 282 case "update":
@@ -49,9 +49,11 @@ import org.thingsboard.server.common.data.kv.Aggregation; @@ -49,9 +49,11 @@ import org.thingsboard.server.common.data.kv.Aggregation;
49 import org.thingsboard.server.common.data.kv.AttributeKey; 49 import org.thingsboard.server.common.data.kv.AttributeKey;
50 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 50 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
51 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; 51 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
  52 +import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery;
52 import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; 53 import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
53 import org.thingsboard.server.common.data.kv.BasicTsKvEntry; 54 import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
54 import org.thingsboard.server.common.data.kv.BooleanDataEntry; 55 import org.thingsboard.server.common.data.kv.BooleanDataEntry;
  56 +import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
55 import org.thingsboard.server.common.data.kv.DoubleDataEntry; 57 import org.thingsboard.server.common.data.kv.DoubleDataEntry;
56 import org.thingsboard.server.common.data.kv.KvEntry; 58 import org.thingsboard.server.common.data.kv.KvEntry;
57 import org.thingsboard.server.common.data.kv.LongDataEntry; 59 import org.thingsboard.server.common.data.kv.LongDataEntry;
@@ -59,14 +61,11 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; @@ -59,14 +61,11 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
59 import org.thingsboard.server.common.data.kv.StringDataEntry; 61 import org.thingsboard.server.common.data.kv.StringDataEntry;
60 import org.thingsboard.server.common.data.kv.TsKvEntry; 62 import org.thingsboard.server.common.data.kv.TsKvEntry;
61 import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; 63 import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
62 -import org.thingsboard.server.common.msg.core.TelemetryUploadRequest;  
63 import org.thingsboard.server.common.transport.adaptor.JsonConverter; 64 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
64 -import org.thingsboard.server.dao.attributes.AttributesService;  
65 import org.thingsboard.server.dao.timeseries.TimeseriesService; 65 import org.thingsboard.server.dao.timeseries.TimeseriesService;
66 import org.thingsboard.server.service.security.AccessValidator; 66 import org.thingsboard.server.service.security.AccessValidator;
67 import org.thingsboard.server.service.security.model.SecurityUser; 67 import org.thingsboard.server.service.security.model.SecurityUser;
68 import org.thingsboard.server.service.telemetry.AttributeData; 68 import org.thingsboard.server.service.telemetry.AttributeData;
69 -import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;  
70 import org.thingsboard.server.service.telemetry.TsData; 69 import org.thingsboard.server.service.telemetry.TsData;
71 import org.thingsboard.server.service.telemetry.exception.InvalidParametersException; 70 import org.thingsboard.server.service.telemetry.exception.InvalidParametersException;
72 import org.thingsboard.server.service.telemetry.exception.UncheckedApiException; 71 import org.thingsboard.server.service.telemetry.exception.UncheckedApiException;
@@ -94,15 +93,9 @@ import java.util.stream.Collectors; @@ -94,15 +93,9 @@ import java.util.stream.Collectors;
94 public class TelemetryController extends BaseController { 93 public class TelemetryController extends BaseController {
95 94
96 @Autowired 95 @Autowired
97 - private AttributesService attributesService;  
98 -  
99 - @Autowired  
100 private TimeseriesService tsService; 96 private TimeseriesService tsService;
101 97
102 @Autowired 98 @Autowired
103 - private TelemetrySubscriptionService tsSubService;  
104 -  
105 - @Autowired  
106 private AccessValidator accessValidator; 99 private AccessValidator accessValidator;
107 100
108 private ExecutorService executor; 101 private ExecutorService executor;
@@ -257,6 +250,60 @@ public class TelemetryController extends BaseController { @@ -257,6 +250,60 @@ public class TelemetryController extends BaseController {
257 } 250 }
258 251
259 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 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 @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE) 307 @RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.DELETE)
261 @ResponseBody 308 @ResponseBody
262 public DeferredResult<ResponseEntity> deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr, 309 public DeferredResult<ResponseEntity> deleteEntityAttributes(@PathVariable("deviceId") String deviceIdStr,
@@ -352,7 +399,7 @@ public class TelemetryController extends BaseController { @@ -352,7 +399,7 @@ public class TelemetryController extends BaseController {
352 } 399 }
353 400
354 private DeferredResult<ResponseEntity> saveTelemetry(EntityId entityIdSrc, String requestBody, long ttl) throws ThingsboardException { 401 private DeferredResult<ResponseEntity> saveTelemetry(EntityId entityIdSrc, String requestBody, long ttl) throws ThingsboardException {
355 - TelemetryUploadRequest telemetryRequest; 402 + Map<Long, List<KvEntry>> telemetryRequest;
356 JsonElement telemetryJson; 403 JsonElement telemetryJson;
357 try { 404 try {
358 telemetryJson = new JsonParser().parse(requestBody); 405 telemetryJson = new JsonParser().parse(requestBody);
@@ -360,12 +407,12 @@ public class TelemetryController extends BaseController { @@ -360,12 +407,12 @@ public class TelemetryController extends BaseController {
360 return getImmediateDeferredResult("Unable to parse timeseries payload: Invalid JSON body!", HttpStatus.BAD_REQUEST); 407 return getImmediateDeferredResult("Unable to parse timeseries payload: Invalid JSON body!", HttpStatus.BAD_REQUEST);
361 } 408 }
362 try { 409 try {
363 - telemetryRequest = JsonConverter.convertToTelemetry(telemetryJson); 410 + telemetryRequest = JsonConverter.convertToTelemetry(telemetryJson, System.currentTimeMillis());
364 } catch (Exception e) { 411 } catch (Exception e) {
365 return getImmediateDeferredResult("Unable to parse timeseries payload. Invalid JSON body: " + e.getMessage(), HttpStatus.BAD_REQUEST); 412 return getImmediateDeferredResult("Unable to parse timeseries payload. Invalid JSON body: " + e.getMessage(), HttpStatus.BAD_REQUEST);
366 } 413 }
367 List<TsKvEntry> entries = new ArrayList<>(); 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 for (KvEntry kv : entry.getValue()) { 416 for (KvEntry kv : entry.getValue()) {
370 entries.add(new BasicTsKvEntry(entry.getKey(), kv)); 417 entries.add(new BasicTsKvEntry(entry.getKey(), kv));
371 } 418 }
@@ -513,6 +560,15 @@ public class TelemetryController extends BaseController { @@ -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 private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) { 572 private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) {
517 try { 573 try {
518 logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_DELETED, toException(e), 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,6 +32,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
32 import org.thingsboard.server.common.data.id.TenantId; 32 import org.thingsboard.server.common.data.id.TenantId;
33 import org.thingsboard.server.common.data.page.TextPageData; 33 import org.thingsboard.server.common.data.page.TextPageData;
34 import org.thingsboard.server.common.data.page.TextPageLink; 34 import org.thingsboard.server.common.data.page.TextPageLink;
  35 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
35 import org.thingsboard.server.dao.tenant.TenantService; 36 import org.thingsboard.server.dao.tenant.TenantService;
36 import org.thingsboard.server.service.install.InstallScripts; 37 import org.thingsboard.server.service.install.InstallScripts;
37 38
@@ -84,6 +85,8 @@ public class TenantController extends BaseController { @@ -84,6 +85,8 @@ public class TenantController extends BaseController {
84 try { 85 try {
85 TenantId tenantId = new TenantId(toUUID(strTenantId)); 86 TenantId tenantId = new TenantId(toUUID(strTenantId));
86 tenantService.deleteTenant(tenantId); 87 tenantService.deleteTenant(tenantId);
  88 +
  89 + actorService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED);
87 } catch (Exception e) { 90 } catch (Exception e) {
88 throw handleException(e); 91 throw handleException(e);
89 } 92 }
@@ -24,9 +24,10 @@ import org.springframework.context.annotation.Profile; @@ -24,9 +24,10 @@ import org.springframework.context.annotation.Profile;
24 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
25 import org.thingsboard.server.service.component.ComponentDiscoveryService; 25 import org.thingsboard.server.service.component.ComponentDiscoveryService;
26 import org.thingsboard.server.service.install.DataUpdateService; 26 import org.thingsboard.server.service.install.DataUpdateService;
27 -import org.thingsboard.server.service.install.DatabaseSchemaService;  
28 import org.thingsboard.server.service.install.DatabaseUpgradeService; 27 import org.thingsboard.server.service.install.DatabaseUpgradeService;
  28 +import org.thingsboard.server.service.install.EntityDatabaseSchemaService;
29 import org.thingsboard.server.service.install.SystemDataLoaderService; 29 import org.thingsboard.server.service.install.SystemDataLoaderService;
  30 +import org.thingsboard.server.service.install.TsDatabaseSchemaService;
30 31
31 @Service 32 @Service
32 @Profile("install") 33 @Profile("install")
@@ -43,7 +44,10 @@ public class ThingsboardInstallService { @@ -43,7 +44,10 @@ public class ThingsboardInstallService {
43 private Boolean loadDemo; 44 private Boolean loadDemo;
44 45
45 @Autowired 46 @Autowired
46 - private DatabaseSchemaService databaseSchemaService; 47 + private EntityDatabaseSchemaService entityDatabaseSchemaService;
  48 +
  49 + @Autowired
  50 + private TsDatabaseSchemaService tsDatabaseSchemaService;
47 51
48 @Autowired 52 @Autowired
49 private DatabaseUpgradeService databaseUpgradeService; 53 private DatabaseUpgradeService databaseUpgradeService;
@@ -88,6 +92,20 @@ public class ThingsboardInstallService { @@ -88,6 +92,20 @@ public class ThingsboardInstallService {
88 92
89 dataUpdateService.updateData("1.4.0"); 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 log.info("Updating system data..."); 109 log.info("Updating system data...");
92 110
93 systemDataLoaderService.deleteSystemWidgetBundle("charts"); 111 systemDataLoaderService.deleteSystemWidgetBundle("charts");
@@ -114,9 +132,13 @@ public class ThingsboardInstallService { @@ -114,9 +132,13 @@ public class ThingsboardInstallService {
114 132
115 log.info("Starting ThingsBoard Installation..."); 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 log.info("Loading system data..."); 143 log.info("Loading system data...");
122 144
@@ -19,7 +19,8 @@ import lombok.extern.slf4j.Slf4j; @@ -19,7 +19,8 @@ import lombok.extern.slf4j.Slf4j;
19 import org.springframework.beans.factory.annotation.Value; 19 import org.springframework.beans.factory.annotation.Value;
20 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
21 import org.springframework.util.Assert; 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 import javax.annotation.PostConstruct; 25 import javax.annotation.PostConstruct;
25 26
@@ -43,8 +44,7 @@ public class CurrentServerInstanceService implements ServerInstanceService { @@ -43,8 +44,7 @@ public class CurrentServerInstanceService implements ServerInstanceService {
43 public void init() { 44 public void init() {
44 Assert.hasLength(rpcHost, missingProperty("rpc.bind_host")); 45 Assert.hasLength(rpcHost, missingProperty("rpc.bind_host"));
45 Assert.notNull(rpcPort, missingProperty("rpc.bind_port")); 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 log.info("Current server instance: [{};{}]", self.getHost(), self.getPort()); 48 log.info("Current server instance: [{};{}]", self.getHost(), self.getPort());
49 } 49 }
50 50
@@ -30,8 +30,4 @@ public interface DiscoveryService { @@ -30,8 +30,4 @@ public interface DiscoveryService {
30 30
31 List<ServerInstance> getOtherServers(); 31 List<ServerInstance> getOtherServers();
32 32
33 - boolean addListener(DiscoveryServiceListener listener);  
34 -  
35 - boolean removeListener(DiscoveryServiceListener listener);  
36 -  
37 } 33 }
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.service.cluster.discovery; 16 package org.thingsboard.server.service.cluster.discovery;
17 17
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.apache.commons.lang3.RandomStringUtils;
19 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 21 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
21 import org.springframework.context.annotation.DependsOn; 22 import org.springframework.context.annotation.DependsOn;
@@ -62,13 +63,5 @@ public class DummyDiscoveryService implements DiscoveryService { @@ -62,13 +63,5 @@ public class DummyDiscoveryService implements DiscoveryService {
62 return Collections.emptyList(); 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,7 +19,6 @@ import lombok.EqualsAndHashCode;
19 import lombok.Getter; 19 import lombok.Getter;
20 import lombok.ToString; 20 import lombok.ToString;
21 import org.thingsboard.server.common.msg.cluster.ServerAddress; 21 import org.thingsboard.server.common.msg.cluster.ServerAddress;
22 -import org.thingsboard.server.gen.discovery.ServerInstanceProtos;  
23 22
24 /** 23 /**
25 * @author Andrew Shvayka 24 * @author Andrew Shvayka
@@ -41,12 +40,6 @@ public final class ServerInstance implements Comparable<ServerInstance> { @@ -41,12 +40,6 @@ public final class ServerInstance implements Comparable<ServerInstance> {
41 this.port = serverAddress.getPort(); 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 @Override 43 @Override
51 public int compareTo(ServerInstance o) { 44 public int compareTo(ServerInstance o) {
52 return this.serverAddress.compareTo(o.serverAddress); 45 return this.serverAddress.compareTo(o.serverAddress);