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