Commit 2c02406ee5f41b08e655b634dd9871403f67149d

Authored by Andrew Shvayka
Committed by GitHub
1 parent a868f006

Merge with master. AlarmRepository.findAlarms is failing (#2663)

* Merge with master. AlarmRepository.findAlarms is failing

* Fix Alarm repository. Add queue type list select.

Co-authored-by: Igor Kulikov <ikulikov@thingsboard.io>
Showing 26 changed files with 2456 additions and 1316 deletions

Too many changes to show.

To preserve performance only 26 of 471 files are displayed.

  1 +{
  2 + "title": "Gateways",
  3 + "configuration": {
  4 + "widgets": {
  5 + "94715984-ae74-76e4-20b7-2f956b01ed80": {
  6 + "isSystemType": true,
  7 + "bundleAlias": "entity_admin_widgets",
  8 + "typeAlias": "device_admin_table2",
  9 + "type": "latest",
  10 + "title": "New widget",
  11 + "sizeX": 24,
  12 + "sizeY": 12,
  13 + "config": {
  14 + "timewindow": {
  15 + "realtime": {
  16 + "interval": 1000,
  17 + "timewindowMs": 86400000
  18 + },
  19 + "aggregation": {
  20 + "type": "NONE",
  21 + "limit": 200
  22 + }
  23 + },
  24 + "showTitle": true,
  25 + "backgroundColor": "rgb(255, 255, 255)",
  26 + "color": "rgba(0, 0, 0, 0.87)",
  27 + "padding": "4px",
  28 + "settings": {
  29 + "enableSearch": true,
  30 + "displayPagination": true,
  31 + "defaultPageSize": 10,
  32 + "defaultSortOrder": "entityName",
  33 + "displayEntityName": true,
  34 + "displayEntityType": false,
  35 + "entitiesTitle": "List of gateways",
  36 + "enableSelectColumnDisplay": true,
  37 + "displayEntityLabel": false,
  38 + "entityNameColumnTitle": "Gateway Name"
  39 + },
  40 + "title": "Devices gateway table",
  41 + "dropShadow": true,
  42 + "enableFullscreen": true,
  43 + "titleStyle": {
  44 + "fontSize": "16px",
  45 + "fontWeight": 400,
  46 + "padding": "5px 10px 5px 10px"
  47 + },
  48 + "useDashboardTimewindow": false,
  49 + "showLegend": false,
  50 + "datasources": [
  51 + {
  52 + "type": "entity",
  53 + "dataKeys": [
  54 + {
  55 + "name": "active",
  56 + "type": "attribute",
  57 + "label": "Active",
  58 + "color": "#2196f3",
  59 + "settings": {
  60 + "columnWidth": "0px",
  61 + "useCellStyleFunction": true,
  62 + "useCellContentFunction": true,
  63 + "cellContentFunction": "value = '&#11044;';\nreturn value;",
  64 + "cellStyleFunction": "var color;\nif (value == 'false') {\n color = '#EB5757';\n} else {\n color = '#27AE60';\n}\nreturn {\n color: color,\n fontSize: '18px'\n};"
  65 + },
  66 + "_hash": 0.3646047595211721
  67 + },
  68 + {
  69 + "name": "eventsSent",
  70 + "type": "timeseries",
  71 + "label": "Sent",
  72 + "color": "#4caf50",
  73 + "settings": {
  74 + "columnWidth": "0px",
  75 + "useCellStyleFunction": false,
  76 + "useCellContentFunction": false
  77 + },
  78 + "_hash": 0.7235710720767985
  79 + },
  80 + {
  81 + "name": "eventsProduced",
  82 + "type": "timeseries",
  83 + "label": "Events",
  84 + "color": "#f44336",
  85 + "settings": {
  86 + "columnWidth": "0px",
  87 + "useCellStyleFunction": false,
  88 + "useCellContentFunction": false
  89 + },
  90 + "_hash": 0.5085933386303254
  91 + },
  92 + {
  93 + "name": "LOGS",
  94 + "type": "timeseries",
  95 + "label": "Latest log",
  96 + "color": "#ffc107",
  97 + "settings": {
  98 + "columnWidth": "0px",
  99 + "useCellStyleFunction": false,
  100 + "useCellContentFunction": false
  101 + },
  102 + "_hash": 0.3504240371585048,
  103 + "postFuncBody": "if(value) {\n return value.substring(0, 31) + \"...\";\n} else {\n return '';\n}"
  104 + },
  105 + {
  106 + "name": "RemoteLoggingLevel",
  107 + "type": "attribute",
  108 + "label": "Log level",
  109 + "color": "#607d8b",
  110 + "settings": {
  111 + "columnWidth": "0px",
  112 + "useCellStyleFunction": false,
  113 + "useCellContentFunction": false
  114 + },
  115 + "_hash": 0.9785994222542516
  116 + }
  117 + ],
  118 + "entityAliasId": "3e0f533a-0db1-3292-184f-06e73535061a"
  119 + }
  120 + ],
  121 + "showTitleIcon": true,
  122 + "titleIcon": "list",
  123 + "iconColor": "rgba(0, 0, 0, 0.87)",
  124 + "iconSize": "24px",
  125 + "titleTooltip": "List device",
  126 + "widgetStyle": {},
  127 + "displayTimewindow": true,
  128 + "actions": {
  129 + "headerButton": [
  130 + {
  131 + "id": "70837a9d-c3de-a9a7-03c5-dccd14998758",
  132 + "name": "Add device",
  133 + "icon": "add",
  134 + "type": "customPretty",
  135 + "customHtml": "<md-dialog aria-label=\"Add entity\" style=\"width: 480px\">\n <form name=\"addDeviceForm\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Add device</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-progress-linear class=\"md-warn\" md-mode=\"indeterminate\" ng-disabled=\"!$root.loading && !vm.loading\" ng-show=\"$root.loading || vm.loading\"></md-progress-linear>\n <span style=\"min-height: 5px;\" flex=\"\" ng-show=\"!$root.loading && !vm.loading\"></span>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <fieldset ng-disabled=\"$root.loading || vm.loading\">\n <md-input-container flex class=\"md-block\">\n <label>Device name</label>\n <input ng-model=\"vm.deviceName\" name=deviceName required>\n <div ng-messages=\"addDeviceForm.deviceName.$error\">\n <div ng-message=\"required\">Device name is required.</div>\n </div>\n </md-input-container>\n <div flex layout=\"row\">\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Latitude</label>\n <input type=\"number\" step=\"any\" name=\"latitude\" ng-model=\"vm.attributes.latitude\">\n </md-input-container>\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Longitude</label>\n <input type=\"number\" step=\"any\" name=\"longitude\" ng-model=\"vm.attributes.longitude\">\n </md-input-container>\n </div>\n <md-input-container class=\"md-block\">\n <label>Label</label>\n <input name=\"deviceLabel\" ng-model=\"vm.deviceLabel\">\n </md-input-container>\n </fieldset>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"vm.loading || addDeviceForm.$invalid || !addDeviceForm.$dirty\" class=\"md-raised md-primary\">Create</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>\n",
  136 + "customCss": "",
  137 + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n $q = $injector.get('$q'),\n $rootScope = $injector.get('$rootScope'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n attributeService = $injector.get('attributeService');\n\nopenAddDeviceDialog();\n\nfunction openAddDeviceDialog() {\n $mdDialog.show({\n controller: ['$scope', '$mdDialog',\n AddDeviceDialogController\n ],\n controllerAs: 'vm',\n template: htmlTemplate,\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction AddDeviceDialogController($scope, $mdDialog) {\n let vm = this;\n vm.types = types;\n vm.attributes = {};\n vm.deviceType = \"gateway\";\n\n vm.cancel = () => {\n $mdDialog.hide();\n };\n\n vm.save = () => {\n vm.loading = true;\n $scope.addDeviceForm.$setPristine();\n let device = {\n additionalInfo: {gateway: true},\n name: vm.deviceName,\n type: vm.deviceType,\n label: vm.deviceLabel\n };\n deviceService.saveDevice(device).then(\n (device) => {\n saveAttributes(device.id).then(\n () => {\n vm.loading = false;\n updateAliasData();\n $mdDialog.hide();\n }\n );\n },\n () => {\n vm.loading = false;\n }\n );\n };\n\n function saveAttributes(entityId) {\n let attributesArray = [];\n for (let key in vm.attributes) {\n attributesArray.push({\n key: key,\n value: vm.attributes[key]\n });\n }\n if (attributesArray.length > 0) {\n return attributeService.saveEntityAttributes(\n entityId.entityType, entityId.id,\n \"SERVER_SCOPE\", attributesArray);\n } else {\n return $q.when([]);\n }\n }\n\n function updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController\n .resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController\n .setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController\n .getAliasInfo(aliasId));\n });\n $q.all(tasks).then(() => {\n $rootScope.$broadcast(\n 'widgetForceReInit');\n });\n }\n}"
  138 + }
  139 + ],
  140 + "actionCellButton": [
  141 + {
  142 + "id": "78845501-234e-a452-6819-82b5b776e99f",
  143 + "name": "Configuration",
  144 + "icon": "settings",
  145 + "type": "openDashboardState",
  146 + "targetDashboardStateId": "__entityname__config",
  147 + "openRightLayout": false,
  148 + "setEntityId": true
  149 + },
  150 + {
  151 + "id": "f6ffdba8-e40f-2b8d-851b-f5ecaf18606b",
  152 + "name": "Graphs",
  153 + "icon": "show_chart",
  154 + "type": "openDashboardState",
  155 + "targetDashboardStateId": "__entityname_grafic",
  156 + "setEntityId": true
  157 + },
  158 + {
  159 + "id": "242671f3-76c6-6982-7acc-6f12addf0ccc",
  160 + "name": "Edit device",
  161 + "icon": "edit",
  162 + "type": "customPretty",
  163 + "customHtml": "<md-dialog aria-label=\"Edit entity\" style=\"width: 480px\">\n <form name=\"editDeviceForm\" ng-submit=\"vm.save()\">\n <md-toolbar>\n <div class=\"md-toolbar-tools\">\n <h2>Edit device</h2>\n <span flex></span>\n <md-button class=\"md-icon-button\" ng-click=\"vm.cancel()\">\n <ng-md-icon icon=\"close\" aria-label=\"Close\"></ng-md-icon>\n </md-button>\n </div>\n </md-toolbar>\n <md-progress-linear class=\"md-warn\" md-mode=\"indeterminate\" ng-disabled=\"!$root.loading && !vm.loading\" ng-show=\"$root.loading || vm.loading\"></md-progress-linear>\n <span style=\"min-height: 5px;\" flex=\"\" ng-show=\"!$root.loading && !vm.loading\"></span>\n <md-dialog-content>\n <div class=\"md-dialog-content\">\n <fieldset ng-disabled=\"$root.loading || vm.loading\">\n <md-input-container flex class=\"md-block\">\n <label>Device name</label>\n <input ng-model=\"vm.device.name\" name=deviceName required>\n <div ng-messages=\"editDeviceForm.deviceName.$error\">\n <div ng-message=\"required\">Device name is required.</div>\n </div>\n </md-input-container>\n <!--<div flex layout=\"row\">-->\n <!--<tb-entity-subtype-autocomplete flex=\"50\"-->\n <!-- ng-disabled=\"true\"-->\n <!-- tb-required=\"true\"-->\n <!-- the-form=\"editDeviceForm\"-->\n <!-- ng-model=\"vm.device.type\"-->\n <!-- entity-type=\"vm.types.entityType.device\">-->\n <!--</tb-entity-subtype-autocomplete>-->\n <!-- <md-input-container flex=\"50\" class=\"md-block\">-->\n <!-- <label>Label</label>-->\n <!-- <input name=\"deviceLabel\" ng-model=\"vm.device.label\">-->\n <!-- </md-input-container>-->\n <!--</div>-->\n <div flex layout=\"row\">\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Latitude</label>\n <input type=\"number\" step=\"any\" name=\"latitude\" ng-model=\"vm.attributes.latitude\">\n </md-input-container>\n <md-input-container flex=\"50\" class=\"md-block\">\n <label>Longitude</label>\n <input type=\"number\" step=\"any\" name=\"longitude\" ng-model=\"vm.attributes.longitude\">\n </md-input-container>\n </div>\n <md-input-container class=\"md-block\">\n <label>Label</label>\n <input name=\"deviceLabel\" ng-model=\"vm.device.label\">\n </md-input-container>\n </fieldset>\n </div>\n </md-dialog-content>\n <md-dialog-actions>\n <md-button type=\"submit\" ng-disabled=\"vm.loading || editDeviceForm.$invalid || !editDeviceForm.$dirty\" class=\"md-raised md-primary\">Create</md-button>\n <md-button ng-click=\"vm.cancel()\" class=\"md-primary\">Cancel</md-button>\n </md-dialog-actions>\n </form>\n</md-dialog>",
  164 + "customCss": "/*=======================================================================*/\n/*========== There are two examples: for edit and add entity ==========*/\n/*=======================================================================*/\n/*======================== Edit entity example ========================*/\n/*=======================================================================*/\n/*\n.edit-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.edit-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.edit-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n\n.relations-list .header {\n padding-right: 5px;\n padding-bottom: 5px;\n padding-left: 5px;\n}\n\n.relations-list .header .cell {\n padding-right: 5px;\n padding-left: 5px;\n font-size: 12px;\n font-weight: 700;\n color: rgba(0, 0, 0, .54);\n white-space: nowrap;\n}\n\n.relations-list .body {\n padding-right: 5px;\n padding-bottom: 15px;\n padding-left: 5px;\n}\n\n.relations-list .body .row {\n padding-top: 5px;\n}\n\n.relations-list .body .cell {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.relations-list .body md-autocomplete-wrap md-input-container {\n height: 30px;\n}\n\n.relations-list .body .md-button {\n margin: 0;\n}\n\n.relations-list.old-relations tb-entity-select tb-entity-autocomplete button {\n display: none;\n} \n*/\n/*========================================================================*/\n/*========================= Add entity example =========================*/\n/*========================================================================*/\n/*\n.add-entity-form md-input-container {\n padding-right: 10px;\n}\n\n.add-entity-form .boolean-value-input {\n padding-left: 5px;\n}\n\n.add-entity-form .boolean-value-input .checkbox-label {\n margin-bottom: 8px;\n color: rgba(0,0,0,0.54);\n font-size: 12px;\n}\n\n.relations-list .header {\n padding-right: 5px;\n padding-bottom: 5px;\n padding-left: 5px;\n}\n\n.relations-list .header .cell {\n padding-right: 5px;\n padding-left: 5px;\n font-size: 12px;\n font-weight: 700;\n color: rgba(0, 0, 0, .54);\n white-space: nowrap;\n}\n\n.relations-list .body {\n padding-right: 5px;\n padding-bottom: 15px;\n padding-left: 5px;\n}\n\n.relations-list .body .row {\n padding-top: 5px;\n}\n\n.relations-list .body .cell {\n padding-right: 5px;\n padding-left: 5px;\n}\n\n.relations-list .body md-autocomplete-wrap md-input-container {\n height: 30px;\n}\n\n.relations-list .body .md-button {\n margin: 0;\n}\n*/\n",
  165 + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n $q = $injector.get('$q'),\n $rootScope = $injector.get('$rootScope'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n attributeService = $injector.get('attributeService');\n \nopenEditDeviceDialog();\n\nfunction openEditDeviceDialog() {\n $mdDialog.show({\n controller: ['$scope','$mdDialog', EditDeviceDialogController],\n controllerAs: 'vm',\n template: htmlTemplate,\n parent: angular.element($document[0].body),\n targetEvent: $event,\n multiple: true,\n clickOutsideToClose: false\n });\n}\n\nfunction EditDeviceDialogController($scope,$mdDialog) {\n let vm = this;\n vm.types = types;\n vm.loading = false;\n vm.attributes = {};\n \n getEntityInfo();\n \n function getEntityInfo() {\n vm.loading = true;\n deviceService.getDevice(entityId.id).then(\n (device) => {\n attributeService.getEntityAttributesValues(entityId.entityType, entityId.id, 'SERVER_SCOPE').then(\n (data) => {\n if (data.length) {\n getEntityAttributes(data);\n }\n vm.device = device;\n vm.loading = false;\n } \n );\n }\n )\n }\n \n vm.cancel = function() {\n $mdDialog.hide();\n };\n \n vm.save = () => {\n vm.loading = true;\n $scope.editDeviceForm.$setPristine();\n deviceService.saveDevice(vm.device).then(\n () => {\n saveAttributes().then(\n () => {\n updateAliasData();\n vm.loading = false;\n $mdDialog.hide();\n }\n );\n },\n () => {\n vm.loading = false;\n }\n );\n }\n \n function getEntityAttributes(attributes) {\n for (let i = 0; i < attributes.length; i++) {\n vm.attributes[attributes[i].key] = attributes[i].value; \n }\n }\n \n function saveAttributes() {\n let attributesArray = [];\n for (let key in vm.attributes) {\n attributesArray.push({key: key, value: vm.attributes[key]});\n }\n if (attributesArray.length > 0) {\n return attributeService.saveEntityAttributes(entityId.entityType, entityId.id, \"SERVER_SCOPE\", attributesArray);\n } else {\n return $q.when([]);\n }\n }\n \n function updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n console.log(widgetContext);\n $q.all(tasks).then(() => {\n $rootScope.$broadcast('widgetForceReInit');\n });\n }\n}\n"
  166 + },
  167 + {
  168 + "id": "862ec2b7-fbcf-376e-f85f-b77c07f36efa",
  169 + "name": "Delete device",
  170 + "icon": "delete",
  171 + "type": "custom",
  172 + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet $mdDialog = $injector.get('$mdDialog'),\n $document = $injector.get('$document'),\n types = $injector.get('types'),\n deviceService = $injector.get('deviceService'),\n $rootScope = $injector.get('$rootScope'),\n $q = $injector.get('$q');\n\nopenDeleteDeviceDialog();\n\nfunction openDeleteDeviceDialog() {\n let title = \"Are you sure you want to delete the device \" + entityName + \"?\";\n let content = \"Be careful, after the confirmation, the device and all related data will become unrecoverable!\";\n let confirm = $mdDialog.confirm()\n .targetEvent($event)\n .title(title)\n .htmlContent(content)\n .ariaLabel(title)\n .cancel('Cancel')\n .ok('Delete');\n $mdDialog.show(confirm).then(() => {\n deleteDevice();\n })\n}\n\nfunction deleteDevice() {\n deviceService.deleteDevice(entityId.id).then(\n () => {\n updateAliasData();\n }\n );\n}\n\nfunction updateAliasData() {\n let aliasIds = [];\n for (let id in widgetContext.aliasController.resolvedAliases) {\n aliasIds.push(id);\n }\n let tasks = [];\n aliasIds.forEach((aliasId) => {\n widgetContext.aliasController.setAliasUnresolved(aliasId);\n tasks.push(widgetContext.aliasController.getAliasInfo(aliasId));\n });\n $q.all(tasks).then(() => {\n $rootScope.$broadcast('entityAliasesChanged', aliasIds);\n });\n}"
  173 + }
  174 + ],
  175 + "rowClick": [
  176 + {
  177 + "id": "ad5fc7e1-5e60-e056-6940-a75a383466a1",
  178 + "name": "to_entityname__config",
  179 + "icon": "more_horiz",
  180 + "type": "openDashboardState",
  181 + "targetDashboardStateId": "__entityname__config",
  182 + "setEntityId": true,
  183 + "stateEntityParamName": ""
  184 + }
  185 + ]
  186 + }
  187 + },
  188 + "id": "94715984-ae74-76e4-20b7-2f956b01ed80"
  189 + },
  190 + "eadabbc7-519e-76fc-ba10-b3fe8c18da10": {
  191 + "isSystemType": true,
  192 + "bundleAlias": "cards",
  193 + "typeAlias": "timeseries_table",
  194 + "type": "timeseries",
  195 + "title": "New widget",
  196 + "sizeX": 14,
  197 + "sizeY": 13,
  198 + "config": {
  199 + "datasources": [
  200 + {
  201 + "type": "entity",
  202 + "dataKeys": [
  203 + {
  204 + "name": "LOGS",
  205 + "type": "timeseries",
  206 + "label": "LOGS",
  207 + "color": "#2196f3",
  208 + "settings": {
  209 + "useCellStyleFunction": false,
  210 + "useCellContentFunction": false
  211 + },
  212 + "_hash": 0.3496649158709739,
  213 + "postFuncBody": "return value.replace(/ - (.*) - \\[/gi, ' - <b style=\"color:#0f0;\">$1</b> - [');"
  214 + }
  215 + ],
  216 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  217 + }
  218 + ],
  219 + "timewindow": {
  220 + "realtime": {
  221 + "interval": 1000,
  222 + "timewindowMs": 2592000000
  223 + },
  224 + "aggregation": {
  225 + "type": "NONE",
  226 + "limit": 200
  227 + }
  228 + },
  229 + "showTitle": true,
  230 + "backgroundColor": "rgb(255, 255, 255)",
  231 + "color": "rgba(0, 0, 0, 0.87)",
  232 + "padding": "8px",
  233 + "settings": {
  234 + "showTimestamp": true,
  235 + "displayPagination": true,
  236 + "defaultPageSize": 10
  237 + },
  238 + "title": "Debug events (logs)",
  239 + "dropShadow": true,
  240 + "enableFullscreen": true,
  241 + "titleStyle": {
  242 + "fontSize": "16px",
  243 + "fontWeight": 400
  244 + },
  245 + "useDashboardTimewindow": false,
  246 + "showLegend": false,
  247 + "widgetStyle": {},
  248 + "actions": {},
  249 + "showTitleIcon": false,
  250 + "titleIcon": null,
  251 + "iconColor": "rgba(0, 0, 0, 0.87)",
  252 + "iconSize": "24px",
  253 + "titleTooltip": "",
  254 + "displayTimewindow": true
  255 + },
  256 + "id": "eadabbc7-519e-76fc-ba10-b3fe8c18da10"
  257 + },
  258 + "f928afc4-30d1-8d0c-e3cf-777f9f9d1155": {
  259 + "isSystemType": true,
  260 + "bundleAlias": "charts",
  261 + "typeAlias": "basic_timeseries",
  262 + "type": "timeseries",
  263 + "title": "New widget",
  264 + "sizeX": 17,
  265 + "sizeY": 4,
  266 + "config": {
  267 + "datasources": [
  268 + {
  269 + "type": "entity",
  270 + "dataKeys": [
  271 + {
  272 + "name": "opcuaEventsProduced",
  273 + "type": "timeseries",
  274 + "label": "opcuaEventsProduced",
  275 + "color": "#2196f3",
  276 + "settings": {
  277 + "excludeFromStacking": false,
  278 + "hideDataByDefault": false,
  279 + "disableDataHiding": false,
  280 + "removeFromLegend": false,
  281 + "showLines": true,
  282 + "fillLines": false,
  283 + "showPoints": false,
  284 + "showPointShape": "circle",
  285 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  286 + "showPointsLineWidth": 5,
  287 + "showPointsRadius": 3,
  288 + "tooltipValueFormatter": "",
  289 + "showSeparateAxis": false,
  290 + "axisTitle": "",
  291 + "axisPosition": "left",
  292 + "axisTicksFormatter": "",
  293 + "comparisonSettings": {
  294 + "showValuesForComparison": true,
  295 + "comparisonValuesLabel": "",
  296 + "color": ""
  297 + }
  298 + },
  299 + "_hash": 0.1477920581839779
  300 + },
  301 + {
  302 + "name": "opcuaEventsSent",
  303 + "type": "timeseries",
  304 + "label": "opcuaEventsSent",
  305 + "color": "#4caf50",
  306 + "settings": {
  307 + "excludeFromStacking": false,
  308 + "hideDataByDefault": false,
  309 + "disableDataHiding": false,
  310 + "removeFromLegend": false,
  311 + "showLines": true,
  312 + "fillLines": false,
  313 + "showPoints": false,
  314 + "showPointShape": "circle",
  315 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  316 + "showPointsLineWidth": 5,
  317 + "showPointsRadius": 3,
  318 + "tooltipValueFormatter": "",
  319 + "showSeparateAxis": false,
  320 + "axisTitle": "",
  321 + "axisPosition": "left",
  322 + "axisTicksFormatter": "",
  323 + "comparisonSettings": {
  324 + "showValuesForComparison": true,
  325 + "comparisonValuesLabel": "",
  326 + "color": ""
  327 + }
  328 + },
  329 + "_hash": 0.6500957113784758
  330 + }
  331 + ],
  332 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  333 + }
  334 + ],
  335 + "timewindow": {
  336 + "realtime": {
  337 + "interval": 1000,
  338 + "timewindowMs": 120000
  339 + },
  340 + "aggregation": {
  341 + "type": "NONE",
  342 + "limit": 25000
  343 + },
  344 + "hideInterval": false,
  345 + "hideAggregation": false
  346 + },
  347 + "showTitle": true,
  348 + "backgroundColor": "#fff",
  349 + "color": "rgba(0, 0, 0, 0.87)",
  350 + "padding": "8px",
  351 + "settings": {
  352 + "shadowSize": 4,
  353 + "fontColor": "#545454",
  354 + "fontSize": 10,
  355 + "xaxis": {
  356 + "showLabels": true,
  357 + "color": "#545454"
  358 + },
  359 + "yaxis": {
  360 + "showLabels": true,
  361 + "color": "#545454"
  362 + },
  363 + "grid": {
  364 + "color": "#545454",
  365 + "tickColor": "#DDDDDD",
  366 + "verticalLines": true,
  367 + "horizontalLines": true,
  368 + "outlineWidth": 1
  369 + },
  370 + "stack": false,
  371 + "tooltipIndividual": false,
  372 + "timeForComparison": "months",
  373 + "xaxisSecond": {
  374 + "axisPosition": "top",
  375 + "showLabels": true
  376 + }
  377 + },
  378 + "title": "Real time information",
  379 + "dropShadow": true,
  380 + "enableFullscreen": true,
  381 + "titleStyle": {
  382 + "fontSize": "16px",
  383 + "fontWeight": 400
  384 + },
  385 + "mobileHeight": null,
  386 + "showTitleIcon": false,
  387 + "titleIcon": null,
  388 + "iconColor": "rgba(0, 0, 0, 0.87)",
  389 + "iconSize": "24px",
  390 + "titleTooltip": "",
  391 + "widgetStyle": {},
  392 + "useDashboardTimewindow": false,
  393 + "displayTimewindow": true,
  394 + "showLegend": true,
  395 + "legendConfig": {
  396 + "direction": "column",
  397 + "position": "right",
  398 + "showMin": true,
  399 + "showMax": true,
  400 + "showAvg": true,
  401 + "showTotal": true
  402 + },
  403 + "actions": {}
  404 + },
  405 + "id": "f928afc4-30d1-8d0c-e3cf-777f9f9d1155"
  406 + },
  407 + "2a95b473-042d-59d0-2da2-40d0cccb6c8a": {
  408 + "isSystemType": true,
  409 + "bundleAlias": "cards",
  410 + "typeAlias": "timeseries_table",
  411 + "type": "timeseries",
  412 + "title": "New widget",
  413 + "sizeX": 7,
  414 + "sizeY": 7,
  415 + "config": {
  416 + "datasources": [
  417 + {
  418 + "type": "entity",
  419 + "dataKeys": [
  420 + {
  421 + "name": "eventsSent",
  422 + "type": "timeseries",
  423 + "label": "Events",
  424 + "color": "#2196f3",
  425 + "settings": {
  426 + "useCellStyleFunction": false,
  427 + "useCellContentFunction": false
  428 + },
  429 + "_hash": 0.8156044798125357
  430 + },
  431 + {
  432 + "name": "eventsProduced",
  433 + "type": "timeseries",
  434 + "label": "Produced",
  435 + "color": "#4caf50",
  436 + "settings": {
  437 + "useCellStyleFunction": false,
  438 + "useCellContentFunction": false
  439 + },
  440 + "_hash": 0.6538259344015449
  441 + }
  442 + ],
  443 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  444 + }
  445 + ],
  446 + "timewindow": {
  447 + "realtime": {
  448 + "interval": 1000,
  449 + "timewindowMs": 604800000
  450 + },
  451 + "aggregation": {
  452 + "type": "NONE",
  453 + "limit": 200
  454 + }
  455 + },
  456 + "showTitle": true,
  457 + "backgroundColor": "rgb(255, 255, 255)",
  458 + "color": "rgba(0, 0, 0, 0.87)",
  459 + "padding": "8px",
  460 + "settings": {
  461 + "showTimestamp": true,
  462 + "displayPagination": true,
  463 + "defaultPageSize": 6,
  464 + "hideEmptyLines": true
  465 + },
  466 + "title": "Total Messages",
  467 + "dropShadow": true,
  468 + "enableFullscreen": true,
  469 + "titleStyle": {
  470 + "fontSize": "16px",
  471 + "fontWeight": 400
  472 + },
  473 + "useDashboardTimewindow": false,
  474 + "showLegend": false,
  475 + "widgetStyle": {},
  476 + "actions": {},
  477 + "showTitleIcon": false,
  478 + "titleIcon": null,
  479 + "iconColor": "rgba(0, 0, 0, 0.87)",
  480 + "iconSize": "24px",
  481 + "titleTooltip": "",
  482 + "displayTimewindow": true,
  483 + "legendConfig": {
  484 + "direction": "column",
  485 + "position": "bottom",
  486 + "showMin": false,
  487 + "showMax": false,
  488 + "showAvg": true,
  489 + "showTotal": false
  490 + }
  491 + },
  492 + "id": "2a95b473-042d-59d0-2da2-40d0cccb6c8a"
  493 + },
  494 + "aaa69366-aacc-9028-65aa-645c0f8533ec": {
  495 + "isSystemType": true,
  496 + "bundleAlias": "charts",
  497 + "typeAlias": "basic_timeseries",
  498 + "type": "timeseries",
  499 + "title": "New widget",
  500 + "sizeX": 17,
  501 + "sizeY": 4,
  502 + "config": {
  503 + "datasources": [
  504 + {
  505 + "type": "entity",
  506 + "dataKeys": [
  507 + {
  508 + "name": "eventsSent",
  509 + "type": "timeseries",
  510 + "label": "eventsSent",
  511 + "color": "#2196f3",
  512 + "settings": {
  513 + "excludeFromStacking": false,
  514 + "hideDataByDefault": false,
  515 + "disableDataHiding": false,
  516 + "removeFromLegend": false,
  517 + "showLines": true,
  518 + "fillLines": false,
  519 + "showPoints": false,
  520 + "showPointShape": "circle",
  521 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  522 + "showPointsLineWidth": 5,
  523 + "showPointsRadius": 3,
  524 + "tooltipValueFormatter": "",
  525 + "showSeparateAxis": false,
  526 + "axisTitle": "",
  527 + "axisPosition": "left",
  528 + "axisTicksFormatter": "",
  529 + "comparisonSettings": {
  530 + "showValuesForComparison": true,
  531 + "comparisonValuesLabel": "",
  532 + "color": ""
  533 + }
  534 + },
  535 + "_hash": 0.41414001784591314
  536 + },
  537 + {
  538 + "name": "eventsProduced",
  539 + "type": "timeseries",
  540 + "label": "eventsProduced",
  541 + "color": "#4caf50",
  542 + "settings": {
  543 + "excludeFromStacking": false,
  544 + "hideDataByDefault": false,
  545 + "disableDataHiding": false,
  546 + "removeFromLegend": false,
  547 + "showLines": true,
  548 + "fillLines": false,
  549 + "showPoints": false,
  550 + "showPointShape": "circle",
  551 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  552 + "showPointsLineWidth": 5,
  553 + "showPointsRadius": 3,
  554 + "tooltipValueFormatter": "",
  555 + "showSeparateAxis": false,
  556 + "axisTitle": "",
  557 + "axisPosition": "left",
  558 + "axisTicksFormatter": "",
  559 + "comparisonSettings": {
  560 + "showValuesForComparison": true,
  561 + "comparisonValuesLabel": "",
  562 + "color": ""
  563 + }
  564 + },
  565 + "_hash": 0.7819101846284422
  566 + }
  567 + ],
  568 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  569 + }
  570 + ],
  571 + "timewindow": {
  572 + "realtime": {
  573 + "timewindowMs": 60000
  574 + }
  575 + },
  576 + "showTitle": true,
  577 + "backgroundColor": "#fff",
  578 + "color": "rgba(0, 0, 0, 0.87)",
  579 + "padding": "8px",
  580 + "settings": {
  581 + "shadowSize": 4,
  582 + "fontColor": "#545454",
  583 + "fontSize": 10,
  584 + "xaxis": {
  585 + "showLabels": true,
  586 + "color": "#545454"
  587 + },
  588 + "yaxis": {
  589 + "showLabels": true,
  590 + "color": "#545454"
  591 + },
  592 + "grid": {
  593 + "color": "#545454",
  594 + "tickColor": "#DDDDDD",
  595 + "verticalLines": true,
  596 + "horizontalLines": true,
  597 + "outlineWidth": 1
  598 + },
  599 + "stack": false,
  600 + "tooltipIndividual": false,
  601 + "timeForComparison": "months",
  602 + "xaxisSecond": {
  603 + "axisPosition": "top",
  604 + "showLabels": true
  605 + }
  606 + },
  607 + "title": "History information",
  608 + "dropShadow": true,
  609 + "enableFullscreen": true,
  610 + "titleStyle": {
  611 + "fontSize": "16px",
  612 + "fontWeight": 400
  613 + },
  614 + "mobileHeight": null,
  615 + "showTitleIcon": false,
  616 + "titleIcon": null,
  617 + "iconColor": "rgba(0, 0, 0, 0.87)",
  618 + "iconSize": "24px",
  619 + "titleTooltip": "",
  620 + "widgetStyle": {},
  621 + "useDashboardTimewindow": true,
  622 + "displayTimewindow": true,
  623 + "showLegend": true,
  624 + "legendConfig": {
  625 + "direction": "column",
  626 + "position": "right",
  627 + "showMin": true,
  628 + "showMax": true,
  629 + "showAvg": true,
  630 + "showTotal": true
  631 + },
  632 + "actions": {}
  633 + },
  634 + "id": "aaa69366-aacc-9028-65aa-645c0f8533ec"
  635 + },
  636 + "ce5c7d01-a3ef-5cf0-4578-8505135c23a0": {
  637 + "isSystemType": true,
  638 + "bundleAlias": "charts",
  639 + "typeAlias": "basic_timeseries",
  640 + "type": "timeseries",
  641 + "title": "New widget",
  642 + "sizeX": 17,
  643 + "sizeY": 4,
  644 + "config": {
  645 + "datasources": [
  646 + {
  647 + "type": "entity",
  648 + "dataKeys": [
  649 + {
  650 + "name": "bleEventsProduced",
  651 + "type": "timeseries",
  652 + "label": "bleEventsProduced",
  653 + "color": "#2196f3",
  654 + "settings": {
  655 + "excludeFromStacking": false,
  656 + "hideDataByDefault": false,
  657 + "disableDataHiding": false,
  658 + "removeFromLegend": false,
  659 + "showLines": true,
  660 + "fillLines": false,
  661 + "showPoints": false,
  662 + "showPointShape": "circle",
  663 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  664 + "showPointsLineWidth": 5,
  665 + "showPointsRadius": 3,
  666 + "tooltipValueFormatter": "",
  667 + "showSeparateAxis": false,
  668 + "axisTitle": "",
  669 + "axisPosition": "left",
  670 + "axisTicksFormatter": "",
  671 + "comparisonSettings": {
  672 + "showValuesForComparison": true,
  673 + "comparisonValuesLabel": "",
  674 + "color": ""
  675 + }
  676 + },
  677 + "_hash": 0.5625165504526104
  678 + },
  679 + {
  680 + "name": "bleEventsSent",
  681 + "type": "timeseries",
  682 + "label": "bleEventsSent",
  683 + "color": "#4caf50",
  684 + "settings": {
  685 + "excludeFromStacking": false,
  686 + "hideDataByDefault": false,
  687 + "disableDataHiding": false,
  688 + "removeFromLegend": false,
  689 + "showLines": true,
  690 + "fillLines": false,
  691 + "showPoints": false,
  692 + "showPointShape": "circle",
  693 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  694 + "showPointsLineWidth": 5,
  695 + "showPointsRadius": 3,
  696 + "tooltipValueFormatter": "",
  697 + "showSeparateAxis": false,
  698 + "axisTitle": "",
  699 + "axisPosition": "left",
  700 + "axisTicksFormatter": "",
  701 + "comparisonSettings": {
  702 + "showValuesForComparison": true,
  703 + "comparisonValuesLabel": "",
  704 + "color": ""
  705 + }
  706 + },
  707 + "_hash": 0.6817950080745288
  708 + }
  709 + ],
  710 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  711 + }
  712 + ],
  713 + "timewindow": {
  714 + "realtime": {
  715 + "interval": 5000,
  716 + "timewindowMs": 120000
  717 + },
  718 + "aggregation": {
  719 + "type": "AVG",
  720 + "limit": 25000
  721 + }
  722 + },
  723 + "showTitle": true,
  724 + "backgroundColor": "#fff",
  725 + "color": "rgba(0, 0, 0, 0.87)",
  726 + "padding": "8px",
  727 + "settings": {
  728 + "shadowSize": 4,
  729 + "fontColor": "#545454",
  730 + "fontSize": 10,
  731 + "xaxis": {
  732 + "showLabels": true,
  733 + "color": "#545454"
  734 + },
  735 + "yaxis": {
  736 + "showLabels": true,
  737 + "color": "#545454"
  738 + },
  739 + "grid": {
  740 + "color": "#545454",
  741 + "tickColor": "#DDDDDD",
  742 + "verticalLines": true,
  743 + "horizontalLines": true,
  744 + "outlineWidth": 1
  745 + },
  746 + "stack": false,
  747 + "tooltipIndividual": false,
  748 + "timeForComparison": "months",
  749 + "xaxisSecond": {
  750 + "axisPosition": "top",
  751 + "showLabels": true
  752 + }
  753 + },
  754 + "title": "Real time information",
  755 + "dropShadow": true,
  756 + "enableFullscreen": true,
  757 + "titleStyle": {
  758 + "fontSize": "16px",
  759 + "fontWeight": 400
  760 + },
  761 + "mobileHeight": null,
  762 + "showTitleIcon": false,
  763 + "titleIcon": null,
  764 + "iconColor": "rgba(0, 0, 0, 0.87)",
  765 + "iconSize": "24px",
  766 + "titleTooltip": "",
  767 + "widgetStyle": {},
  768 + "useDashboardTimewindow": false,
  769 + "displayTimewindow": true,
  770 + "showLegend": true,
  771 + "legendConfig": {
  772 + "direction": "column",
  773 + "position": "right",
  774 + "showMin": true,
  775 + "showMax": true,
  776 + "showAvg": true,
  777 + "showTotal": true
  778 + },
  779 + "actions": {}
  780 + },
  781 + "id": "ce5c7d01-a3ef-5cf0-4578-8505135c23a0"
  782 + },
  783 + "466f046d-6005-a168-b107-60fcb2469cd5": {
  784 + "isSystemType": true,
  785 + "bundleAlias": "gateway_widgets",
  786 + "typeAlias": "attributes_card",
  787 + "type": "latest",
  788 + "title": "New widget",
  789 + "sizeX": 7,
  790 + "sizeY": 5,
  791 + "config": {
  792 + "datasources": [
  793 + {
  794 + "type": "entity",
  795 + "dataKeys": [],
  796 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  797 + }
  798 + ],
  799 + "timewindow": {
  800 + "realtime": {
  801 + "timewindowMs": 60000
  802 + }
  803 + },
  804 + "showTitle": true,
  805 + "backgroundColor": "#fff",
  806 + "color": "rgba(0, 0, 0, 0.87)",
  807 + "padding": "8px",
  808 + "settings": {
  809 + "eventsTitle": "Gateway Events Form",
  810 + "eventsReg": [
  811 + "EventsProduced",
  812 + "EventsSent"
  813 + ]
  814 + },
  815 + "title": "Gateway events",
  816 + "showTitleIcon": false,
  817 + "titleIcon": null,
  818 + "iconColor": "rgba(0, 0, 0, 0.87)",
  819 + "iconSize": "24px",
  820 + "titleTooltip": "",
  821 + "dropShadow": true,
  822 + "enableFullscreen": true,
  823 + "widgetStyle": {},
  824 + "titleStyle": {
  825 + "fontSize": "16px",
  826 + "fontWeight": 400
  827 + },
  828 + "useDashboardTimewindow": true,
  829 + "displayTimewindow": true,
  830 + "showLegend": false,
  831 + "actions": {}
  832 + },
  833 + "id": "466f046d-6005-a168-b107-60fcb2469cd5"
  834 + },
  835 + "8fc32225-164f-3258-73f7-e6b6d959cf0b": {
  836 + "isSystemType": true,
  837 + "bundleAlias": "gateway_widgets",
  838 + "typeAlias": "config_form_latest",
  839 + "type": "latest",
  840 + "title": "New widget",
  841 + "sizeX": 10,
  842 + "sizeY": 9,
  843 + "config": {
  844 + "datasources": [
  845 + {
  846 + "type": "entity",
  847 + "dataKeys": [],
  848 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  849 + }
  850 + ],
  851 + "timewindow": {
  852 + "realtime": {
  853 + "timewindowMs": 60000
  854 + }
  855 + },
  856 + "showTitle": true,
  857 + "backgroundColor": "#fff",
  858 + "color": "rgba(0, 0, 0, 0.87)",
  859 + "padding": "8px",
  860 + "settings": {
  861 + "gatewayTitle": "Gateway configuration (Single device)",
  862 + "readOnly": false
  863 + },
  864 + "title": "New Gateway configuration (Single device)",
  865 + "showTitleIcon": false,
  866 + "titleIcon": null,
  867 + "iconColor": "rgba(0, 0, 0, 0.87)",
  868 + "iconSize": "24px",
  869 + "titleTooltip": "",
  870 + "dropShadow": true,
  871 + "enableFullscreen": true,
  872 + "widgetStyle": {},
  873 + "titleStyle": {
  874 + "fontSize": "16px",
  875 + "fontWeight": 400
  876 + },
  877 + "useDashboardTimewindow": true,
  878 + "displayTimewindow": true,
  879 + "showLegend": false,
  880 + "actions": {}
  881 + },
  882 + "id": "8fc32225-164f-3258-73f7-e6b6d959cf0b"
  883 + },
  884 + "063fc179-c9fd-f952-e714-f24e9c43c05c": {
  885 + "isSystemType": true,
  886 + "bundleAlias": "control_widgets",
  887 + "typeAlias": "rpcbutton",
  888 + "type": "rpc",
  889 + "title": "New widget",
  890 + "sizeX": 4,
  891 + "sizeY": 2,
  892 + "config": {
  893 + "targetDeviceAliases": [],
  894 + "showTitle": false,
  895 + "backgroundColor": "#e6e7e8",
  896 + "color": "rgba(0, 0, 0, 0.87)",
  897 + "padding": "0px",
  898 + "settings": {
  899 + "requestTimeout": 5000,
  900 + "oneWayElseTwoWay": true,
  901 + "styleButton": {
  902 + "isRaised": true,
  903 + "isPrimary": false
  904 + },
  905 + "methodParams": "{}",
  906 + "methodName": "gateway_reboot",
  907 + "buttonText": "GATEWAY REBOOT"
  908 + },
  909 + "title": "New RPC Button",
  910 + "dropShadow": true,
  911 + "enableFullscreen": false,
  912 + "widgetStyle": {},
  913 + "titleStyle": {
  914 + "fontSize": "16px",
  915 + "fontWeight": 400
  916 + },
  917 + "useDashboardTimewindow": true,
  918 + "showLegend": false,
  919 + "actions": {},
  920 + "datasources": [],
  921 + "showTitleIcon": false,
  922 + "titleIcon": null,
  923 + "iconColor": "rgba(0, 0, 0, 0.87)",
  924 + "iconSize": "24px",
  925 + "titleTooltip": "",
  926 + "displayTimewindow": true,
  927 + "targetDeviceAliasIds": [
  928 + "b2487e75-2fa4-f211-142c-434dfd50c70c"
  929 + ]
  930 + },
  931 + "id": "063fc179-c9fd-f952-e714-f24e9c43c05c"
  932 + },
  933 + "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7": {
  934 + "isSystemType": true,
  935 + "bundleAlias": "control_widgets",
  936 + "typeAlias": "rpcbutton",
  937 + "type": "rpc",
  938 + "title": "New widget",
  939 + "sizeX": 4,
  940 + "sizeY": 2,
  941 + "config": {
  942 + "targetDeviceAliases": [],
  943 + "showTitle": false,
  944 + "backgroundColor": "#e6e7e8",
  945 + "color": "rgba(0, 0, 0, 0.87)",
  946 + "padding": "0px",
  947 + "settings": {
  948 + "requestTimeout": 5000,
  949 + "oneWayElseTwoWay": true,
  950 + "styleButton": {
  951 + "isRaised": true,
  952 + "isPrimary": false
  953 + },
  954 + "methodName": "gateway_restart",
  955 + "methodParams": "{}",
  956 + "buttonText": "gateway restart"
  957 + },
  958 + "title": "New RPC Button",
  959 + "dropShadow": true,
  960 + "enableFullscreen": false,
  961 + "widgetStyle": {},
  962 + "titleStyle": {
  963 + "fontSize": "16px",
  964 + "fontWeight": 400
  965 + },
  966 + "useDashboardTimewindow": true,
  967 + "showLegend": false,
  968 + "actions": {},
  969 + "datasources": [],
  970 + "showTitleIcon": false,
  971 + "titleIcon": null,
  972 + "iconColor": "rgba(0, 0, 0, 0.87)",
  973 + "iconSize": "24px",
  974 + "titleTooltip": "",
  975 + "displayTimewindow": true,
  976 + "targetDeviceAliasIds": [
  977 + "b2487e75-2fa4-f211-142c-434dfd50c70c"
  978 + ]
  979 + },
  980 + "id": "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7"
  981 + },
  982 + "6770b6ba-eff8-df05-75f8-c1f9326d4842": {
  983 + "isSystemType": true,
  984 + "bundleAlias": "input_widgets",
  985 + "typeAlias": "markers_placement_openstreetmap",
  986 + "type": "latest",
  987 + "title": "New widget",
  988 + "sizeX": 6,
  989 + "sizeY": 4,
  990 + "config": {
  991 + "datasources": [
  992 + {
  993 + "type": "entity",
  994 + "dataKeys": [
  995 + {
  996 + "name": "latitude",
  997 + "type": "attribute",
  998 + "label": "latitude",
  999 + "color": "#2196f3",
  1000 + "settings": {},
  1001 + "_hash": 0.9743324774725604
  1002 + },
  1003 + {
  1004 + "name": "longitude",
  1005 + "type": "attribute",
  1006 + "label": "longitude",
  1007 + "color": "#4caf50",
  1008 + "settings": {},
  1009 + "_hash": 0.5530093635101525
  1010 + }
  1011 + ],
  1012 + "entityAliasId": "b2487e75-2fa4-f211-142c-434dfd50c70c"
  1013 + }
  1014 + ],
  1015 + "timewindow": {
  1016 + "realtime": {
  1017 + "timewindowMs": 60000
  1018 + }
  1019 + },
  1020 + "showTitle": false,
  1021 + "backgroundColor": "#fff",
  1022 + "color": "rgba(0, 0, 0, 0.87)",
  1023 + "padding": "8px",
  1024 + "settings": {
  1025 + "fitMapBounds": true,
  1026 + "latKeyName": "latitude",
  1027 + "lngKeyName": "longitude",
  1028 + "showLabel": true,
  1029 + "label": "${entityName}",
  1030 + "tooltipPattern": "<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><br/><link-act name='delete'>Delete</link-act>",
  1031 + "markerImageSize": 34,
  1032 + "useColorFunction": false,
  1033 + "markerImages": [],
  1034 + "useMarkerImageFunction": false,
  1035 + "color": "#fe7569",
  1036 + "mapProvider": "OpenStreetMap.Mapnik",
  1037 + "showTooltip": true,
  1038 + "autocloseTooltip": true,
  1039 + "defaultCenterPosition": [
  1040 + 0,
  1041 + 0
  1042 + ],
  1043 + "customProviderTileUrl": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
  1044 + "showTooltipAction": "click",
  1045 + "polygonKeyName": "coordinates",
  1046 + "polygonOpacity": 0.5,
  1047 + "polygonStrokeOpacity": 1,
  1048 + "polygonStrokeWeight": 1,
  1049 + "zoomOnClick": true,
  1050 + "showCoverageOnHover": true,
  1051 + "animate": true,
  1052 + "maxClusterRadius": 80,
  1053 + "removeOutsideVisibleBounds": true,
  1054 + "defaultZoomLevel": 5
  1055 + },
  1056 + "title": "Gateway Location",
  1057 + "dropShadow": true,
  1058 + "enableFullscreen": false,
  1059 + "titleStyle": {
  1060 + "fontSize": "16px",
  1061 + "fontWeight": 400
  1062 + },
  1063 + "useDashboardTimewindow": true,
  1064 + "showLegend": false,
  1065 + "widgetStyle": {},
  1066 + "actions": {
  1067 + "tooltipAction": [
  1068 + {
  1069 + "id": "54c293c4-9ca6-e34f-dc6a-0271944c1c66",
  1070 + "name": "delete",
  1071 + "icon": "more_horiz",
  1072 + "type": "custom",
  1073 + "customFunction": "var $rootScope = widgetContext.$scope.$injector.get('$rootScope');\nvar entityDatasource = widgetContext.map.subscription.datasources.filter(\n function(entity) {\n return entity.entityId === entityId.id\n });\n\nwidgetContext.map.saveMarkerLocation(entityDatasource[0],\n widgetContext.map.locations[0], {\n \"lat\": null,\n \"lng\": null\n }).then(function succes() {\n $rootScope.$broadcast('widgetForceReInit');\n });"
  1074 + }
  1075 + ]
  1076 + },
  1077 + "showTitleIcon": false,
  1078 + "titleIcon": null,
  1079 + "iconColor": "rgba(0, 0, 0, 0.87)",
  1080 + "iconSize": "24px",
  1081 + "titleTooltip": "",
  1082 + "displayTimewindow": true
  1083 + },
  1084 + "id": "6770b6ba-eff8-df05-75f8-c1f9326d4842"
  1085 + }
  1086 + },
  1087 + "states": {
  1088 + "main_gateway": {
  1089 + "name": "Gateways",
  1090 + "root": true,
  1091 + "layouts": {
  1092 + "main": {
  1093 + "widgets": {
  1094 + "94715984-ae74-76e4-20b7-2f956b01ed80": {
  1095 + "sizeX": 24,
  1096 + "sizeY": 12,
  1097 + "row": 0,
  1098 + "col": 0
  1099 + }
  1100 + },
  1101 + "gridSettings": {
  1102 + "backgroundColor": "#eeeeee",
  1103 + "color": "rgba(0,0,0,0.870588)",
  1104 + "columns": 24,
  1105 + "margins": [
  1106 + 10,
  1107 + 10
  1108 + ],
  1109 + "backgroundSizeMode": "100%",
  1110 + "autoFillHeight": true,
  1111 + "mobileAutoFillHeight": false,
  1112 + "mobileRowHeight": 70
  1113 + }
  1114 + }
  1115 + }
  1116 + },
  1117 + "__entityname__config": {
  1118 + "name": "${entityName} Configuration",
  1119 + "root": false,
  1120 + "layouts": {
  1121 + "main": {
  1122 + "widgets": {
  1123 + "eadabbc7-519e-76fc-ba10-b3fe8c18da10": {
  1124 + "sizeX": 14,
  1125 + "sizeY": 13,
  1126 + "row": 0,
  1127 + "col": 10
  1128 + },
  1129 + "8fc32225-164f-3258-73f7-e6b6d959cf0b": {
  1130 + "sizeX": 10,
  1131 + "sizeY": 9,
  1132 + "row": 0,
  1133 + "col": 0
  1134 + },
  1135 + "063fc179-c9fd-f952-e714-f24e9c43c05c": {
  1136 + "sizeX": 4,
  1137 + "sizeY": 2,
  1138 + "row": 9,
  1139 + "col": 0
  1140 + },
  1141 + "3c2134cc-27a0-93e1-dbe1-2fa7c1ce16b7": {
  1142 + "sizeX": 4,
  1143 + "sizeY": 2,
  1144 + "row": 11,
  1145 + "col": 0
  1146 + },
  1147 + "6770b6ba-eff8-df05-75f8-c1f9326d4842": {
  1148 + "sizeX": 6,
  1149 + "sizeY": 4,
  1150 + "row": 9,
  1151 + "col": 4
  1152 + }
  1153 + },
  1154 + "gridSettings": {
  1155 + "backgroundColor": "#eeeeee",
  1156 + "color": "rgba(0,0,0,0.870588)",
  1157 + "columns": 24,
  1158 + "margins": [
  1159 + 10,
  1160 + 10
  1161 + ],
  1162 + "backgroundSizeMode": "100%",
  1163 + "autoFillHeight": true,
  1164 + "mobileAutoFillHeight": false,
  1165 + "mobileRowHeight": 70
  1166 + }
  1167 + }
  1168 + }
  1169 + },
  1170 + "__entityname_grafic": {
  1171 + "name": "${entityName} Details",
  1172 + "root": false,
  1173 + "layouts": {
  1174 + "main": {
  1175 + "widgets": {
  1176 + "f928afc4-30d1-8d0c-e3cf-777f9f9d1155": {
  1177 + "sizeX": 17,
  1178 + "sizeY": 4,
  1179 + "mobileHeight": null,
  1180 + "row": 4,
  1181 + "col": 7
  1182 + },
  1183 + "2a95b473-042d-59d0-2da2-40d0cccb6c8a": {
  1184 + "sizeX": 7,
  1185 + "sizeY": 7,
  1186 + "row": 5,
  1187 + "col": 0
  1188 + },
  1189 + "aaa69366-aacc-9028-65aa-645c0f8533ec": {
  1190 + "sizeX": 17,
  1191 + "sizeY": 4,
  1192 + "mobileHeight": null,
  1193 + "row": 0,
  1194 + "col": 7
  1195 + },
  1196 + "ce5c7d01-a3ef-5cf0-4578-8505135c23a0": {
  1197 + "sizeX": 17,
  1198 + "sizeY": 4,
  1199 + "mobileHeight": null,
  1200 + "row": 8,
  1201 + "col": 7
  1202 + },
  1203 + "466f046d-6005-a168-b107-60fcb2469cd5": {
  1204 + "sizeX": 7,
  1205 + "sizeY": 5,
  1206 + "row": 0,
  1207 + "col": 0
  1208 + }
  1209 + },
  1210 + "gridSettings": {
  1211 + "backgroundColor": "#eeeeee",
  1212 + "color": "rgba(0,0,0,0.870588)",
  1213 + "columns": 24,
  1214 + "margins": [
  1215 + 10,
  1216 + 10
  1217 + ],
  1218 + "backgroundSizeMode": "auto 100%",
  1219 + "autoFillHeight": true,
  1220 + "mobileAutoFillHeight": true,
  1221 + "mobileRowHeight": 70
  1222 + }
  1223 + }
  1224 + }
  1225 + }
  1226 + },
  1227 + "entityAliases": {
  1228 + "3e0f533a-0db1-3292-184f-06e73535061a": {
  1229 + "id": "3e0f533a-0db1-3292-184f-06e73535061a",
  1230 + "alias": "Gateways",
  1231 + "filter": {
  1232 + "type": "deviceType",
  1233 + "resolveMultiple": true,
  1234 + "deviceType": "gateway",
  1235 + "deviceNameFilter": ""
  1236 + }
  1237 + },
  1238 + "b2487e75-2fa4-f211-142c-434dfd50c70c": {
  1239 + "id": "b2487e75-2fa4-f211-142c-434dfd50c70c",
  1240 + "alias": "Current Gateway",
  1241 + "filter": {
  1242 + "type": "stateEntity",
  1243 + "resolveMultiple": false,
  1244 + "stateEntityParamName": "",
  1245 + "defaultStateEntity": null
  1246 + }
  1247 + }
  1248 + },
  1249 + "timewindow": {
  1250 + "realtime": {
  1251 + "interval": 1000,
  1252 + "timewindowMs": 86400000
  1253 + },
  1254 + "aggregation": {
  1255 + "type": "NONE",
  1256 + "limit": 25000
  1257 + },
  1258 + "hideInterval": false,
  1259 + "hideAggregation": false,
  1260 + "hideAggInterval": false
  1261 + },
  1262 + "settings": {
  1263 + "stateControllerId": "entity",
  1264 + "showTitle": true,
  1265 + "showDashboardsSelect": true,
  1266 + "showEntitiesSelect": true,
  1267 + "showDashboardTimewindow": true,
  1268 + "showDashboardExport": true,
  1269 + "toolbarAlwaysOpen": true,
  1270 + "titleColor": "rgba(0,0,0,0.870588)"
  1271 + }
  1272 + },
  1273 + "name": "Gateways"
  1274 +}
  1 +{
  2 + "title": "Rule Engine Statistics",
  3 + "configuration": {
  4 + "widgets": {
  5 + "81987f19-3eac-e4ce-b790-d96e9b54d9a0": {
  6 + "isSystemType": true,
  7 + "bundleAlias": "charts",
  8 + "typeAlias": "basic_timeseries",
  9 + "type": "timeseries",
  10 + "title": "New widget",
  11 + "sizeX": 12,
  12 + "sizeY": 7,
  13 + "config": {
  14 + "datasources": [
  15 + {
  16 + "type": "entity",
  17 + "dataKeys": [
  18 + {
  19 + "name": "successfulMsgs",
  20 + "type": "timeseries",
  21 + "label": "${entityName} Successful",
  22 + "color": "#4caf50",
  23 + "settings": {
  24 + "excludeFromStacking": false,
  25 + "hideDataByDefault": false,
  26 + "disableDataHiding": false,
  27 + "removeFromLegend": false,
  28 + "showLines": true,
  29 + "fillLines": false,
  30 + "showPoints": false,
  31 + "showPointShape": "circle",
  32 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  33 + "showPointsLineWidth": 5,
  34 + "showPointsRadius": 3,
  35 + "showSeparateAxis": false,
  36 + "axisPosition": "left",
  37 + "thresholds": [
  38 + {
  39 + "thresholdValueSource": "predefinedValue"
  40 + }
  41 + ],
  42 + "comparisonSettings": {
  43 + "showValuesForComparison": true
  44 + }
  45 + },
  46 + "_hash": 0.15490750967648736
  47 + },
  48 + {
  49 + "name": "failedMsgs",
  50 + "type": "timeseries",
  51 + "label": "${entityName} Permanent Failures",
  52 + "color": "#ef5350",
  53 + "settings": {
  54 + "excludeFromStacking": false,
  55 + "hideDataByDefault": false,
  56 + "disableDataHiding": false,
  57 + "removeFromLegend": false,
  58 + "showLines": true,
  59 + "fillLines": false,
  60 + "showPoints": false,
  61 + "showPointShape": "circle",
  62 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  63 + "showPointsLineWidth": 5,
  64 + "showPointsRadius": 3,
  65 + "showSeparateAxis": false,
  66 + "axisPosition": "left",
  67 + "thresholds": [
  68 + {
  69 + "thresholdValueSource": "predefinedValue"
  70 + }
  71 + ],
  72 + "comparisonSettings": {
  73 + "showValuesForComparison": true
  74 + }
  75 + },
  76 + "_hash": 0.4186621166514697
  77 + },
  78 + {
  79 + "name": "tmpFailed",
  80 + "type": "timeseries",
  81 + "label": "${entityName} Processing Failures",
  82 + "color": "#ffc107",
  83 + "settings": {
  84 + "excludeFromStacking": false,
  85 + "hideDataByDefault": false,
  86 + "disableDataHiding": false,
  87 + "removeFromLegend": false,
  88 + "showLines": true,
  89 + "fillLines": false,
  90 + "showPoints": false,
  91 + "showPointShape": "circle",
  92 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  93 + "showPointsLineWidth": 5,
  94 + "showPointsRadius": 3,
  95 + "showSeparateAxis": false,
  96 + "axisPosition": "left",
  97 + "thresholds": [
  98 + {
  99 + "thresholdValueSource": "predefinedValue"
  100 + }
  101 + ],
  102 + "comparisonSettings": {
  103 + "showValuesForComparison": true
  104 + }
  105 + },
  106 + "_hash": 0.49891007198715376
  107 + }
  108 + ],
  109 + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018"
  110 + }
  111 + ],
  112 + "timewindow": {
  113 + "realtime": {
  114 + "interval": 1000,
  115 + "timewindowMs": 300000
  116 + },
  117 + "aggregation": {
  118 + "type": "NONE",
  119 + "limit": 8640
  120 + },
  121 + "hideInterval": false,
  122 + "hideAggregation": false,
  123 + "hideAggInterval": false
  124 + },
  125 + "showTitle": true,
  126 + "backgroundColor": "#fff",
  127 + "color": "rgba(0, 0, 0, 0.87)",
  128 + "padding": "8px",
  129 + "settings": {
  130 + "shadowSize": 4,
  131 + "fontColor": "#545454",
  132 + "fontSize": 10,
  133 + "xaxis": {
  134 + "showLabels": true,
  135 + "color": "#545454"
  136 + },
  137 + "yaxis": {
  138 + "showLabels": true,
  139 + "color": "#545454"
  140 + },
  141 + "grid": {
  142 + "color": "#545454",
  143 + "tickColor": "#DDDDDD",
  144 + "verticalLines": true,
  145 + "horizontalLines": true,
  146 + "outlineWidth": 1
  147 + },
  148 + "stack": false,
  149 + "tooltipIndividual": false,
  150 + "timeForComparison": "months",
  151 + "xaxisSecond": {
  152 + "axisPosition": "top",
  153 + "showLabels": true
  154 + }
  155 + },
  156 + "title": "Queue Stats",
  157 + "dropShadow": true,
  158 + "enableFullscreen": true,
  159 + "titleStyle": {
  160 + "fontSize": "16px",
  161 + "fontWeight": 400
  162 + },
  163 + "mobileHeight": null,
  164 + "showTitleIcon": false,
  165 + "titleIcon": null,
  166 + "iconColor": "rgba(0, 0, 0, 0.87)",
  167 + "iconSize": "24px",
  168 + "titleTooltip": "",
  169 + "widgetStyle": {},
  170 + "useDashboardTimewindow": false,
  171 + "displayTimewindow": true,
  172 + "showLegend": true,
  173 + "actions": {},
  174 + "legendConfig": {
  175 + "direction": "column",
  176 + "position": "bottom",
  177 + "showMin": true,
  178 + "showMax": true,
  179 + "showAvg": false,
  180 + "showTotal": true
  181 + }
  182 + },
  183 + "id": "81987f19-3eac-e4ce-b790-d96e9b54d9a0"
  184 + },
  185 + "5eb79712-5c24-3060-7e4f-6af36b8f842d": {
  186 + "isSystemType": true,
  187 + "bundleAlias": "cards",
  188 + "typeAlias": "timeseries_table",
  189 + "type": "timeseries",
  190 + "title": "New widget",
  191 + "sizeX": 24,
  192 + "sizeY": 5,
  193 + "config": {
  194 + "datasources": [
  195 + {
  196 + "type": "entity",
  197 + "dataKeys": [
  198 + {
  199 + "name": "ruleEngineException",
  200 + "type": "timeseries",
  201 + "label": "Rule Chain",
  202 + "color": "#2196f3",
  203 + "settings": {
  204 + "useCellStyleFunction": false,
  205 + "useCellContentFunction": true,
  206 + "cellContentFunction": "return JSON.parse(value).ruleChainName;"
  207 + },
  208 + "_hash": 0.9954481282345906
  209 + },
  210 + {
  211 + "name": "ruleEngineException",
  212 + "type": "timeseries",
  213 + "label": "Rule Node",
  214 + "color": "#4caf50",
  215 + "settings": {
  216 + "useCellStyleFunction": false,
  217 + "useCellContentFunction": true,
  218 + "cellContentFunction": "return JSON.parse(value).ruleNodeName;"
  219 + },
  220 + "_hash": 0.18580357036589978
  221 + },
  222 + {
  223 + "name": "ruleEngineException",
  224 + "type": "timeseries",
  225 + "label": "Latest Error",
  226 + "color": "#f44336",
  227 + "settings": {
  228 + "useCellStyleFunction": false,
  229 + "useCellContentFunction": true,
  230 + "cellContentFunction": "return JSON.parse(value).message;"
  231 + },
  232 + "_hash": 0.7255162989552142
  233 + }
  234 + ],
  235 + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018"
  236 + }
  237 + ],
  238 + "timewindow": {
  239 + "realtime": {
  240 + "interval": 1000,
  241 + "timewindowMs": 86400000
  242 + },
  243 + "aggregation": {
  244 + "type": "NONE",
  245 + "limit": 200
  246 + }
  247 + },
  248 + "showTitle": true,
  249 + "backgroundColor": "rgb(255, 255, 255)",
  250 + "color": "rgba(0, 0, 0, 0.87)",
  251 + "padding": "8px",
  252 + "settings": {
  253 + "showTimestamp": true,
  254 + "displayPagination": true,
  255 + "defaultPageSize": 10
  256 + },
  257 + "title": "Exceptions",
  258 + "dropShadow": true,
  259 + "enableFullscreen": true,
  260 + "titleStyle": {
  261 + "fontSize": "16px",
  262 + "fontWeight": 400
  263 + },
  264 + "useDashboardTimewindow": false,
  265 + "showLegend": false,
  266 + "widgetStyle": {},
  267 + "actions": {},
  268 + "showTitleIcon": false,
  269 + "titleIcon": null,
  270 + "iconColor": "rgba(0, 0, 0, 0.87)",
  271 + "iconSize": "24px",
  272 + "titleTooltip": "",
  273 + "displayTimewindow": true
  274 + },
  275 + "id": "5eb79712-5c24-3060-7e4f-6af36b8f842d"
  276 + },
  277 + "ad3f1417-87a8-750e-fc67-49a2de1466d4": {
  278 + "isSystemType": true,
  279 + "bundleAlias": "charts",
  280 + "typeAlias": "basic_timeseries",
  281 + "type": "timeseries",
  282 + "title": "New widget",
  283 + "sizeX": 12,
  284 + "sizeY": 7,
  285 + "config": {
  286 + "datasources": [
  287 + {
  288 + "type": "entity",
  289 + "dataKeys": [
  290 + {
  291 + "name": "timeoutMsgs",
  292 + "type": "timeseries",
  293 + "label": "${entityName} Permanent Timeouts",
  294 + "color": "#4caf50",
  295 + "settings": {
  296 + "excludeFromStacking": false,
  297 + "hideDataByDefault": false,
  298 + "disableDataHiding": false,
  299 + "removeFromLegend": false,
  300 + "showLines": true,
  301 + "fillLines": false,
  302 + "showPoints": false,
  303 + "showPointShape": "circle",
  304 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  305 + "showPointsLineWidth": 5,
  306 + "showPointsRadius": 3,
  307 + "showSeparateAxis": false,
  308 + "axisPosition": "left",
  309 + "thresholds": [
  310 + {
  311 + "thresholdValueSource": "predefinedValue"
  312 + }
  313 + ],
  314 + "comparisonSettings": {
  315 + "showValuesForComparison": true
  316 + }
  317 + },
  318 + "_hash": 0.565222981550328
  319 + },
  320 + {
  321 + "name": "tmpTimeout",
  322 + "type": "timeseries",
  323 + "label": "${entityName} Processing Timeouts",
  324 + "color": "#9c27b0",
  325 + "settings": {
  326 + "excludeFromStacking": false,
  327 + "hideDataByDefault": false,
  328 + "disableDataHiding": false,
  329 + "removeFromLegend": false,
  330 + "showLines": true,
  331 + "fillLines": false,
  332 + "showPoints": false,
  333 + "showPointShape": "circle",
  334 + "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
  335 + "showPointsLineWidth": 5,
  336 + "showPointsRadius": 3,
  337 + "showSeparateAxis": false,
  338 + "axisPosition": "left",
  339 + "thresholds": [
  340 + {
  341 + "thresholdValueSource": "predefinedValue"
  342 + }
  343 + ],
  344 + "comparisonSettings": {
  345 + "showValuesForComparison": true
  346 + }
  347 + },
  348 + "_hash": 0.2679547062508352
  349 + }
  350 + ],
  351 + "entityAliasId": "140f23dd-e3a0-ed98-6189-03c49d2d8018"
  352 + }
  353 + ],
  354 + "timewindow": {
  355 + "realtime": {
  356 + "interval": 1000,
  357 + "timewindowMs": 300000
  358 + },
  359 + "aggregation": {
  360 + "type": "NONE",
  361 + "limit": 8640
  362 + },
  363 + "hideInterval": false,
  364 + "hideAggregation": false,
  365 + "hideAggInterval": false
  366 + },
  367 + "showTitle": true,
  368 + "backgroundColor": "#fff",
  369 + "color": "rgba(0, 0, 0, 0.87)",
  370 + "padding": "8px",
  371 + "settings": {
  372 + "shadowSize": 4,
  373 + "fontColor": "#545454",
  374 + "fontSize": 10,
  375 + "xaxis": {
  376 + "showLabels": true,
  377 + "color": "#545454"
  378 + },
  379 + "yaxis": {
  380 + "showLabels": true,
  381 + "color": "#545454"
  382 + },
  383 + "grid": {
  384 + "color": "#545454",
  385 + "tickColor": "#DDDDDD",
  386 + "verticalLines": true,
  387 + "horizontalLines": true,
  388 + "outlineWidth": 1
  389 + },
  390 + "stack": false,
  391 + "tooltipIndividual": false,
  392 + "timeForComparison": "months",
  393 + "xaxisSecond": {
  394 + "axisPosition": "top",
  395 + "showLabels": true
  396 + }
  397 + },
  398 + "title": "Processing Failures and Timeouts",
  399 + "dropShadow": true,
  400 + "enableFullscreen": true,
  401 + "titleStyle": {
  402 + "fontSize": "16px",
  403 + "fontWeight": 400
  404 + },
  405 + "mobileHeight": null,
  406 + "showTitleIcon": false,
  407 + "titleIcon": null,
  408 + "iconColor": "rgba(0, 0, 0, 0.87)",
  409 + "iconSize": "24px",
  410 + "titleTooltip": "",
  411 + "widgetStyle": {},
  412 + "useDashboardTimewindow": false,
  413 + "displayTimewindow": true,
  414 + "showLegend": true,
  415 + "actions": {},
  416 + "legendConfig": {
  417 + "direction": "column",
  418 + "position": "bottom",
  419 + "showMin": true,
  420 + "showMax": true,
  421 + "showAvg": false,
  422 + "showTotal": true
  423 + }
  424 + },
  425 + "id": "ad3f1417-87a8-750e-fc67-49a2de1466d4"
  426 + }
  427 + },
  428 + "states": {
  429 + "default": {
  430 + "name": "Rule Engine Statistics",
  431 + "root": true,
  432 + "layouts": {
  433 + "main": {
  434 + "widgets": {
  435 + "81987f19-3eac-e4ce-b790-d96e9b54d9a0": {
  436 + "sizeX": 12,
  437 + "sizeY": 7,
  438 + "mobileHeight": null,
  439 + "row": 0,
  440 + "col": 0
  441 + },
  442 + "5eb79712-5c24-3060-7e4f-6af36b8f842d": {
  443 + "sizeX": 24,
  444 + "sizeY": 5,
  445 + "row": 7,
  446 + "col": 0
  447 + },
  448 + "ad3f1417-87a8-750e-fc67-49a2de1466d4": {
  449 + "sizeX": 12,
  450 + "sizeY": 7,
  451 + "mobileHeight": null,
  452 + "row": 0,
  453 + "col": 12
  454 + }
  455 + },
  456 + "gridSettings": {
  457 + "backgroundColor": "#eeeeee",
  458 + "color": "rgba(0,0,0,0.870588)",
  459 + "columns": 24,
  460 + "margins": [
  461 + 10,
  462 + 10
  463 + ],
  464 + "backgroundSizeMode": "100%",
  465 + "autoFillHeight": true,
  466 + "mobileAutoFillHeight": false,
  467 + "mobileRowHeight": 70
  468 + }
  469 + }
  470 + }
  471 + }
  472 + },
  473 + "entityAliases": {
  474 + "140f23dd-e3a0-ed98-6189-03c49d2d8018": {
  475 + "id": "140f23dd-e3a0-ed98-6189-03c49d2d8018",
  476 + "alias": "TbServiceQueues",
  477 + "filter": {
  478 + "type": "assetType",
  479 + "resolveMultiple": true,
  480 + "assetType": "TbServiceQueue",
  481 + "assetNameFilter": ""
  482 + }
  483 + }
  484 + },
  485 + "timewindow": {
  486 + "displayValue": "",
  487 + "selectedTab": 0,
  488 + "hideInterval": false,
  489 + "hideAggregation": false,
  490 + "hideAggInterval": false,
  491 + "realtime": {
  492 + "interval": 1000,
  493 + "timewindowMs": 60000
  494 + },
  495 + "history": {
  496 + "historyType": 0,
  497 + "interval": 1000,
  498 + "timewindowMs": 60000,
  499 + "fixedTimewindow": {
  500 + "startTimeMs": 1586176634823,
  501 + "endTimeMs": 1586263034823
  502 + }
  503 + },
  504 + "aggregation": {
  505 + "type": "AVG",
  506 + "limit": 25000
  507 + }
  508 + },
  509 + "settings": {
  510 + "stateControllerId": "entity",
  511 + "showTitle": false,
  512 + "showDashboardsSelect": true,
  513 + "showEntitiesSelect": true,
  514 + "showDashboardTimewindow": true,
  515 + "showDashboardExport": true,
  516 + "toolbarAlwaysOpen": true
  517 + }
  518 + },
  519 + "name": "Rule Engine Statistics"
  520 +}
@@ -123,3 +123,28 @@ BEGIN @@ -123,3 +123,28 @@ BEGIN
123 END LOOP; 123 END LOOP;
124 END 124 END
125 $$; 125 $$;
  126 +
  127 +CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint)
  128 + LANGUAGE plpgsql AS
  129 +$$
  130 +DECLARE
  131 + ttl_ts bigint;
  132 + debug_ttl_ts bigint;
  133 + ttl_deleted_count bigint DEFAULT 0;
  134 + debug_ttl_deleted_count bigint DEFAULT 0;
  135 +BEGIN
  136 + IF ttl > 0 THEN
  137 + ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint;
  138 + EXECUTE format(
  139 + 'WITH deleted AS (DELETE FROM event WHERE ts < %L::bigint AND (event_type != %L::varchar AND event_type != %L::varchar) RETURNING *) SELECT count(*) FROM deleted', ttl_ts, 'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into ttl_deleted_count;
  140 + END IF;
  141 + IF debug_ttl > 0 THEN
  142 + debug_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - debug_ttl::bigint * 1000)::bigint;
  143 + EXECUTE format(
  144 + 'WITH deleted AS (DELETE FROM event WHERE ts < %L::bigint AND (event_type = %L::varchar OR event_type = %L::varchar) RETURNING *) SELECT count(*) FROM deleted', debug_ttl_ts, 'DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN') into debug_ttl_deleted_count;
  145 + END IF;
  146 + RAISE NOTICE 'Events removed by ttl: %', ttl_deleted_count;
  147 + RAISE NOTICE 'Debug Events removed by ttl: %', debug_ttl_deleted_count;
  148 + deleted := ttl_deleted_count + debug_ttl_deleted_count;
  149 +END
  150 +$$;
@@ -32,12 +32,10 @@ import lombok.Setter; @@ -32,12 +32,10 @@ import lombok.Setter;
32 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
33 import org.springframework.beans.factory.annotation.Autowired; 33 import org.springframework.beans.factory.annotation.Autowired;
34 import org.springframework.beans.factory.annotation.Value; 34 import org.springframework.beans.factory.annotation.Value;
35 -import org.springframework.context.annotation.Lazy;  
36 import org.springframework.data.redis.core.RedisTemplate; 35 import org.springframework.data.redis.core.RedisTemplate;
37 import org.springframework.scheduling.annotation.Scheduled; 36 import org.springframework.scheduling.annotation.Scheduled;
38 import org.springframework.stereotype.Component; 37 import org.springframework.stereotype.Component;
39 import org.thingsboard.rule.engine.api.MailService; 38 import org.thingsboard.rule.engine.api.MailService;
40 -import org.thingsboard.rule.engine.api.RuleChainTransactionService;  
41 import org.thingsboard.server.actors.service.ActorService; 39 import org.thingsboard.server.actors.service.ActorService;
42 import org.thingsboard.server.actors.tenant.DebugTbRateLimits; 40 import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
43 import org.thingsboard.server.common.data.DataConstants; 41 import org.thingsboard.server.common.data.DataConstants;
@@ -45,10 +43,11 @@ import org.thingsboard.server.common.data.Event; @@ -45,10 +43,11 @@ import org.thingsboard.server.common.data.Event;
45 import org.thingsboard.server.common.data.id.EntityId; 43 import org.thingsboard.server.common.data.id.EntityId;
46 import org.thingsboard.server.common.data.id.TenantId; 44 import org.thingsboard.server.common.data.id.TenantId;
47 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 45 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
  46 +import org.thingsboard.server.common.msg.TbActorMsg;
48 import org.thingsboard.server.common.msg.TbMsg; 47 import org.thingsboard.server.common.msg.TbMsg;
49 -import org.thingsboard.server.common.msg.cluster.ServerAddress; 48 +import org.thingsboard.server.common.msg.queue.ServiceType;
  49 +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
50 import org.thingsboard.server.common.msg.tools.TbRateLimits; 50 import org.thingsboard.server.common.msg.tools.TbRateLimits;
51 -import org.thingsboard.server.common.transport.auth.DeviceAuthService;  
52 import org.thingsboard.server.dao.alarm.AlarmService; 51 import org.thingsboard.server.dao.alarm.AlarmService;
53 import org.thingsboard.server.dao.asset.AssetService; 52 import org.thingsboard.server.dao.asset.AssetService;
54 import org.thingsboard.server.dao.attributes.AttributesService; 53 import org.thingsboard.server.dao.attributes.AttributesService;
@@ -65,24 +64,23 @@ import org.thingsboard.server.dao.rule.RuleChainService; @@ -65,24 +64,23 @@ import org.thingsboard.server.dao.rule.RuleChainService;
65 import org.thingsboard.server.dao.tenant.TenantService; 64 import org.thingsboard.server.dao.tenant.TenantService;
66 import org.thingsboard.server.dao.timeseries.TimeseriesService; 65 import org.thingsboard.server.dao.timeseries.TimeseriesService;
67 import org.thingsboard.server.dao.user.UserService; 66 import org.thingsboard.server.dao.user.UserService;
68 -import org.thingsboard.server.kafka.TbNodeIdProvider;  
69 -import org.thingsboard.server.service.cluster.discovery.DiscoveryService;  
70 -import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;  
71 -import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; 67 +import org.thingsboard.server.queue.discovery.PartitionService;
  68 +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
72 import org.thingsboard.server.service.component.ComponentDiscoveryService; 69 import org.thingsboard.server.service.component.ComponentDiscoveryService;
73 import org.thingsboard.server.service.encoding.DataDecodingEncodingService; 70 import org.thingsboard.server.service.encoding.DataDecodingEncodingService;
74 -import org.thingsboard.server.service.executors.ClusterRpcCallbackExecutorService;  
75 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 71 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
76 import org.thingsboard.server.service.executors.ExternalCallExecutorService; 72 import org.thingsboard.server.service.executors.ExternalCallExecutorService;
77 import org.thingsboard.server.service.executors.SharedEventLoopGroupService; 73 import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
78 import org.thingsboard.server.service.mail.MailExecutorService; 74 import org.thingsboard.server.service.mail.MailExecutorService;
79 -import org.thingsboard.server.service.rpc.DeviceRpcService; 75 +import org.thingsboard.server.service.queue.TbClusterService;
  76 +import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
  77 +import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
80 import org.thingsboard.server.service.script.JsExecutorService; 78 import org.thingsboard.server.service.script.JsExecutorService;
81 import org.thingsboard.server.service.script.JsInvokeService; 79 import org.thingsboard.server.service.script.JsInvokeService;
82 import org.thingsboard.server.service.session.DeviceSessionCacheService; 80 import org.thingsboard.server.service.session.DeviceSessionCacheService;
83 import org.thingsboard.server.service.state.DeviceStateService; 81 import org.thingsboard.server.service.state.DeviceStateService;
84 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; 82 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
85 -import org.thingsboard.server.service.transport.RuleEngineTransportService; 83 +import org.thingsboard.server.service.transport.TbCoreToTransportService;
86 84
87 import javax.annotation.Nullable; 85 import javax.annotation.Nullable;
88 import java.io.IOException; 86 import java.io.IOException;
@@ -106,13 +104,14 @@ public class ActorSystemContext { @@ -106,13 +104,14 @@ public class ActorSystemContext {
106 return debugPerTenantLimits; 104 return debugPerTenantLimits;
107 } 105 }
108 106
  107 + @Autowired
109 @Getter 108 @Getter
110 @Setter 109 @Setter
111 - private ActorService actorService; 110 + private TbServiceInfoProvider serviceInfoProvider;
112 111
113 - @Autowired  
114 @Getter 112 @Getter
115 - private DiscoveryService discoveryService; 113 + @Setter
  114 + private ActorService actorService;
116 115
117 @Autowired 116 @Autowired
118 @Getter 117 @Getter
@@ -121,22 +120,10 @@ public class ActorSystemContext { @@ -121,22 +120,10 @@ public class ActorSystemContext {
121 120
122 @Autowired 121 @Autowired
123 @Getter 122 @Getter
124 - private ClusterRoutingService routingService;  
125 -  
126 - @Autowired  
127 - @Getter  
128 - private ClusterRpcService rpcService;  
129 -  
130 - @Autowired  
131 - @Getter  
132 private DataDecodingEncodingService encodingService; 123 private DataDecodingEncodingService encodingService;
133 124
134 @Autowired 125 @Autowired
135 @Getter 126 @Getter
136 - private DeviceAuthService deviceAuthService;  
137 -  
138 - @Autowired  
139 - @Getter  
140 private DeviceService deviceService; 127 private DeviceService deviceService;
141 128
142 @Autowired 129 @Autowired
@@ -164,6 +151,13 @@ public class ActorSystemContext { @@ -164,6 +151,13 @@ public class ActorSystemContext {
164 private RuleChainService ruleChainService; 151 private RuleChainService ruleChainService;
165 152
166 @Autowired 153 @Autowired
  154 + private PartitionService partitionService;
  155 +
  156 + @Autowired
  157 + @Getter
  158 + private TbClusterService clusterService;
  159 +
  160 + @Autowired
167 @Getter 161 @Getter
168 private TimeseriesService tsService; 162 private TimeseriesService tsService;
169 163
@@ -197,10 +191,6 @@ public class ActorSystemContext { @@ -197,10 +191,6 @@ public class ActorSystemContext {
197 191
198 @Autowired 192 @Autowired
199 @Getter 193 @Getter
200 - private DeviceRpcService deviceRpcService;  
201 -  
202 - @Autowired  
203 - @Getter  
204 private JsInvokeService jsSandbox; 194 private JsInvokeService jsSandbox;
205 195
206 @Autowired 196 @Autowired
@@ -213,10 +203,6 @@ public class ActorSystemContext { @@ -213,10 +203,6 @@ public class ActorSystemContext {
213 203
214 @Autowired 204 @Autowired
215 @Getter 205 @Getter
216 - private ClusterRpcCallbackExecutorService clusterRpcCallbackExecutor;  
217 -  
218 - @Autowired  
219 - @Getter  
220 private DbCallbackExecutorService dbCallbackExecutor; 206 private DbCallbackExecutorService dbCallbackExecutor;
221 207
222 @Autowired 208 @Autowired
@@ -231,27 +217,32 @@ public class ActorSystemContext { @@ -231,27 +217,32 @@ public class ActorSystemContext {
231 @Getter 217 @Getter
232 private MailService mailService; 218 private MailService mailService;
233 219
234 - @Autowired 220 + //TODO: separate context for TbCore and TbRuleEngine
  221 + @Autowired(required = false)
235 @Getter 222 @Getter
236 private DeviceStateService deviceStateService; 223 private DeviceStateService deviceStateService;
237 224
238 - @Autowired 225 + @Autowired(required = false)
239 @Getter 226 @Getter
240 private DeviceSessionCacheService deviceSessionCacheService; 227 private DeviceSessionCacheService deviceSessionCacheService;
241 228
242 - @Lazy  
243 - @Autowired 229 + @Autowired(required = false)
244 @Getter 230 @Getter
245 - private RuleEngineTransportService ruleEngineTransportService; 231 + private TbCoreToTransportService tbCoreToTransportService;
246 232
247 - @Lazy  
248 - @Autowired 233 + /**
  234 + * The following Service will be null if we operate in tb-core mode
  235 + */
  236 + @Autowired(required = false)
249 @Getter 237 @Getter
250 - private RuleChainTransactionService ruleChainTransactionService; 238 + private TbRuleEngineDeviceRpcService tbRuleEngineDeviceRpcService;
251 239
252 - @Value("${cluster.partition_id}") 240 + /**
  241 + * The following Service will be null if we operate in tb-rule-engine mode
  242 + */
  243 + @Autowired(required = false)
253 @Getter 244 @Getter
254 - private long queuePartitionId; 245 + private TbCoreDeviceRpcService tbCoreDeviceRpcService;
255 246
256 @Value("${actors.session.max_concurrent_sessions_per_device:1}") 247 @Value("${actors.session.max_concurrent_sessions_per_device:1}")
257 @Getter 248 @Getter
@@ -269,10 +260,6 @@ public class ActorSystemContext { @@ -269,10 +260,6 @@ public class ActorSystemContext {
269 @Getter 260 @Getter
270 private long queuePersistenceTimeout; 261 private long queuePersistenceTimeout;
271 262
272 - @Value("${actors.client_side_rpc.timeout}")  
273 - @Getter  
274 - private long clientSideRpcTimeout;  
275 -  
276 @Value("${actors.rule.chain.error_persist_frequency}") 263 @Value("${actors.rule.chain.error_persist_frequency}")
277 @Getter 264 @Getter
278 private long ruleChainErrorPersistFrequency; 265 private long ruleChainErrorPersistFrequency;
@@ -334,11 +321,6 @@ public class ActorSystemContext { @@ -334,11 +321,6 @@ public class ActorSystemContext {
334 @Setter 321 @Setter
335 private ActorSystem actorSystem; 322 private ActorSystem actorSystem;
336 323
337 - @Autowired  
338 - @Getter  
339 - private TbNodeIdProvider nodeIdProvider;  
340 -  
341 - @Getter  
342 @Setter 324 @Setter
343 private ActorRef appActor; 325 private ActorRef appActor;
344 326
@@ -365,6 +347,8 @@ public class ActorSystemContext { @@ -365,6 +347,8 @@ public class ActorSystemContext {
365 config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); 347 config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load());
366 } 348 }
367 349
  350 +
  351 +
368 public Scheduler getScheduler() { 352 public Scheduler getScheduler() {
369 return actorSystem.scheduler(); 353 return actorSystem.scheduler();
370 } 354 }
@@ -374,7 +358,7 @@ public class ActorSystemContext { @@ -374,7 +358,7 @@ public class ActorSystemContext {
374 event.setTenantId(tenantId); 358 event.setTenantId(tenantId);
375 event.setEntityId(entityId); 359 event.setEntityId(entityId);
376 event.setType(DataConstants.ERROR); 360 event.setType(DataConstants.ERROR);
377 - event.setBody(toBodyJson(discoveryService.getCurrentServer().getServerAddress(), method, toString(e))); 361 + event.setBody(toBodyJson(serviceInfoProvider.getServiceInfo().getServiceId(), method, toString(e)));
378 persistEvent(event); 362 persistEvent(event);
379 } 363 }
380 364
@@ -383,7 +367,7 @@ public class ActorSystemContext { @@ -383,7 +367,7 @@ public class ActorSystemContext {
383 event.setTenantId(tenantId); 367 event.setTenantId(tenantId);
384 event.setEntityId(entityId); 368 event.setEntityId(entityId);
385 event.setType(DataConstants.LC_EVENT); 369 event.setType(DataConstants.LC_EVENT);
386 - event.setBody(toBodyJson(discoveryService.getCurrentServer().getServerAddress(), lcEvent, Optional.ofNullable(e))); 370 + event.setBody(toBodyJson(serviceInfoProvider.getServiceInfo().getServiceId(), lcEvent, Optional.ofNullable(e)));
387 persistEvent(event); 371 persistEvent(event);
388 } 372 }
389 373
@@ -397,8 +381,8 @@ public class ActorSystemContext { @@ -397,8 +381,8 @@ public class ActorSystemContext {
397 return sw.toString(); 381 return sw.toString();
398 } 382 }
399 383
400 - private JsonNode toBodyJson(ServerAddress server, ComponentLifecycleEvent event, Optional<Exception> e) {  
401 - ObjectNode node = mapper.createObjectNode().put("server", server.toString()).put("event", event.name()); 384 + private JsonNode toBodyJson(String serviceId, ComponentLifecycleEvent event, Optional<Exception> e) {
  385 + ObjectNode node = mapper.createObjectNode().put("server", serviceId).put("event", event.name());
402 if (e.isPresent()) { 386 if (e.isPresent()) {
403 node = node.put("success", false); 387 node = node.put("success", false);
404 node = node.put("error", toString(e.get())); 388 node = node.put("error", toString(e.get()));
@@ -408,12 +392,21 @@ public class ActorSystemContext { @@ -408,12 +392,21 @@ public class ActorSystemContext {
408 return node; 392 return node;
409 } 393 }
410 394
411 - private JsonNode toBodyJson(ServerAddress server, String method, String body) {  
412 - return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body); 395 + private JsonNode toBodyJson(String serviceId, String method, String body) {
  396 + return mapper.createObjectNode().put("server", serviceId).put("method", method).put("error", body);
413 } 397 }
414 398
415 - public String getServerAddress() {  
416 - return discoveryService.getCurrentServer().getServerAddress().toString(); 399 + public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId) {
  400 + return partitionService.resolve(serviceType, tenantId, entityId);
  401 + }
  402 +
  403 + public TopicPartitionInfo resolve(ServiceType serviceType, String queueName, TenantId tenantId, EntityId entityId) {
  404 + return partitionService.resolve(serviceType, queueName, tenantId, entityId);
  405 + }
  406 +
  407 +
  408 + public String getServiceId() {
  409 + return serviceInfoProvider.getServiceId();
417 } 410 }
418 411
419 public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType) { 412 public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType) {
@@ -444,7 +437,7 @@ public class ActorSystemContext { @@ -444,7 +437,7 @@ public class ActorSystemContext {
444 437
445 ObjectNode node = mapper.createObjectNode() 438 ObjectNode node = mapper.createObjectNode()
446 .put("type", type) 439 .put("type", type)
447 - .put("server", getServerAddress()) 440 + .put("server", getServiceId())
448 .put("entityId", tbMsg.getOriginator().getId().toString()) 441 .put("entityId", tbMsg.getOriginator().getId().toString())
449 .put("entityName", tbMsg.getOriginator().getEntityType().name()) 442 .put("entityName", tbMsg.getOriginator().getEntityType().name())
450 .put("msgId", tbMsg.getId().toString()) 443 .put("msgId", tbMsg.getId().toString())
@@ -504,7 +497,7 @@ public class ActorSystemContext { @@ -504,7 +497,7 @@ public class ActorSystemContext {
504 497
505 ObjectNode node = mapper.createObjectNode() 498 ObjectNode node = mapper.createObjectNode()
506 //todo: what fields are needed here? 499 //todo: what fields are needed here?
507 - .put("server", getServerAddress()) 500 + .put("server", getServiceId())
508 .put("message", "Reached debug mode rate limit!"); 501 .put("message", "Reached debug mode rate limit!");
509 502
510 if (error != null) { 503 if (error != null) {
@@ -530,4 +523,7 @@ public class ActorSystemContext { @@ -530,4 +523,7 @@ public class ActorSystemContext {
530 return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); 523 return Exception.class.isInstance(error) ? (Exception) error : new Exception(error);
531 } 524 }
532 525
  526 + public void tell(TbActorMsg tbActorMsg, ActorRef sender) {
  527 + appActor.tell(tbActorMsg, sender);
  528 + }
533 } 529 }
@@ -20,19 +20,13 @@ import akka.actor.LocalActorRef; @@ -20,19 +20,13 @@ import akka.actor.LocalActorRef;
20 import akka.actor.OneForOneStrategy; 20 import akka.actor.OneForOneStrategy;
21 import akka.actor.Props; 21 import akka.actor.Props;
22 import akka.actor.SupervisorStrategy; 22 import akka.actor.SupervisorStrategy;
23 -import akka.actor.SupervisorStrategy.Directive;  
24 import akka.actor.Terminated; 23 import akka.actor.Terminated;
25 -import akka.event.Logging;  
26 -import akka.event.LoggingAdapter;  
27 -import akka.japi.Function;  
28 import com.google.common.collect.BiMap; 24 import com.google.common.collect.BiMap;
29 import com.google.common.collect.HashBiMap; 25 import com.google.common.collect.HashBiMap;
30 -import lombok.extern.slf4j.Slf4j;  
31 import org.thingsboard.server.actors.ActorSystemContext; 26 import org.thingsboard.server.actors.ActorSystemContext;
32 -import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; 27 +import org.thingsboard.server.actors.service.ContextAwareActor;
33 import org.thingsboard.server.actors.service.ContextBasedCreator; 28 import org.thingsboard.server.actors.service.ContextBasedCreator;
34 import org.thingsboard.server.actors.service.DefaultActorService; 29 import org.thingsboard.server.actors.service.DefaultActorService;
35 -import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager;  
36 import org.thingsboard.server.actors.tenant.TenantActor; 30 import org.thingsboard.server.actors.tenant.TenantActor;
37 import org.thingsboard.server.common.data.EntityType; 31 import org.thingsboard.server.common.data.EntityType;
38 import org.thingsboard.server.common.data.Tenant; 32 import org.thingsboard.server.common.data.Tenant;
@@ -42,29 +36,32 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; @@ -42,29 +36,32 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
42 import org.thingsboard.server.common.msg.MsgType; 36 import org.thingsboard.server.common.msg.MsgType;
43 import org.thingsboard.server.common.msg.TbActorMsg; 37 import org.thingsboard.server.common.msg.TbActorMsg;
44 import org.thingsboard.server.common.msg.aware.TenantAwareMsg; 38 import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
45 -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;  
46 -import org.thingsboard.server.common.msg.cluster.ServerAddress;  
47 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 39 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
48 -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; 40 +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
  41 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  42 +import org.thingsboard.server.common.msg.queue.ServiceType;
49 import org.thingsboard.server.dao.model.ModelConstants; 43 import org.thingsboard.server.dao.model.ModelConstants;
50 import org.thingsboard.server.dao.tenant.TenantService; 44 import org.thingsboard.server.dao.tenant.TenantService;
  45 +import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
51 import scala.concurrent.duration.Duration; 46 import scala.concurrent.duration.Duration;
52 47
53 -import java.util.HashMap;  
54 -import java.util.Map; 48 +import java.util.HashSet;
55 import java.util.Optional; 49 import java.util.Optional;
  50 +import java.util.Set;
56 51
57 -public class AppActor extends RuleChainManagerActor { 52 +public class AppActor extends ContextAwareActor {
58 53
59 private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); 54 private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
60 private final TenantService tenantService; 55 private final TenantService tenantService;
61 private final BiMap<TenantId, ActorRef> tenantActors; 56 private final BiMap<TenantId, ActorRef> tenantActors;
  57 + private final Set<TenantId> deletedTenants;
62 private boolean ruleChainsInitialized; 58 private boolean ruleChainsInitialized;
63 59
64 private AppActor(ActorSystemContext systemContext) { 60 private AppActor(ActorSystemContext systemContext) {
65 - super(systemContext, new SystemRuleChainManager(systemContext)); 61 + super(systemContext);
66 this.tenantService = systemContext.getTenantService(); 62 this.tenantService = systemContext.getTenantService();
67 this.tenantActors = HashBiMap.create(); 63 this.tenantActors = HashBiMap.create();
  64 + this.deletedTenants = new HashSet<>();
68 } 65 }
69 66
70 @Override 67 @Override
@@ -79,7 +76,7 @@ public class AppActor extends RuleChainManagerActor { @@ -79,7 +76,7 @@ public class AppActor extends RuleChainManagerActor {
79 @Override 76 @Override
80 protected boolean process(TbActorMsg msg) { 77 protected boolean process(TbActorMsg msg) {
81 if (!ruleChainsInitialized) { 78 if (!ruleChainsInitialized) {
82 - initRuleChainsAndTenantActors(); 79 + initTenantActors();
83 ruleChainsInitialized = true; 80 ruleChainsInitialized = true;
84 if (msg.getMsgType() != MsgType.APP_INIT_MSG) { 81 if (msg.getMsgType() != MsgType.APP_INIT_MSG) {
85 log.warn("Rule Chains initialized by unexpected message: {}", msg); 82 log.warn("Rule Chains initialized by unexpected message: {}", msg);
@@ -88,17 +85,14 @@ public class AppActor extends RuleChainManagerActor { @@ -88,17 +85,14 @@ public class AppActor extends RuleChainManagerActor {
88 switch (msg.getMsgType()) { 85 switch (msg.getMsgType()) {
89 case APP_INIT_MSG: 86 case APP_INIT_MSG:
90 break; 87 break;
91 - case SEND_TO_CLUSTER_MSG:  
92 - onPossibleClusterMsg((SendToClusterMsg) msg);  
93 - break;  
94 - case CLUSTER_EVENT_MSG: 88 + case PARTITION_CHANGE_MSG:
95 broadcast(msg); 89 broadcast(msg);
96 break; 90 break;
97 case COMPONENT_LIFE_CYCLE_MSG: 91 case COMPONENT_LIFE_CYCLE_MSG:
98 onComponentLifecycleMsg((ComponentLifecycleMsg) msg); 92 onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
99 break; 93 break;
100 - case SERVICE_TO_RULE_ENGINE_MSG:  
101 - onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); 94 + case QUEUE_TO_RULE_ENGINE_MSG:
  95 + onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg);
102 break; 96 break;
103 case TRANSPORT_TO_DEVICE_ACTOR_MSG: 97 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
104 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 98 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
@@ -106,7 +100,6 @@ public class AppActor extends RuleChainManagerActor { @@ -106,7 +100,6 @@ public class AppActor extends RuleChainManagerActor {
106 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: 100 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
107 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 101 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
108 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: 102 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
109 - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:  
110 onToDeviceActorMsg((TenantAwareMsg) msg); 103 onToDeviceActorMsg((TenantAwareMsg) msg);
111 break; 104 break;
112 default: 105 default:
@@ -115,16 +108,30 @@ public class AppActor extends RuleChainManagerActor { @@ -115,16 +108,30 @@ public class AppActor extends RuleChainManagerActor {
115 return true; 108 return true;
116 } 109 }
117 110
118 - private void initRuleChainsAndTenantActors() { 111 + private void initTenantActors() {
119 log.info("Starting main system actor."); 112 log.info("Starting main system actor.");
120 try { 113 try {
121 - initRuleChains();  
122 - if (systemContext.isTenantComponentsInitEnabled()) {  
123 - PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);  
124 - for (Tenant tenant : tenantIterator) { 114 + // This Service may be started for specific tenant only.
  115 + Optional<TenantId> isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant();
  116 + if (isolatedTenantId.isPresent()) {
  117 + Tenant tenant = systemContext.getTenantService().findTenantById(isolatedTenantId.get());
  118 + if (tenant != null) {
125 log.debug("[{}] Creating tenant actor", tenant.getId()); 119 log.debug("[{}] Creating tenant actor", tenant.getId());
126 getOrCreateTenantActor(tenant.getId()); 120 getOrCreateTenantActor(tenant.getId());
127 log.debug("Tenant actor created."); 121 log.debug("Tenant actor created.");
  122 + } else {
  123 + log.error("[{}] Tenant with such ID does not exist", isolatedTenantId.get());
  124 + }
  125 + } else if (systemContext.isTenantComponentsInitEnabled()) {
  126 + PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);
  127 + boolean isRuleEngine = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE);
  128 + boolean isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE);
  129 + for (Tenant tenant : tenantIterator) {
  130 + if (isCore || (isRuleEngine && !tenant.isIsolatedTbRuleEngine())) {
  131 + log.debug("[{}] Creating tenant actor", tenant.getId());
  132 + getOrCreateTenantActor(tenant.getId());
  133 + log.debug("[{}] Tenant actor created.", tenant.getId());
  134 + }
128 } 135 }
129 } 136 }
130 log.info("Main system actor started."); 137 log.info("Main system actor started.");
@@ -133,40 +140,33 @@ public class AppActor extends RuleChainManagerActor { @@ -133,40 +140,33 @@ public class AppActor extends RuleChainManagerActor {
133 } 140 }
134 } 141 }
135 142
136 - private void onPossibleClusterMsg(SendToClusterMsg msg) {  
137 - Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId());  
138 - if (address.isPresent()) {  
139 - systemContext.getRpcService().tell(  
140 - systemContext.getEncodingService().convertToProtoDataMessage(address.get(), msg.getMsg()));  
141 - } else {  
142 - self().tell(msg.getMsg(), ActorRef.noSender());  
143 - }  
144 - }  
145 -  
146 - private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { 143 + private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) {
147 if (SYSTEM_TENANT.equals(msg.getTenantId())) { 144 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
148 -// this may be a notification about system entities created.  
149 -// log.warn("[{}] Invalid service to rule engine msg called. System messages are not supported yet: {}", SYSTEM_TENANT, msg); 145 + msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!"));
150 } else { 146 } else {
151 - getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); 147 + if (!deletedTenants.contains(msg.getTenantId())) {
  148 + getOrCreateTenantActor(msg.getTenantId()).tell(msg, self());
  149 + } else {
  150 + msg.getTbMsg().getCallback().onSuccess();
  151 + }
152 } 152 }
153 } 153 }
154 154
155 - @Override  
156 protected void broadcast(Object msg) { 155 protected void broadcast(Object msg) {
157 - super.broadcast(msg);  
158 tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); 156 tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
159 } 157 }
160 158
161 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 159 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
162 ActorRef target = null; 160 ActorRef target = null;
163 if (SYSTEM_TENANT.equals(msg.getTenantId())) { 161 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
164 - target = getEntityActorRef(msg.getEntityId()); 162 + log.warn("Message has system tenant id: {}", msg);
165 } else { 163 } else {
166 if (msg.getEntityId().getEntityType() == EntityType.TENANT 164 if (msg.getEntityId().getEntityType() == EntityType.TENANT
167 && msg.getEvent() == ComponentLifecycleEvent.DELETED) { 165 && msg.getEvent() == ComponentLifecycleEvent.DELETED) {
168 - log.debug("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg);  
169 - ActorRef tenantActor = tenantActors.remove(new TenantId(msg.getEntityId().getId())); 166 + log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg);
  167 + TenantId tenantId = new TenantId(msg.getEntityId().getId());
  168 + deletedTenants.add(tenantId);
  169 + ActorRef tenantActor = tenantActors.get(tenantId);
170 if (tenantActor != null) { 170 if (tenantActor != null) {
171 log.debug("[{}] Deleting tenant actor: {}", msg.getTenantId(), tenantActor); 171 log.debug("[{}] Deleting tenant actor: {}", msg.getTenantId(), tenantActor);
172 context().stop(tenantActor); 172 context().stop(tenantActor);
@@ -183,16 +183,22 @@ public class AppActor extends RuleChainManagerActor { @@ -183,16 +183,22 @@ public class AppActor extends RuleChainManagerActor {
183 } 183 }
184 184
185 private void onToDeviceActorMsg(TenantAwareMsg msg) { 185 private void onToDeviceActorMsg(TenantAwareMsg msg) {
186 - getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); 186 + if (!deletedTenants.contains(msg.getTenantId())) {
  187 + getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender());
  188 + } else {
  189 + if (msg instanceof TransportToDeviceActorMsgWrapper) {
  190 + ((TransportToDeviceActorMsgWrapper) msg).getCallback().onSuccess();
  191 + }
  192 + }
187 } 193 }
188 194
189 private ActorRef getOrCreateTenantActor(TenantId tenantId) { 195 private ActorRef getOrCreateTenantActor(TenantId tenantId) {
190 return tenantActors.computeIfAbsent(tenantId, k -> { 196 return tenantActors.computeIfAbsent(tenantId, k -> {
191 - log.debug("[{}] Creating tenant actor.", tenantId); 197 + log.info("[{}] Creating tenant actor.", tenantId);
192 ActorRef tenantActor = context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId)) 198 ActorRef tenantActor = context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId))
193 .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString()); 199 .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString());
194 context().watch(tenantActor); 200 context().watch(tenantActor);
195 - log.debug("[{}] Created tenant actor: {}.", tenantId, tenantActor); 201 + log.info("[{}] Created tenant actor: {}.", tenantId, tenantActor);
196 return tenantActor; 202 return tenantActor;
197 }); 203 });
198 } 204 }
@@ -22,10 +22,8 @@ import org.thingsboard.server.actors.service.ContextAwareActor; @@ -22,10 +22,8 @@ import org.thingsboard.server.actors.service.ContextAwareActor;
22 import org.thingsboard.server.common.data.id.DeviceId; 22 import org.thingsboard.server.common.data.id.DeviceId;
23 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.msg.TbActorMsg; 24 import org.thingsboard.server.common.msg.TbActorMsg;
25 -import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;  
26 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; 25 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
27 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 26 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
28 -import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;  
29 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; 27 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
30 28
31 public class DeviceActor extends ContextAwareActor { 29 public class DeviceActor extends ContextAwareActor {
@@ -49,6 +47,11 @@ public class DeviceActor extends ContextAwareActor { @@ -49,6 +47,11 @@ public class DeviceActor extends ContextAwareActor {
49 } 47 }
50 48
51 @Override 49 @Override
  50 + public void postStop() {
  51 +
  52 + }
  53 +
  54 + @Override
52 protected boolean process(TbActorMsg msg) { 55 protected boolean process(TbActorMsg msg) {
53 switch (msg.getMsgType()) { 56 switch (msg.getMsgType()) {
54 case TRANSPORT_TO_DEVICE_ACTOR_MSG: 57 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
@@ -66,15 +69,9 @@ public class DeviceActor extends ContextAwareActor { @@ -66,15 +69,9 @@ public class DeviceActor extends ContextAwareActor {
66 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 69 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
67 processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg); 70 processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg);
68 break; 71 break;
69 - case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:  
70 - processor.processToServerRPCResponse(context(), (ToServerRpcResponseActorMsg) msg);  
71 - break;  
72 case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: 72 case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG:
73 processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg); 73 processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg);
74 break; 74 break;
75 - case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG:  
76 - processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg);  
77 - break;  
78 case SESSION_TIMEOUT_MSG: 75 case SESSION_TIMEOUT_MSG:
79 processor.checkSessionsTimeout(); 76 processor.checkSessionsTimeout();
80 break; 77 break;
@@ -16,13 +16,10 @@ @@ -16,13 +16,10 @@
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 import akka.actor.ActorContext; 18 import akka.actor.ActorContext;
19 -import com.datastax.driver.core.utils.UUIDs;  
20 import com.google.common.util.concurrent.FutureCallback; 19 import com.google.common.util.concurrent.FutureCallback;
21 import com.google.common.util.concurrent.Futures; 20 import com.google.common.util.concurrent.Futures;
22 import com.google.common.util.concurrent.ListenableFuture; 21 import com.google.common.util.concurrent.ListenableFuture;
23 import com.google.common.util.concurrent.MoreExecutors; 22 import com.google.common.util.concurrent.MoreExecutors;
24 -import com.google.gson.Gson;  
25 -import com.google.gson.JsonObject;  
26 import com.google.protobuf.InvalidProtocolBufferException; 23 import com.google.protobuf.InvalidProtocolBufferException;
27 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
28 import org.apache.commons.collections.CollectionUtils; 25 import org.apache.commons.collections.CollectionUtils;
@@ -38,38 +35,34 @@ import org.thingsboard.server.common.data.kv.AttributeKey; @@ -38,38 +35,34 @@ import org.thingsboard.server.common.data.kv.AttributeKey;
38 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 35 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
39 import org.thingsboard.server.common.data.kv.KvEntry; 36 import org.thingsboard.server.common.data.kv.KvEntry;
40 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; 37 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
41 -import org.thingsboard.server.common.msg.TbMsg;  
42 -import org.thingsboard.server.common.msg.TbMsgDataType;  
43 import org.thingsboard.server.common.msg.TbMsgMetaData; 38 import org.thingsboard.server.common.msg.TbMsgMetaData;
  39 +import org.thingsboard.server.common.msg.queue.TbCallback;
44 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 40 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
45 -import org.thingsboard.server.common.msg.session.SessionMsgType;  
46 -import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg;  
47 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; 41 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
48 -import org.thingsboard.server.gen.transport.TransportProtos;  
49 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; 42 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
50 -import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; 43 +import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry;
51 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; 44 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
52 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; 45 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
53 import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; 46 import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto;
54 import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; 47 import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType;
55 -import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;  
56 -import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;  
57 import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; 48 import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
58 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; 49 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
59 import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg; 50 import org.thingsboard.server.gen.transport.TransportProtos.SessionEventMsg;
60 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 51 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
  52 +import org.thingsboard.server.gen.transport.TransportProtos.SessionSubscriptionInfoProto;
  53 +import org.thingsboard.server.gen.transport.TransportProtos.SessionType;
61 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg; 54 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToAttributeUpdatesMsg;
62 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg; 55 import org.thingsboard.server.gen.transport.TransportProtos.SubscribeToRPCMsg;
  56 +import org.thingsboard.server.gen.transport.TransportProtos.SubscriptionInfoProto;
63 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; 57 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
64 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg; 58 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
  59 +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
  60 +import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
65 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; 61 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
66 -import org.thingsboard.server.gen.transport.TransportProtos.TsKvListProto;  
67 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; 62 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
68 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 63 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
69 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 64 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
70 -import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;  
71 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; 65 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
72 -import org.thingsboard.server.utils.JsonUtils;  
73 66
74 import javax.annotation.Nullable; 67 import javax.annotation.Nullable;
75 import java.util.ArrayList; 68 import java.util.ArrayList;
@@ -100,9 +93,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -100,9 +93,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
100 private final Map<UUID, SessionInfo> attributeSubscriptions; 93 private final Map<UUID, SessionInfo> attributeSubscriptions;
101 private final Map<UUID, SessionInfo> rpcSubscriptions; 94 private final Map<UUID, SessionInfo> rpcSubscriptions;
102 private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; 95 private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap;
103 - private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap;  
104 -  
105 - private final Gson gson = new Gson();  
106 96
107 private int rpcSeq = 0; 97 private int rpcSeq = 0;
108 private String deviceName; 98 private String deviceName;
@@ -117,7 +107,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -117,7 +107,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
117 this.attributeSubscriptions = new HashMap<>(); 107 this.attributeSubscriptions = new HashMap<>();
118 this.rpcSubscriptions = new HashMap<>(); 108 this.rpcSubscriptions = new HashMap<>();
119 this.toDeviceRpcPendingMap = new HashMap<>(); 109 this.toDeviceRpcPendingMap = new HashMap<>();
120 - this.toServerRpcPendingMap = new HashMap<>();  
121 if (initAttributes()) { 110 if (initAttributes()) {
122 restoreSessions(); 111 restoreSessions();
123 } 112 }
@@ -153,7 +142,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -153,7 +142,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
153 Set<UUID> syncSessionSet = new HashSet<>(); 142 Set<UUID> syncSessionSet = new HashSet<>();
154 rpcSubscriptions.forEach((key, value) -> { 143 rpcSubscriptions.forEach((key, value) -> {
155 sendToTransport(rpcRequest, key, value.getNodeId()); 144 sendToTransport(rpcRequest, key, value.getNodeId());
156 - if (TransportProtos.SessionType.SYNC == value.getType()) { 145 + if (SessionType.SYNC == value.getType()) {
157 syncSessionSet.add(key); 146 syncSessionSet.add(key);
158 } 147 }
159 }); 148 });
@@ -161,7 +150,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -161,7 +150,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
161 150
162 if (request.isOneway() && sent) { 151 if (request.isOneway() && sent) {
163 log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); 152 log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId());
164 - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null)); 153 + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null));
165 } else { 154 } else {
166 registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); 155 registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout);
167 } 156 }
@@ -182,16 +171,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -182,16 +171,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
182 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); 171 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId());
183 if (requestMd != null) { 172 if (requestMd != null) {
184 log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); 173 log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId());
185 - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), 174 + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
186 null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); 175 null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION));
187 } 176 }
188 } 177 }
189 178
190 private void sendPendingRequests(ActorContext context, UUID sessionId, SessionInfoProto sessionInfo) { 179 private void sendPendingRequests(ActorContext context, UUID sessionId, SessionInfoProto sessionInfo) {
191 - TransportProtos.SessionType sessionType = getSessionType(sessionId); 180 + SessionType sessionType = getSessionType(sessionId);
192 if (!toDeviceRpcPendingMap.isEmpty()) { 181 if (!toDeviceRpcPendingMap.isEmpty()) {
193 log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); 182 log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId);
194 - if (sessionType == TransportProtos.SessionType.SYNC) { 183 + if (sessionType == SessionType.SYNC) {
195 log.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); 184 log.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId);
196 rpcSubscriptions.remove(sessionId); 185 rpcSubscriptions.remove(sessionId);
197 } 186 }
@@ -199,7 +188,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -199,7 +188,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
199 log.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId); 188 log.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId);
200 } 189 }
201 Set<Integer> sentOneWayIds = new HashSet<>(); 190 Set<Integer> sentOneWayIds = new HashSet<>();
202 - if (sessionType == TransportProtos.SessionType.ASYNC) { 191 + if (sessionType == SessionType.ASYNC) {
203 toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); 192 toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds));
204 } else { 193 } else {
205 toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds)); 194 toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, sessionInfo.getNodeId(), sentOneWayIds));
@@ -214,7 +203,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -214,7 +203,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
214 ToDeviceRpcRequestBody body = request.getBody(); 203 ToDeviceRpcRequestBody body = request.getBody();
215 if (request.isOneway()) { 204 if (request.isOneway()) {
216 sentOneWayIds.add(entry.getKey()); 205 sentOneWayIds.add(entry.getKey());
217 - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(request.getId(), null, null)); 206 + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(request.getId(), null, null));
218 } 207 }
219 ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId( 208 ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId(
220 entry.getKey()).setMethodName(body.getMethod()).setParams(body.getParams()).build(); 209 entry.getKey()).setMethodName(body.getMethod()).setParams(body.getParams()).build();
@@ -223,8 +212,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -223,8 +212,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
223 } 212 }
224 213
225 void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) { 214 void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) {
226 - boolean reportDeviceActivity = false;  
227 TransportToDeviceActorMsg msg = wrapper.getMsg(); 215 TransportToDeviceActorMsg msg = wrapper.getMsg();
  216 + TbCallback callback = wrapper.getCallback();
228 if (msg.hasSessionEvent()) { 217 if (msg.hasSessionEvent()) {
229 processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent()); 218 processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent());
230 } 219 }
@@ -234,34 +223,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -234,34 +223,16 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
234 if (msg.hasSubscribeToRPC()) { 223 if (msg.hasSubscribeToRPC()) {
235 processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToRPC()); 224 processSubscriptionCommands(context, msg.getSessionInfo(), msg.getSubscribeToRPC());
236 } 225 }
237 - if (msg.hasPostAttributes()) {  
238 - handlePostAttributesRequest(context, msg.getSessionInfo(), msg.getPostAttributes());  
239 - reportDeviceActivity = true;  
240 - }  
241 - if (msg.hasPostTelemetry()) {  
242 - handlePostTelemetryRequest(context, msg.getSessionInfo(), msg.getPostTelemetry());  
243 - reportDeviceActivity = true;  
244 - }  
245 if (msg.hasGetAttributes()) { 226 if (msg.hasGetAttributes()) {
246 handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes()); 227 handleGetAttributesRequest(context, msg.getSessionInfo(), msg.getGetAttributes());
247 } 228 }
248 if (msg.hasToDeviceRPCCallResponse()) { 229 if (msg.hasToDeviceRPCCallResponse()) {
249 processRpcResponses(context, msg.getSessionInfo(), msg.getToDeviceRPCCallResponse()); 230 processRpcResponses(context, msg.getSessionInfo(), msg.getToDeviceRPCCallResponse());
250 } 231 }
251 - if (msg.hasToServerRPCCallRequest()) {  
252 - handleClientSideRPCRequest(context, msg.getSessionInfo(), msg.getToServerRPCCallRequest());  
253 - reportDeviceActivity = true;  
254 - }  
255 if (msg.hasSubscriptionInfo()) { 232 if (msg.hasSubscriptionInfo()) {
256 handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); 233 handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo());
257 } 234 }
258 - if (reportDeviceActivity) {  
259 - reportLogicalDeviceActivity();  
260 - }  
261 - }  
262 -  
263 - private void reportLogicalDeviceActivity() {  
264 - systemContext.getDeviceStateService().onDeviceActivity(deviceId); 235 + callback.onSuccess();
265 } 236 }
266 237
267 private void reportSessionOpen() { 238 private void reportSessionOpen() {
@@ -326,67 +297,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -326,67 +297,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
326 return new HashSet<>(strings); 297 return new HashSet<>(strings);
327 } 298 }
328 299
329 - private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) {  
330 - JsonObject json = JsonUtils.getJsonObject(postAttributes.getKvList());  
331 - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(),  
332 - TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);  
333 - pushToRuleEngine(context, tbMsg);  
334 - }  
335 -  
336 - private void handlePostTelemetryRequest(ActorContext context, SessionInfoProto sessionInfo, PostTelemetryMsg postTelemetry) {  
337 - for (TsKvListProto tsKv : postTelemetry.getTsKvListList()) {  
338 - JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList());  
339 - TbMsgMetaData metaData = defaultMetaData.copy();  
340 - metaData.putValue("ts", tsKv.getTs() + "");  
341 - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);  
342 - pushToRuleEngine(context, tbMsg);  
343 - }  
344 - }  
345 -  
346 - private void handleClientSideRPCRequest(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.ToServerRpcRequestMsg request) {  
347 - UUID sessionId = getSessionId(sessionInfo);  
348 - JsonObject json = new JsonObject();  
349 - json.addProperty("method", request.getMethodName());  
350 - json.add("params", JsonUtils.parse(request.getParams()));  
351 -  
352 - TbMsgMetaData requestMetaData = defaultMetaData.copy();  
353 - requestMetaData.putValue("requestId", Integer.toString(request.getRequestId()));  
354 - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L);  
355 - context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self());  
356 -  
357 - scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout());  
358 - toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(sessionId, getSessionType(sessionId), sessionInfo.getNodeId()));  
359 - }  
360 -  
361 - private TransportProtos.SessionType getSessionType(UUID sessionId) {  
362 - return sessions.containsKey(sessionId) ? TransportProtos.SessionType.ASYNC : TransportProtos.SessionType.SYNC;  
363 - }  
364 -  
365 - void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) {  
366 - ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId());  
367 - if (data != null) {  
368 - log.debug("[{}] Client side RPC request [{}] timeout detected!", deviceId, msg.getId());  
369 - sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder()  
370 - .setRequestId(msg.getId()).setError("timeout").build()  
371 - , data.getSessionId(), data.getNodeId());  
372 - }  
373 - }  
374 -  
375 - void processToServerRPCResponse(ActorContext context, ToServerRpcResponseActorMsg msg) {  
376 - int requestId = msg.getMsg().getRequestId();  
377 - ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(requestId);  
378 - if (data != null) {  
379 - log.debug("[{}] Pushing reply to [{}][{}]!", deviceId, data.getNodeId(), data.getSessionId());  
380 - sendToTransport(TransportProtos.ToServerRpcResponseMsg.newBuilder()  
381 - .setRequestId(requestId).setPayload(msg.getMsg().getData()).build()  
382 - , data.getSessionId(), data.getNodeId());  
383 - } else {  
384 - log.debug("[{}][{}] Pending RPC request to server not found!", deviceId, requestId);  
385 - }  
386 - }  
387 -  
388 - private void pushToRuleEngine(ActorContext context, TbMsg tbMsg) {  
389 - context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); 300 + private SessionType getSessionType(UUID sessionId) {
  301 + return sessions.containsKey(sessionId) ? SessionType.ASYNC : SessionType.SYNC;
390 } 302 }
391 303
392 void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { 304 void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) {
@@ -434,7 +346,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -434,7 +346,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
434 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); 346 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId());
435 boolean success = requestMd != null; 347 boolean success = requestMd != null;
436 if (success) { 348 if (success) {
437 - systemContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), 349 + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
438 responseMsg.getPayload(), null)); 350 responseMsg.getPayload(), null));
439 } else { 351 } else {
440 log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); 352 log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId());
@@ -449,7 +361,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -449,7 +361,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
449 } else { 361 } else {
450 SessionInfoMetaData sessionMD = sessions.get(sessionId); 362 SessionInfoMetaData sessionMD = sessions.get(sessionId);
451 if (sessionMD == null) { 363 if (sessionMD == null) {
452 - sessionMD = new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.SYNC, sessionInfo.getNodeId())); 364 + sessionMD = new SessionInfoMetaData(new SessionInfo(SessionType.SYNC, sessionInfo.getNodeId()));
453 } 365 }
454 sessionMD.setSubscribedToAttributes(true); 366 sessionMD.setSubscribedToAttributes(true);
455 log.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); 367 log.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId);
@@ -470,7 +382,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -470,7 +382,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
470 } else { 382 } else {
471 SessionInfoMetaData sessionMD = sessions.get(sessionId); 383 SessionInfoMetaData sessionMD = sessions.get(sessionId);
472 if (sessionMD == null) { 384 if (sessionMD == null) {
473 - sessionMD = new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.SYNC, sessionInfo.getNodeId())); 385 + sessionMD = new SessionInfoMetaData(new SessionInfo(SessionType.SYNC, sessionInfo.getNodeId()));
474 } 386 }
475 sessionMD.setSubscribedToRPC(true); 387 sessionMD.setSubscribedToRPC(true);
476 log.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId); 388 log.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId);
@@ -494,10 +406,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -494,10 +406,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
494 notifyTransportAboutClosedSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); 406 notifyTransportAboutClosedSession(sessionIdToRemove, sessions.remove(sessionIdToRemove));
495 } 407 }
496 } 408 }
497 - sessions.put(sessionId, new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfo.getNodeId()))); 409 + sessions.put(sessionId, new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfo.getNodeId())));
498 if (sessions.size() == 1) { 410 if (sessions.size() == 1) {
499 reportSessionOpen(); 411 reportSessionOpen();
500 } 412 }
  413 + systemContext.getDeviceStateService().onDeviceActivity(deviceId, System.currentTimeMillis());
501 dumpSessions(); 414 dumpSessions();
502 } else if (msg.getEvent() == SessionEvent.CLOSED) { 415 } else if (msg.getEvent() == SessionEvent.CLOSED) {
503 log.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); 416 log.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId);
@@ -511,10 +424,10 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -511,10 +424,10 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
511 } 424 }
512 } 425 }
513 426
514 - private void handleSessionActivity(ActorContext context, SessionInfoProto sessionInfoProto, TransportProtos.SubscriptionInfoProto subscriptionInfo) { 427 + private void handleSessionActivity(ActorContext context, SessionInfoProto sessionInfoProto, SubscriptionInfoProto subscriptionInfo) {
515 UUID sessionId = getSessionId(sessionInfoProto); 428 UUID sessionId = getSessionId(sessionInfoProto);
516 SessionInfoMetaData sessionMD = sessions.computeIfAbsent(sessionId, 429 SessionInfoMetaData sessionMD = sessions.computeIfAbsent(sessionId,
517 - id -> new SessionInfoMetaData(new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfoProto.getNodeId()), 0L)); 430 + id -> new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfoProto.getNodeId()), 0L));
518 431
519 sessionMD.setLastActivityTime(subscriptionInfo.getLastActivityTime()); 432 sessionMD.setLastActivityTime(subscriptionInfo.getLastActivityTime());
520 sessionMD.setSubscribedToAttributes(subscriptionInfo.getAttributeSubscription()); 433 sessionMD.setSubscribedToAttributes(subscriptionInfo.getAttributeSubscription());
@@ -525,6 +438,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -525,6 +438,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
525 if (subscriptionInfo.getRpcSubscription()) { 438 if (subscriptionInfo.getRpcSubscription()) {
526 rpcSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo()); 439 rpcSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo());
527 } 440 }
  441 + systemContext.getDeviceStateService().onDeviceActivity(deviceId, subscriptionInfo.getLastActivityTime());
528 dumpSessions(); 442 dumpSessions();
529 } 443 }
530 444
@@ -536,11 +450,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -536,11 +450,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
536 } 450 }
537 451
538 private void notifyTransportAboutClosedSession(UUID sessionId, SessionInfoMetaData sessionMd) { 452 private void notifyTransportAboutClosedSession(UUID sessionId, SessionInfoMetaData sessionMd) {
539 - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() 453 + ToTransportMsg msg = ToTransportMsg.newBuilder()
540 .setSessionIdMSB(sessionId.getMostSignificantBits()) 454 .setSessionIdMSB(sessionId.getMostSignificantBits())
541 .setSessionIdLSB(sessionId.getLeastSignificantBits()) 455 .setSessionIdLSB(sessionId.getLeastSignificantBits())
542 .setSessionCloseNotification(SessionCloseNotificationProto.getDefaultInstance()).build(); 456 .setSessionCloseNotification(SessionCloseNotificationProto.getDefaultInstance()).build();
543 - systemContext.getRuleEngineTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg); 457 + systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg);
544 } 458 }
545 459
546 void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { 460 void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) {
@@ -552,35 +466,35 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -552,35 +466,35 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
552 } 466 }
553 467
554 private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { 468 private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) {
555 - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() 469 + ToTransportMsg msg = ToTransportMsg.newBuilder()
556 .setSessionIdMSB(sessionInfo.getSessionIdMSB()) 470 .setSessionIdMSB(sessionInfo.getSessionIdMSB())
557 .setSessionIdLSB(sessionInfo.getSessionIdLSB()) 471 .setSessionIdLSB(sessionInfo.getSessionIdLSB())
558 .setGetAttributesResponse(responseMsg).build(); 472 .setGetAttributesResponse(responseMsg).build();
559 - systemContext.getRuleEngineTransportService().process(sessionInfo.getNodeId(), msg); 473 + systemContext.getTbCoreToTransportService().process(sessionInfo.getNodeId(), msg);
560 } 474 }
561 475
562 private void sendToTransport(AttributeUpdateNotificationMsg notificationMsg, UUID sessionId, String nodeId) { 476 private void sendToTransport(AttributeUpdateNotificationMsg notificationMsg, UUID sessionId, String nodeId) {
563 - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() 477 + ToTransportMsg msg = ToTransportMsg.newBuilder()
564 .setSessionIdMSB(sessionId.getMostSignificantBits()) 478 .setSessionIdMSB(sessionId.getMostSignificantBits())
565 .setSessionIdLSB(sessionId.getLeastSignificantBits()) 479 .setSessionIdLSB(sessionId.getLeastSignificantBits())
566 .setAttributeUpdateNotification(notificationMsg).build(); 480 .setAttributeUpdateNotification(notificationMsg).build();
567 - systemContext.getRuleEngineTransportService().process(nodeId, msg); 481 + systemContext.getTbCoreToTransportService().process(nodeId, msg);
568 } 482 }
569 483
570 private void sendToTransport(ToDeviceRpcRequestMsg rpcMsg, UUID sessionId, String nodeId) { 484 private void sendToTransport(ToDeviceRpcRequestMsg rpcMsg, UUID sessionId, String nodeId) {
571 - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() 485 + ToTransportMsg msg = ToTransportMsg.newBuilder()
572 .setSessionIdMSB(sessionId.getMostSignificantBits()) 486 .setSessionIdMSB(sessionId.getMostSignificantBits())
573 .setSessionIdLSB(sessionId.getLeastSignificantBits()) 487 .setSessionIdLSB(sessionId.getLeastSignificantBits())
574 .setToDeviceRequest(rpcMsg).build(); 488 .setToDeviceRequest(rpcMsg).build();
575 - systemContext.getRuleEngineTransportService().process(nodeId, msg); 489 + systemContext.getTbCoreToTransportService().process(nodeId, msg);
576 } 490 }
577 491
578 - private void sendToTransport(TransportProtos.ToServerRpcResponseMsg rpcMsg, UUID sessionId, String nodeId) {  
579 - DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() 492 + private void sendToTransport(ToServerRpcResponseMsg rpcMsg, UUID sessionId, String nodeId) {
  493 + ToTransportMsg msg = ToTransportMsg.newBuilder()
580 .setSessionIdMSB(sessionId.getMostSignificantBits()) 494 .setSessionIdMSB(sessionId.getMostSignificantBits())
581 .setSessionIdLSB(sessionId.getLeastSignificantBits()) 495 .setSessionIdLSB(sessionId.getLeastSignificantBits())
582 .setToServerResponse(rpcMsg).build(); 496 .setToServerResponse(rpcMsg).build();
583 - systemContext.getRuleEngineTransportService().process(nodeId, msg); 497 + systemContext.getTbCoreToTransportService().process(nodeId, msg);
584 } 498 }
585 499
586 500
@@ -632,9 +546,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -632,9 +546,9 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
632 546
633 private void restoreSessions() { 547 private void restoreSessions() {
634 log.debug("[{}] Restoring sessions from cache", deviceId); 548 log.debug("[{}] Restoring sessions from cache", deviceId);
635 - TransportProtos.DeviceSessionsCacheEntry sessionsDump = null; 549 + DeviceSessionsCacheEntry sessionsDump = null;
636 try { 550 try {
637 - sessionsDump = TransportProtos.DeviceSessionsCacheEntry.parseFrom(systemContext.getDeviceSessionCacheService().get(deviceId)); 551 + sessionsDump = DeviceSessionsCacheEntry.parseFrom(systemContext.getDeviceSessionCacheService().get(deviceId));
638 } catch (InvalidProtocolBufferException e) { 552 } catch (InvalidProtocolBufferException e) {
639 log.warn("[{}] Failed to decode device sessions from cache", deviceId); 553 log.warn("[{}] Failed to decode device sessions from cache", deviceId);
640 return; 554 return;
@@ -643,11 +557,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -643,11 +557,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
643 log.debug("[{}] No session information found", deviceId); 557 log.debug("[{}] No session information found", deviceId);
644 return; 558 return;
645 } 559 }
646 - for (TransportProtos.SessionSubscriptionInfoProto sessionSubscriptionInfoProto : sessionsDump.getSessionsList()) { 560 + for (SessionSubscriptionInfoProto sessionSubscriptionInfoProto : sessionsDump.getSessionsList()) {
647 SessionInfoProto sessionInfoProto = sessionSubscriptionInfoProto.getSessionInfo(); 561 SessionInfoProto sessionInfoProto = sessionSubscriptionInfoProto.getSessionInfo();
648 UUID sessionId = getSessionId(sessionInfoProto); 562 UUID sessionId = getSessionId(sessionInfoProto);
649 - SessionInfo sessionInfo = new SessionInfo(TransportProtos.SessionType.ASYNC, sessionInfoProto.getNodeId());  
650 - TransportProtos.SubscriptionInfoProto subInfo = sessionSubscriptionInfoProto.getSubscriptionInfo(); 563 + SessionInfo sessionInfo = new SessionInfo(SessionType.ASYNC, sessionInfoProto.getNodeId());
  564 + SubscriptionInfoProto subInfo = sessionSubscriptionInfoProto.getSubscriptionInfo();
651 SessionInfoMetaData sessionMD = new SessionInfoMetaData(sessionInfo, subInfo.getLastActivityTime()); 565 SessionInfoMetaData sessionMD = new SessionInfoMetaData(sessionInfo, subInfo.getLastActivityTime());
652 sessions.put(sessionId, sessionMD); 566 sessions.put(sessionId, sessionMD);
653 if (subInfo.getAttributeSubscription()) { 567 if (subInfo.getAttributeSubscription()) {
@@ -665,27 +579,27 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -665,27 +579,27 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
665 579
666 private void dumpSessions() { 580 private void dumpSessions() {
667 log.debug("[{}] Dumping sessions: {}, rpc subscriptions: {}, attribute subscriptions: {} to cache", deviceId, sessions.size(), rpcSubscriptions.size(), attributeSubscriptions.size()); 581 log.debug("[{}] Dumping sessions: {}, rpc subscriptions: {}, attribute subscriptions: {} to cache", deviceId, sessions.size(), rpcSubscriptions.size(), attributeSubscriptions.size());
668 - List<TransportProtos.SessionSubscriptionInfoProto> sessionsList = new ArrayList<>(sessions.size()); 582 + List<SessionSubscriptionInfoProto> sessionsList = new ArrayList<>(sessions.size());
669 sessions.forEach((uuid, sessionMD) -> { 583 sessions.forEach((uuid, sessionMD) -> {
670 - if (sessionMD.getSessionInfo().getType() == TransportProtos.SessionType.SYNC) { 584 + if (sessionMD.getSessionInfo().getType() == SessionType.SYNC) {
671 return; 585 return;
672 } 586 }
673 SessionInfo sessionInfo = sessionMD.getSessionInfo(); 587 SessionInfo sessionInfo = sessionMD.getSessionInfo();
674 - TransportProtos.SubscriptionInfoProto subscriptionInfoProto = TransportProtos.SubscriptionInfoProto.newBuilder() 588 + SubscriptionInfoProto subscriptionInfoProto = SubscriptionInfoProto.newBuilder()
675 .setLastActivityTime(sessionMD.getLastActivityTime()) 589 .setLastActivityTime(sessionMD.getLastActivityTime())
676 .setAttributeSubscription(sessionMD.isSubscribedToAttributes()) 590 .setAttributeSubscription(sessionMD.isSubscribedToAttributes())
677 .setRpcSubscription(sessionMD.isSubscribedToRPC()).build(); 591 .setRpcSubscription(sessionMD.isSubscribedToRPC()).build();
678 - TransportProtos.SessionInfoProto sessionInfoProto = TransportProtos.SessionInfoProto.newBuilder() 592 + SessionInfoProto sessionInfoProto = SessionInfoProto.newBuilder()
679 .setSessionIdMSB(uuid.getMostSignificantBits()) 593 .setSessionIdMSB(uuid.getMostSignificantBits())
680 .setSessionIdLSB(uuid.getLeastSignificantBits()) 594 .setSessionIdLSB(uuid.getLeastSignificantBits())
681 .setNodeId(sessionInfo.getNodeId()).build(); 595 .setNodeId(sessionInfo.getNodeId()).build();
682 - sessionsList.add(TransportProtos.SessionSubscriptionInfoProto.newBuilder() 596 + sessionsList.add(SessionSubscriptionInfoProto.newBuilder()
683 .setSessionInfo(sessionInfoProto) 597 .setSessionInfo(sessionInfoProto)
684 .setSubscriptionInfo(subscriptionInfoProto).build()); 598 .setSubscriptionInfo(subscriptionInfoProto).build());
685 log.debug("[{}] Dumping session: {}", deviceId, sessionMD); 599 log.debug("[{}] Dumping session: {}", deviceId, sessionMD);
686 }); 600 });
687 systemContext.getDeviceSessionCacheService() 601 systemContext.getDeviceSessionCacheService()
688 - .put(deviceId, TransportProtos.DeviceSessionsCacheEntry.newBuilder() 602 + .put(deviceId, DeviceSessionsCacheEntry.newBuilder()
689 .addAllSessions(sessionsList).build().toByteArray()); 603 .addAllSessions(sessionsList).build().toByteArray());
690 } 604 }
691 605
@@ -706,4 +620,5 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -706,4 +620,5 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
706 dumpSessions(); 620 dumpSessions();
707 } 621 }
708 } 622 }
  623 +
709 } 624 }
1 -/**  
2 - * Copyright © 2016-2020 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.rpc;  
17 -  
18 -import akka.actor.ActorRef;  
19 -import lombok.extern.slf4j.Slf4j;  
20 -import org.thingsboard.server.actors.ActorSystemContext;  
21 -import org.thingsboard.server.actors.service.ActorService;  
22 -import org.thingsboard.server.gen.cluster.ClusterAPIProtos;  
23 -import org.thingsboard.server.service.cluster.rpc.GrpcSession;  
24 -import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener;  
25 -import org.thingsboard.server.service.executors.ClusterRpcCallbackExecutorService;  
26 -  
27 -/**  
28 - * @author Andrew Shvayka  
29 - */  
30 -@Slf4j  
31 -public class BasicRpcSessionListener implements GrpcSessionListener {  
32 -  
33 - private final ClusterRpcCallbackExecutorService callbackExecutorService;  
34 - private final ActorService service;  
35 - private final ActorRef manager;  
36 - private final ActorRef self;  
37 -  
38 - BasicRpcSessionListener(ActorSystemContext context, ActorRef manager, ActorRef self) {  
39 - this.service = context.getActorService();  
40 - this.callbackExecutorService = context.getClusterRpcCallbackExecutor();  
41 - this.manager = manager;  
42 - this.self = self;  
43 - }  
44 -  
45 - @Override  
46 - public void onConnected(GrpcSession session) {  
47 - log.info("[{}][{}] session started", session.getRemoteServer(), getType(session));  
48 - if (!session.isClient()) {  
49 - manager.tell(new RpcSessionConnectedMsg(session.getRemoteServer(), session.getSessionId()), self);  
50 - }  
51 - }  
52 -  
53 - @Override  
54 - public void onDisconnected(GrpcSession session) {  
55 - log.info("[{}][{}] session closed", session.getRemoteServer(), getType(session));  
56 - manager.tell(new RpcSessionDisconnectedMsg(session.isClient(), session.getRemoteServer()), self);  
57 - }  
58 -  
59 - @Override  
60 - public void onReceiveClusterGrpcMsg(GrpcSession session, ClusterAPIProtos.ClusterMessage clusterMessage) {  
61 - log.trace("Received session actor msg from [{}][{}]: {}", session.getRemoteServer(), getType(session), clusterMessage);  
62 - callbackExecutorService.execute(() -> {  
63 - try {  
64 - service.onReceivedMsg(session.getRemoteServer(), clusterMessage);  
65 - } catch (Exception e) {  
66 - log.debug("[{}][{}] Failed to process cluster message: {}", session.getRemoteServer(), getType(session), clusterMessage, e);  
67 - }  
68 - });  
69 - }  
70 -  
71 - @Override  
72 - public void onError(GrpcSession session, Throwable t) {  
73 - log.warn("[{}][{}] session got error -> {}", session.getRemoteServer(), getType(session), t);  
74 - manager.tell(new RpcSessionClosedMsg(session.isClient(), session.getRemoteServer()), self);  
75 - session.close();  
76 - }  
77 -  
78 - private static String getType(GrpcSession session) {  
79 - return session.isClient() ? "Client" : "Server";  
80 - }  
81 -  
82 -  
83 -}  
1 -/**  
2 - * Copyright © 2016-2020 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.rpc;  
17 -  
18 -import akka.actor.ActorRef;  
19 -import akka.actor.OneForOneStrategy;  
20 -import akka.actor.Props;  
21 -import akka.actor.SupervisorStrategy;  
22 -import akka.event.Logging;  
23 -import akka.event.LoggingAdapter;  
24 -import lombok.extern.slf4j.Slf4j;  
25 -import org.thingsboard.server.actors.ActorSystemContext;  
26 -import org.thingsboard.server.actors.service.ContextAwareActor;  
27 -import org.thingsboard.server.actors.service.ContextBasedCreator;  
28 -import org.thingsboard.server.actors.service.DefaultActorService;  
29 -import org.thingsboard.server.common.msg.TbActorMsg;  
30 -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;  
31 -import org.thingsboard.server.common.msg.cluster.ServerAddress;  
32 -import org.thingsboard.server.common.msg.cluster.ServerType;  
33 -import org.thingsboard.server.gen.cluster.ClusterAPIProtos;  
34 -import org.thingsboard.server.service.cluster.discovery.ServerInstance;  
35 -import scala.concurrent.duration.Duration;  
36 -  
37 -import java.util.*;  
38 -  
39 -/**  
40 - * @author Andrew Shvayka  
41 - */  
42 -public class RpcManagerActor extends ContextAwareActor {  
43 -  
44 - private final Map<ServerAddress, SessionActorInfo> sessionActors;  
45 - private final Map<ServerAddress, Queue<ClusterAPIProtos.ClusterMessage>> pendingMsgs;  
46 - private final ServerAddress instance;  
47 -  
48 - private RpcManagerActor(ActorSystemContext systemContext) {  
49 - super(systemContext);  
50 - this.sessionActors = new HashMap<>();  
51 - this.pendingMsgs = new HashMap<>();  
52 - this.instance = systemContext.getDiscoveryService().getCurrentServer().getServerAddress();  
53 -  
54 - systemContext.getDiscoveryService().getOtherServers().stream()  
55 - .filter(otherServer -> otherServer.getServerAddress().compareTo(instance) > 0)  
56 - .forEach(otherServer -> onCreateSessionRequest(  
57 - new RpcSessionCreateRequestMsg(UUID.randomUUID(), otherServer.getServerAddress(), null)));  
58 - }  
59 -  
60 - @Override  
61 - protected boolean process(TbActorMsg msg) {  
62 - //TODO Move everything here, to work with TbActorMsg  
63 - return false;  
64 - }  
65 -  
66 - @Override  
67 - public void onReceive(Object msg) {  
68 - if (msg instanceof ClusterAPIProtos.ClusterMessage) {  
69 - onMsg((ClusterAPIProtos.ClusterMessage) msg);  
70 - } else if (msg instanceof RpcBroadcastMsg) {  
71 - onMsg((RpcBroadcastMsg) msg);  
72 - } else if (msg instanceof RpcSessionCreateRequestMsg) {  
73 - onCreateSessionRequest((RpcSessionCreateRequestMsg) msg);  
74 - } else if (msg instanceof RpcSessionConnectedMsg) {  
75 - onSessionConnected((RpcSessionConnectedMsg) msg);  
76 - } else if (msg instanceof RpcSessionDisconnectedMsg) {  
77 - onSessionDisconnected((RpcSessionDisconnectedMsg) msg);  
78 - } else if (msg instanceof RpcSessionClosedMsg) {  
79 - onSessionClosed((RpcSessionClosedMsg) msg);  
80 - } else if (msg instanceof ClusterEventMsg) {  
81 - onClusterEvent((ClusterEventMsg) msg);  
82 - }  
83 - }  
84 -  
85 - private void onMsg(RpcBroadcastMsg msg) {  
86 - log.debug("Forwarding msg to session actors {}", msg);  
87 - sessionActors.keySet().forEach(address -> {  
88 - ClusterAPIProtos.ClusterMessage msgWithServerAddress = msg.getMsg()  
89 - .toBuilder()  
90 - .setServerAddress(ClusterAPIProtos.ServerAddress  
91 - .newBuilder()  
92 - .setHost(address.getHost())  
93 - .setPort(address.getPort())  
94 - .build())  
95 - .build();  
96 - onMsg(msgWithServerAddress);  
97 - });  
98 - pendingMsgs.values().forEach(queue -> queue.add(msg.getMsg()));  
99 - }  
100 -  
101 - private void onMsg(ClusterAPIProtos.ClusterMessage msg) {  
102 - if (msg.hasServerAddress()) {  
103 - ServerAddress address = new ServerAddress(msg.getServerAddress().getHost(), msg.getServerAddress().getPort(), ServerType.CORE);  
104 - SessionActorInfo session = sessionActors.get(address);  
105 - if (session != null) {  
106 - log.debug("{} Forwarding msg to session actor: {}", address, msg);  
107 - session.getActor().tell(msg, ActorRef.noSender());  
108 - } else {  
109 - log.debug("{} Storing msg to pending queue: {}", address, msg);  
110 - Queue<ClusterAPIProtos.ClusterMessage> queue = pendingMsgs.get(address);  
111 - if (queue == null) {  
112 - queue = new LinkedList<>();  
113 - pendingMsgs.put(new ServerAddress(  
114 - msg.getServerAddress().getHost(), msg.getServerAddress().getPort(), ServerType.CORE), queue);  
115 - }  
116 - queue.add(msg);  
117 - }  
118 - } else {  
119 - log.warn("Cluster msg doesn't have server address [{}]", msg);  
120 - }  
121 - }  
122 -  
123 - @Override  
124 - public void postStop() {  
125 - sessionActors.clear();  
126 - pendingMsgs.clear();  
127 - }  
128 -  
129 - private void onClusterEvent(ClusterEventMsg msg) {  
130 - ServerAddress server = msg.getServerAddress();  
131 - if (server.compareTo(instance) > 0) {  
132 - if (msg.isAdded()) {  
133 - onCreateSessionRequest(new RpcSessionCreateRequestMsg(UUID.randomUUID(), server, null));  
134 - } else {  
135 - onSessionClose(false, server);  
136 - }  
137 - }  
138 - }  
139 -  
140 - private void onSessionConnected(RpcSessionConnectedMsg msg) {  
141 - register(msg.getRemoteAddress(), msg.getId(), context().sender());  
142 - }  
143 -  
144 - private void onSessionDisconnected(RpcSessionDisconnectedMsg msg) {  
145 - boolean reconnect = msg.isClient() && isRegistered(msg.getRemoteAddress());  
146 - onSessionClose(reconnect, msg.getRemoteAddress());  
147 - }  
148 -  
149 - private void onSessionClosed(RpcSessionClosedMsg msg) {  
150 - boolean reconnect = msg.isClient() && isRegistered(msg.getRemoteAddress());  
151 - onSessionClose(reconnect, msg.getRemoteAddress());  
152 - }  
153 -  
154 - private boolean isRegistered(ServerAddress address) {  
155 - for (ServerInstance server : systemContext.getDiscoveryService().getOtherServers()) {  
156 - if (server.getServerAddress().equals(address)) {  
157 - return true;  
158 - }  
159 - }  
160 - return false;  
161 - }  
162 -  
163 - private void onSessionClose(boolean reconnect, ServerAddress remoteAddress) {  
164 - log.info("[{}] session closed. Should reconnect: {}", remoteAddress, reconnect);  
165 - SessionActorInfo sessionRef = sessionActors.get(remoteAddress);  
166 - if (sessionRef != null && context().sender() != null && context().sender().equals(sessionRef.actor)) {  
167 - context().stop(sessionRef.actor);  
168 - sessionActors.remove(remoteAddress);  
169 - pendingMsgs.remove(remoteAddress);  
170 - if (reconnect) {  
171 - onCreateSessionRequest(new RpcSessionCreateRequestMsg(sessionRef.sessionId, remoteAddress, null));  
172 - }  
173 - }  
174 - }  
175 -  
176 - private void onCreateSessionRequest(RpcSessionCreateRequestMsg msg) {  
177 - if (msg.getRemoteAddress() != null) {  
178 - if (!sessionActors.containsKey(msg.getRemoteAddress())) {  
179 - ActorRef actorRef = createSessionActor(msg);  
180 - register(msg.getRemoteAddress(), msg.getMsgUid(), actorRef);  
181 - }  
182 - } else {  
183 - createSessionActor(msg);  
184 - }  
185 - }  
186 -  
187 - private void register(ServerAddress remoteAddress, UUID uuid, ActorRef sender) {  
188 - sessionActors.put(remoteAddress, new SessionActorInfo(uuid, sender));  
189 - log.info("[{}][{}] Registering session actor.", remoteAddress, uuid);  
190 - Queue<ClusterAPIProtos.ClusterMessage> data = pendingMsgs.remove(remoteAddress);  
191 - if (data != null) {  
192 - log.info("[{}][{}] Forwarding {} pending messages.", remoteAddress, uuid, data.size());  
193 - data.forEach(msg -> sender.tell(new RpcSessionTellMsg(msg), ActorRef.noSender()));  
194 - } else {  
195 - log.info("[{}][{}] No pending messages to forward.", remoteAddress, uuid);  
196 - }  
197 - }  
198 -  
199 - private ActorRef createSessionActor(RpcSessionCreateRequestMsg msg) {  
200 - log.info("[{}] Creating session actor.", msg.getMsgUid());  
201 - ActorRef actor = context().actorOf(  
202 - Props.create(new RpcSessionActor.ActorCreator(systemContext, msg.getMsgUid()))  
203 - .withDispatcher(DefaultActorService.RPC_DISPATCHER_NAME));  
204 - actor.tell(msg, context().self());  
205 - return actor;  
206 - }  
207 -  
208 - public static class ActorCreator extends ContextBasedCreator<RpcManagerActor> {  
209 - private static final long serialVersionUID = 1L;  
210 -  
211 - public ActorCreator(ActorSystemContext context) {  
212 - super(context);  
213 - }  
214 -  
215 - @Override  
216 - public RpcManagerActor create() {  
217 - return new RpcManagerActor(context);  
218 - }  
219 - }  
220 -  
221 - @Override  
222 - public SupervisorStrategy supervisorStrategy() {  
223 - return strategy;  
224 - }  
225 -  
226 - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> {  
227 - log.warn("Unknown failure", t);  
228 - return SupervisorStrategy.resume();  
229 - });  
230 -}  
1 -/**  
2 - * Copyright © 2016-2020 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.rpc;  
17 -  
18 -import io.grpc.ManagedChannel;  
19 -import io.grpc.ManagedChannelBuilder;  
20 -import io.grpc.stub.StreamObserver;  
21 -import lombok.extern.slf4j.Slf4j;  
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.common.msg.TbActorMsg;  
26 -import org.thingsboard.server.common.msg.cluster.ServerAddress;  
27 -import org.thingsboard.server.gen.cluster.ClusterAPIProtos;  
28 -import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc;  
29 -import org.thingsboard.server.service.cluster.rpc.GrpcSession;  
30 -import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener;  
31 -  
32 -import java.util.UUID;  
33 -  
34 -import static org.thingsboard.server.gen.cluster.ClusterAPIProtos.MessageType.CONNECT_RPC_MESSAGE;  
35 -  
36 -/**  
37 - * @author Andrew Shvayka  
38 - */  
39 -@Slf4j  
40 -public class RpcSessionActor extends ContextAwareActor {  
41 -  
42 -  
43 - private final UUID sessionId;  
44 - private GrpcSession session;  
45 - private GrpcSessionListener listener;  
46 -  
47 - private RpcSessionActor(ActorSystemContext systemContext, UUID sessionId) {  
48 - super(systemContext);  
49 - this.sessionId = sessionId;  
50 - }  
51 -  
52 - @Override  
53 - protected boolean process(TbActorMsg msg) {  
54 - //TODO Move everything here, to work with TbActorMsg  
55 - return false;  
56 - }  
57 -  
58 - @Override  
59 - public void onReceive(Object msg) {  
60 - if (msg instanceof ClusterAPIProtos.ClusterMessage) {  
61 - tell((ClusterAPIProtos.ClusterMessage) msg);  
62 - } else if (msg instanceof RpcSessionCreateRequestMsg) {  
63 - initSession((RpcSessionCreateRequestMsg) msg);  
64 - }  
65 - }  
66 -  
67 - private void tell(ClusterAPIProtos.ClusterMessage msg) {  
68 - if (session != null) {  
69 - session.sendMsg(msg);  
70 - } else {  
71 - log.trace("Failed to send message due to missing session!");  
72 - }  
73 - }  
74 -  
75 - @Override  
76 - public void postStop() {  
77 - if (session != null) {  
78 - log.info("Closing session -> {}", session.getRemoteServer());  
79 - try {  
80 - session.close();  
81 - } catch (RuntimeException e) {  
82 - log.trace("Failed to close session!", e);  
83 - }  
84 - }  
85 - }  
86 -  
87 - private void initSession(RpcSessionCreateRequestMsg msg) {  
88 - log.info("[{}] Initializing session", context().self());  
89 - ServerAddress remoteServer = msg.getRemoteAddress();  
90 - listener = new BasicRpcSessionListener(systemContext, context().parent(), context().self());  
91 - if (msg.getRemoteAddress() == null) {  
92 - // Server session  
93 - session = new GrpcSession(listener);  
94 - session.setOutputStream(msg.getResponseObserver());  
95 - session.initInputStream();  
96 - session.initOutputStream();  
97 - systemContext.getRpcService().onSessionCreated(msg.getMsgUid(), session.getInputStream());  
98 - } else {  
99 - // Client session  
100 - ManagedChannel channel = ManagedChannelBuilder.forAddress(remoteServer.getHost(), remoteServer.getPort()).usePlaintext().build();  
101 - session = new GrpcSession(remoteServer, listener, channel);  
102 - session.initInputStream();  
103 -  
104 - ClusterRpcServiceGrpc.ClusterRpcServiceStub stub = ClusterRpcServiceGrpc.newStub(channel);  
105 - StreamObserver<ClusterAPIProtos.ClusterMessage> outputStream = stub.handleMsgs(session.getInputStream());  
106 -  
107 - session.setOutputStream(outputStream);  
108 - session.initOutputStream();  
109 - outputStream.onNext(toConnectMsg());  
110 - }  
111 - }  
112 -  
113 - public static class ActorCreator extends ContextBasedCreator<RpcSessionActor> {  
114 - private static final long serialVersionUID = 1L;  
115 -  
116 - private final UUID sessionId;  
117 -  
118 - public ActorCreator(ActorSystemContext context, UUID sessionId) {  
119 - super(context);  
120 - this.sessionId = sessionId;  
121 - }  
122 -  
123 - @Override  
124 - public RpcSessionActor create() {  
125 - return new RpcSessionActor(context, sessionId);  
126 - }  
127 - }  
128 -  
129 - private ClusterAPIProtos.ClusterMessage toConnectMsg() {  
130 - ServerAddress instance = systemContext.getDiscoveryService().getCurrentServer().getServerAddress();  
131 - return ClusterAPIProtos.ClusterMessage.newBuilder().setMessageType(CONNECT_RPC_MESSAGE).setServerAddress(  
132 - ClusterAPIProtos.ServerAddress.newBuilder().setHost(instance.getHost())  
133 - .setPort(instance.getPort()).build()).build();  
134 - }  
135 -}  
@@ -17,18 +17,13 @@ package org.thingsboard.server.actors.ruleChain; @@ -17,18 +17,13 @@ package org.thingsboard.server.actors.ruleChain;
17 17
18 import akka.actor.ActorRef; 18 import akka.actor.ActorRef;
19 import com.datastax.driver.core.ResultSetFuture; 19 import com.datastax.driver.core.ResultSetFuture;
20 -import com.datastax.driver.core.utils.UUIDs;  
21 import com.fasterxml.jackson.core.JsonProcessingException; 20 import com.fasterxml.jackson.core.JsonProcessingException;
22 import com.fasterxml.jackson.databind.ObjectMapper; 21 import com.fasterxml.jackson.databind.ObjectMapper;
23 -import com.fasterxml.jackson.databind.node.ObjectNode;  
24 import io.netty.channel.EventLoopGroup; 22 import io.netty.channel.EventLoopGroup;
  23 +import lombok.extern.slf4j.Slf4j;
25 import org.springframework.data.redis.core.RedisTemplate; 24 import org.springframework.data.redis.core.RedisTemplate;
26 -import org.springframework.util.StringUtils;  
27 import org.thingsboard.common.util.ListeningExecutor; 25 import org.thingsboard.common.util.ListeningExecutor;
28 import org.thingsboard.rule.engine.api.MailService; 26 import org.thingsboard.rule.engine.api.MailService;
29 -import org.thingsboard.rule.engine.api.RuleChainTransactionService;  
30 -import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;  
31 -import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse;  
32 import org.thingsboard.rule.engine.api.RuleEngineRpcService; 27 import org.thingsboard.rule.engine.api.RuleEngineRpcService;
33 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; 28 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
34 import org.thingsboard.rule.engine.api.ScriptEngine; 29 import org.thingsboard.rule.engine.api.ScriptEngine;
@@ -40,19 +35,15 @@ import org.thingsboard.server.common.data.DataConstants; @@ -40,19 +35,15 @@ import org.thingsboard.server.common.data.DataConstants;
40 import org.thingsboard.server.common.data.Device; 35 import org.thingsboard.server.common.data.Device;
41 import org.thingsboard.server.common.data.alarm.Alarm; 36 import org.thingsboard.server.common.data.alarm.Alarm;
42 import org.thingsboard.server.common.data.asset.Asset; 37 import org.thingsboard.server.common.data.asset.Asset;
43 -import org.thingsboard.server.common.data.id.DeviceId;  
44 import org.thingsboard.server.common.data.id.EntityId; 38 import org.thingsboard.server.common.data.id.EntityId;
  39 +import org.thingsboard.server.common.data.id.RuleChainId;
45 import org.thingsboard.server.common.data.id.RuleNodeId; 40 import org.thingsboard.server.common.data.id.RuleNodeId;
46 import org.thingsboard.server.common.data.id.TenantId; 41 import org.thingsboard.server.common.data.id.TenantId;
47 -import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;  
48 import org.thingsboard.server.common.data.rule.RuleNode; 42 import org.thingsboard.server.common.data.rule.RuleNode;
49 import org.thingsboard.server.common.msg.TbMsg; 43 import org.thingsboard.server.common.msg.TbMsg;
50 import org.thingsboard.server.common.msg.TbMsgMetaData; 44 import org.thingsboard.server.common.msg.TbMsgMetaData;
51 -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;  
52 -import org.thingsboard.server.common.msg.cluster.ServerAddress;  
53 -import org.thingsboard.server.common.msg.cluster.ServerType;  
54 -import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;  
55 -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; 45 +import org.thingsboard.server.common.msg.queue.ServiceType;
  46 +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
56 import org.thingsboard.server.dao.alarm.AlarmService; 47 import org.thingsboard.server.dao.alarm.AlarmService;
57 import org.thingsboard.server.dao.asset.AssetService; 48 import org.thingsboard.server.dao.asset.AssetService;
58 import org.thingsboard.server.dao.attributes.AttributesService; 49 import org.thingsboard.server.dao.attributes.AttributesService;
@@ -67,11 +58,13 @@ import org.thingsboard.server.dao.rule.RuleChainService; @@ -67,11 +58,13 @@ import org.thingsboard.server.dao.rule.RuleChainService;
67 import org.thingsboard.server.dao.tenant.TenantService; 58 import org.thingsboard.server.dao.tenant.TenantService;
68 import org.thingsboard.server.dao.timeseries.TimeseriesService; 59 import org.thingsboard.server.dao.timeseries.TimeseriesService;
69 import org.thingsboard.server.dao.user.UserService; 60 import org.thingsboard.server.dao.user.UserService;
  61 +import org.thingsboard.server.gen.transport.TransportProtos;
  62 +import org.thingsboard.server.queue.TbQueueCallback;
  63 +import org.thingsboard.server.queue.TbQueueMsgMetadata;
70 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; 64 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
71 import scala.concurrent.duration.Duration; 65 import scala.concurrent.duration.Duration;
72 66
73 import java.util.Collections; 67 import java.util.Collections;
74 -import java.util.Optional;  
75 import java.util.Set; 68 import java.util.Set;
76 import java.util.concurrent.TimeUnit; 69 import java.util.concurrent.TimeUnit;
77 import java.util.function.Consumer; 70 import java.util.function.Consumer;
@@ -79,6 +72,7 @@ import java.util.function.Consumer; @@ -79,6 +72,7 @@ import java.util.function.Consumer;
79 /** 72 /**
80 * Created by ashvayka on 19.03.18. 73 * Created by ashvayka on 19.03.18.
81 */ 74 */
  75 +@Slf4j
82 class DefaultTbContext implements TbContext { 76 class DefaultTbContext implements TbContext {
83 77
84 public final static ObjectMapper mapper = new ObjectMapper(); 78 public final static ObjectMapper mapper = new ObjectMapper();
@@ -92,6 +86,11 @@ class DefaultTbContext implements TbContext { @@ -92,6 +86,11 @@ class DefaultTbContext implements TbContext {
92 } 86 }
93 87
94 @Override 88 @Override
  89 + public void tellSuccess(TbMsg msg) {
  90 + tellNext(msg, Collections.singleton(TbRelationTypes.SUCCESS), null);
  91 + }
  92 +
  93 + @Override
95 public void tellNext(TbMsg msg, String relationType) { 94 public void tellNext(TbMsg msg, String relationType) {
96 tellNext(msg, Collections.singleton(relationType), null); 95 tellNext(msg, Collections.singleton(relationType), null);
97 } 96 }
@@ -101,16 +100,11 @@ class DefaultTbContext implements TbContext { @@ -101,16 +100,11 @@ class DefaultTbContext implements TbContext {
101 tellNext(msg, relationTypes, null); 100 tellNext(msg, relationTypes, null);
102 } 101 }
103 102
104 - @Override  
105 - public void tellNext(TbMsg msg, String relationType, Throwable th) {  
106 - tellNext(msg, Collections.singleton(relationType), th);  
107 - }  
108 -  
109 private void tellNext(TbMsg msg, Set<String> relationTypes, Throwable th) { 103 private void tellNext(TbMsg msg, Set<String> relationTypes, Throwable th) {
110 if (nodeCtx.getSelf().isDebugMode()) { 104 if (nodeCtx.getSelf().isDebugMode()) {
111 relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th)); 105 relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th));
112 } 106 }
113 - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg), nodeCtx.getSelfActor()); 107 + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor());
114 } 108 }
115 109
116 @Override 110 @Override
@@ -120,9 +114,93 @@ class DefaultTbContext implements TbContext { @@ -120,9 +114,93 @@ class DefaultTbContext implements TbContext {
120 } 114 }
121 115
122 @Override 116 @Override
  117 + public void enqueue(TbMsg tbMsg, Runnable onSuccess, Consumer<Throwable> onFailure) {
  118 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
  119 + enqueue(tpi, tbMsg, onFailure, onSuccess);
  120 + }
  121 +
  122 + @Override
  123 + public void enqueue(TbMsg tbMsg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure) {
  124 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
  125 + enqueue(tpi, tbMsg, onFailure, onSuccess);
  126 + }
  127 +
  128 + private void enqueue(TopicPartitionInfo tpi, TbMsg tbMsg, Consumer<Throwable> onFailure, Runnable onSuccess) {
  129 + TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder()
  130 + .setTenantIdMSB(getTenantId().getId().getMostSignificantBits())
  131 + .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits())
  132 + .setTbMsg(TbMsg.toByteString(tbMsg)).build();
  133 + mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg, new SimpleTbQueueCallback(onSuccess, onFailure));
  134 + }
  135 +
  136 + @Override
  137 + public void enqueueForTellFailure(TbMsg tbMsg, String failureMessage) {
  138 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
  139 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), failureMessage, null, null);
  140 + }
  141 +
  142 + @Override
  143 + public void enqueueForTellNext(TbMsg tbMsg, String relationType) {
  144 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
  145 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, null, null);
  146 + }
  147 +
  148 + @Override
  149 + public void enqueueForTellNext(TbMsg tbMsg, Set<String> relationTypes) {
  150 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
  151 + enqueueForTellNext(tpi, tbMsg, relationTypes, null, null, null);
  152 + }
  153 +
  154 + @Override
  155 + public void enqueueForTellNext(TbMsg tbMsg, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) {
  156 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
  157 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
  158 + }
  159 +
  160 + @Override
  161 + public void enqueueForTellNext(TbMsg tbMsg, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
  162 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
  163 + enqueueForTellNext(tpi, tbMsg, relationTypes, null, onSuccess, onFailure);
  164 + }
  165 +
  166 + @Override
  167 + public void enqueueForTellNext(TbMsg tbMsg, String queueName, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) {
  168 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
  169 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
  170 + }
  171 +
  172 + @Override
  173 + public void enqueueForTellNext(TbMsg tbMsg, String queueName, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
  174 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
  175 + enqueueForTellNext(tpi, tbMsg, relationTypes, null, onSuccess, onFailure);
  176 + }
  177 +
  178 + private void enqueueForTellNext(TopicPartitionInfo tpi, TbMsg tbMsg, Set<String> relationTypes, String failureMessage, Runnable onSuccess, Consumer<Throwable> onFailure) {
  179 + RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId();
  180 + RuleNodeId ruleNodeId = nodeCtx.getSelf().getId();
  181 + tbMsg = TbMsg.newMsg(tbMsg, ruleChainId, ruleNodeId);
  182 + TransportProtos.ToRuleEngineMsg.Builder msg = TransportProtos.ToRuleEngineMsg.newBuilder()
  183 + .setTenantIdMSB(getTenantId().getId().getMostSignificantBits())
  184 + .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits())
  185 + .setTbMsg(TbMsg.toByteString(tbMsg))
  186 + .addAllRelationTypes(relationTypes);
  187 + if (failureMessage != null) {
  188 + msg.setFailureMessage(failureMessage);
  189 + }
  190 + mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg.build(), new SimpleTbQueueCallback(onSuccess, onFailure));
  191 + }
  192 +
  193 + @Override
  194 + public void ack(TbMsg tbMsg) {
  195 + if (nodeCtx.getSelf().isDebugMode()) {
  196 + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), tbMsg, "ACK", null);
  197 + }
  198 + tbMsg.getCallback().onSuccess();
  199 + }
  200 +
  201 + @Override
123 public boolean isLocalEntity(EntityId entityId) { 202 public boolean isLocalEntity(EntityId entityId) {
124 - Optional<ServerAddress> address = mainCtx.getRoutingService().resolveById(entityId);  
125 - return !address.isPresent(); 203 + return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), entityId).isMyPartition();
126 } 204 }
127 205
128 private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) { 206 private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) {
@@ -134,66 +212,48 @@ class DefaultTbContext implements TbContext { @@ -134,66 +212,48 @@ class DefaultTbContext implements TbContext {
134 if (nodeCtx.getSelf().isDebugMode()) { 212 if (nodeCtx.getSelf().isDebugMode()) {
135 mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); 213 mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th);
136 } 214 }
137 - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), msg), nodeCtx.getSelfActor()); 215 + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE),
  216 + msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor());
138 } 217 }
139 218
140 - @Override  
141 public void updateSelf(RuleNode self) { 219 public void updateSelf(RuleNode self) {
142 nodeCtx.setSelf(self); 220 nodeCtx.setSelf(self);
143 } 221 }
144 222
145 @Override 223 @Override
146 public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { 224 public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {
147 - return new TbMsg(UUIDs.timeBased(), type, originator, metaData.copy(), data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), mainCtx.getQueuePartitionId()); 225 + return TbMsg.newMsg(type, originator, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
148 } 226 }
149 227
150 @Override 228 @Override
151 public TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { 229 public TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) {
152 - return new TbMsg(origMsg.getId(), type, originator, metaData.copy(), origMsg.getDataType(), data, origMsg.getTransactionData(), origMsg.getRuleChainId(), origMsg.getRuleNodeId(), mainCtx.getQueuePartitionId());  
153 - }  
154 -  
155 - @Override  
156 - public void sendTbMsgToRuleEngine(TbMsg msg) {  
157 - mainCtx.getActorService().onMsg(new SendToClusterMsg(msg.getOriginator(), new ServiceToRuleEngineMsg(getTenantId(), msg))); 230 + return TbMsg.transformMsg(origMsg, type, originator, metaData, data);
158 } 231 }
159 232
160 public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) { 233 public TbMsg customerCreatedMsg(Customer customer, RuleNodeId ruleNodeId) {
161 - try {  
162 - ObjectNode entityNode = mapper.valueToTree(customer);  
163 - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, customer.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L);  
164 - } catch (JsonProcessingException | IllegalArgumentException e) {  
165 - throw new RuntimeException("Failed to process customer created msg: " + e);  
166 - } 234 + return entityCreatedMsg(customer, customer.getId(), ruleNodeId);
167 } 235 }
168 236
169 public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) { 237 public TbMsg deviceCreatedMsg(Device device, RuleNodeId ruleNodeId) {
170 - try {  
171 - ObjectNode entityNode = mapper.valueToTree(device);  
172 - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, device.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L);  
173 - } catch (JsonProcessingException | IllegalArgumentException e) {  
174 - throw new RuntimeException("Failed to process device created msg: " + e);  
175 - } 238 + return entityCreatedMsg(device, device.getId(), ruleNodeId);
176 } 239 }
177 240
178 public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) { 241 public TbMsg assetCreatedMsg(Asset asset, RuleNodeId ruleNodeId) {
179 - try {  
180 - ObjectNode entityNode = mapper.valueToTree(asset);  
181 - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, asset.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L);  
182 - } catch (JsonProcessingException | IllegalArgumentException e) {  
183 - throw new RuntimeException("Failed to process asset created msg: " + e);  
184 - } 242 + return entityCreatedMsg(asset, asset.getId(), ruleNodeId);
185 } 243 }
186 244
187 public TbMsg alarmCreatedMsg(Alarm alarm, RuleNodeId ruleNodeId) { 245 public TbMsg alarmCreatedMsg(Alarm alarm, RuleNodeId ruleNodeId) {
  246 + return entityCreatedMsg(alarm, alarm.getId(), ruleNodeId);
  247 + }
  248 +
  249 + public <E, I extends EntityId> TbMsg entityCreatedMsg(E entity, I id, RuleNodeId ruleNodeId) {
188 try { 250 try {
189 - ObjectNode entityNode = mapper.valueToTree(alarm);  
190 - return new TbMsg(UUIDs.timeBased(), DataConstants.ENTITY_CREATED, alarm.getId(), getActionMetaData(ruleNodeId), mapper.writeValueAsString(entityNode), null, null, 0L); 251 + return TbMsg.newMsg(DataConstants.ENTITY_CREATED, id, getActionMetaData(ruleNodeId), mapper.writeValueAsString(mapper.valueToTree(entity)));
191 } catch (JsonProcessingException | IllegalArgumentException e) { 252 } catch (JsonProcessingException | IllegalArgumentException e) {
192 - throw new RuntimeException("Failed to process alarm created msg: " + e); 253 + throw new RuntimeException("Failed to process " + id.getEntityType().name().toLowerCase() + " created msg: " + e);
193 } 254 }
194 } 255 }
195 256
196 -  
197 @Override 257 @Override
198 public RuleNodeId getSelfId() { 258 public RuleNodeId getSelfId() {
199 return nodeCtx.getSelf().getId(); 259 return nodeCtx.getSelf().getId();
@@ -251,8 +311,8 @@ class DefaultTbContext implements TbContext { @@ -251,8 +311,8 @@ class DefaultTbContext implements TbContext {
251 } 311 }
252 312
253 @Override 313 @Override
254 - public String getNodeId() {  
255 - return mainCtx.getNodeIdProvider().getNodeId(); 314 + public String getServiceId() {
  315 + return mainCtx.getServiceInfoProvider().getServiceId();
256 } 316 }
257 317
258 @Override 318 @Override
@@ -321,11 +381,6 @@ class DefaultTbContext implements TbContext { @@ -321,11 +381,6 @@ class DefaultTbContext implements TbContext {
321 } 381 }
322 382
323 @Override 383 @Override
324 - public RuleChainTransactionService getRuleChainTransactionService() {  
325 - return mainCtx.getRuleChainTransactionService();  
326 - }  
327 -  
328 - @Override  
329 public EventLoopGroup getSharedEventLoop() { 384 public EventLoopGroup getSharedEventLoop() {
330 return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); 385 return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup();
331 } 386 }
@@ -341,35 +396,7 @@ class DefaultTbContext implements TbContext { @@ -341,35 +396,7 @@ class DefaultTbContext implements TbContext {
341 396
342 @Override 397 @Override
343 public RuleEngineRpcService getRpcService() { 398 public RuleEngineRpcService getRpcService() {
344 - return new RuleEngineRpcService() {  
345 - @Override  
346 - public void sendRpcReply(DeviceId deviceId, int requestId, String body) {  
347 - mainCtx.getDeviceRpcService().sendReplyToRpcCallFromDevice(nodeCtx.getTenantId(), deviceId, requestId, body);  
348 - }  
349 -  
350 - @Override  
351 - public void sendRpcRequest(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) {  
352 - ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), nodeCtx.getTenantId(), src.getDeviceId(),  
353 - src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody()));  
354 - mainCtx.getDeviceRpcService().forwardServerSideRPCRequestToDeviceActor(request, response -> {  
355 - if (src.isRestApiCall()) {  
356 - ServerAddress requestOriginAddress;  
357 - if (!StringUtils.isEmpty(src.getOriginHost())) {  
358 - requestOriginAddress = new ServerAddress(src.getOriginHost(), src.getOriginPort(), ServerType.CORE);  
359 - } else {  
360 - requestOriginAddress = mainCtx.getRoutingService().getCurrentServer();  
361 - }  
362 - mainCtx.getDeviceRpcService().processResponseToServerSideRPCRequestFromRuleEngine(requestOriginAddress, response);  
363 - }  
364 - consumer.accept(RuleEngineDeviceRpcResponse.builder()  
365 - .deviceId(src.getDeviceId())  
366 - .requestId(src.getRequestId())  
367 - .error(response.getError())  
368 - .response(response.getResponse())  
369 - .build());  
370 - });  
371 - }  
372 - }; 399 + return mainCtx.getTbRuleEngineDeviceRpcService();
373 } 400 }
374 401
375 @Override 402 @Override
@@ -387,10 +414,6 @@ class DefaultTbContext implements TbContext { @@ -387,10 +414,6 @@ class DefaultTbContext implements TbContext {
387 return mainCtx.getRedisTemplate(); 414 return mainCtx.getRedisTemplate();
388 } 415 }
389 416
390 - @Override  
391 - public String getServerAddress() {  
392 - return mainCtx.getServerAddress();  
393 - }  
394 417
395 private TbMsgMetaData getActionMetaData(RuleNodeId ruleNodeId) { 418 private TbMsgMetaData getActionMetaData(RuleNodeId ruleNodeId) {
396 TbMsgMetaData metaData = new TbMsgMetaData(); 419 TbMsgMetaData metaData = new TbMsgMetaData();
@@ -398,4 +421,29 @@ class DefaultTbContext implements TbContext { @@ -398,4 +421,29 @@ class DefaultTbContext implements TbContext {
398 return metaData; 421 return metaData;
399 } 422 }
400 423
  424 + private class SimpleTbQueueCallback implements TbQueueCallback {
  425 + private final Runnable onSuccess;
  426 + private final Consumer<Throwable> onFailure;
  427 +
  428 + public SimpleTbQueueCallback(Runnable onSuccess, Consumer<Throwable> onFailure) {
  429 + this.onSuccess = onSuccess;
  430 + this.onFailure = onFailure;
  431 + }
  432 +
  433 + @Override
  434 + public void onSuccess(TbQueueMsgMetadata metadata) {
  435 + if (onSuccess != null) {
  436 + onSuccess.run();
  437 + }
  438 + }
  439 +
  440 + @Override
  441 + public void onFailure(Throwable t) {
  442 + if (onFailure != null) {
  443 + onFailure.accept(t);
  444 + } else {
  445 + log.debug("[{}] Failed to put item into queue", nodeCtx.getTenantId(), t);
  446 + }
  447 + }
  448 + }
401 } 449 }
@@ -15,25 +15,25 @@ @@ -15,25 +15,25 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 -import akka.actor.ActorInitializationException;  
19 import akka.actor.OneForOneStrategy; 18 import akka.actor.OneForOneStrategy;
20 import akka.actor.SupervisorStrategy; 19 import akka.actor.SupervisorStrategy;
21 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
22 -import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;  
23 import org.thingsboard.server.actors.service.ComponentActor; 21 import org.thingsboard.server.actors.service.ComponentActor;
24 import org.thingsboard.server.actors.service.ContextBasedCreator; 22 import org.thingsboard.server.actors.service.ContextBasedCreator;
25 import org.thingsboard.server.common.data.id.RuleChainId; 23 import org.thingsboard.server.common.data.id.RuleChainId;
26 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
  25 +import org.thingsboard.server.common.data.rule.RuleChain;
27 import org.thingsboard.server.common.msg.TbActorMsg; 26 import org.thingsboard.server.common.msg.TbActorMsg;
28 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 27 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
29 -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; 28 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
  29 +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
30 import scala.concurrent.duration.Duration; 30 import scala.concurrent.duration.Duration;
31 31
32 public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> { 32 public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> {
33 33
34 - private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) {  
35 - super(systemContext, tenantId, ruleChainId);  
36 - setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext, 34 + private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChain ruleChain) {
  35 + super(systemContext, tenantId, ruleChain.getId());
  36 + setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChain, systemContext,
37 context().parent(), context().self())); 37 context().parent(), context().self()));
38 } 38 }
39 39
@@ -43,20 +43,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe @@ -43,20 +43,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
43 case COMPONENT_LIFE_CYCLE_MSG: 43 case COMPONENT_LIFE_CYCLE_MSG:
44 onComponentLifecycleMsg((ComponentLifecycleMsg) msg); 44 onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
45 break; 45 break;
46 - case SERVICE_TO_RULE_ENGINE_MSG:  
47 - processor.onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);  
48 - break;  
49 - case DEVICE_ACTOR_TO_RULE_ENGINE_MSG:  
50 - processor.onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); 46 + case QUEUE_TO_RULE_ENGINE_MSG:
  47 + processor.onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg);
51 break; 48 break;
52 case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG: 49 case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG:
53 - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:  
54 processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg); 50 processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg);
55 break; 51 break;
56 case RULE_CHAIN_TO_RULE_CHAIN_MSG: 52 case RULE_CHAIN_TO_RULE_CHAIN_MSG:
57 processor.onRuleChainToRuleChainMsg((RuleChainToRuleChainMsg) msg); 53 processor.onRuleChainToRuleChainMsg((RuleChainToRuleChainMsg) msg);
58 break; 54 break;
59 - case CLUSTER_EVENT_MSG: 55 + case PARTITION_CHANGE_MSG:
  56 + processor.onPartitionChangeMsg((PartitionChangeMsg) msg);
60 break; 57 break;
61 case STATS_PERSIST_TICK_MSG: 58 case STATS_PERSIST_TICK_MSG:
62 onStatsPersistTick(id); 59 onStatsPersistTick(id);
@@ -71,17 +68,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe @@ -71,17 +68,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
71 private static final long serialVersionUID = 1L; 68 private static final long serialVersionUID = 1L;
72 69
73 private final TenantId tenantId; 70 private final TenantId tenantId;
74 - private final RuleChainId ruleChainId; 71 + private final RuleChain ruleChain;
75 72
76 - public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId pluginId) { 73 + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChain ruleChain) {
77 super(context); 74 super(context);
78 this.tenantId = tenantId; 75 this.tenantId = tenantId;
79 - this.ruleChainId = pluginId; 76 + this.ruleChain = ruleChain;
80 } 77 }
81 78
82 @Override 79 @Override
83 public RuleChainActor create() { 80 public RuleChainActor create() {
84 - return new RuleChainActor(context, tenantId, ruleChainId); 81 + return new RuleChainActor(context, tenantId, ruleChain);
85 } 82 }
86 } 83 }
87 84
@@ -18,14 +18,9 @@ package org.thingsboard.server.actors.ruleChain; @@ -18,14 +18,9 @@ package org.thingsboard.server.actors.ruleChain;
18 import akka.actor.ActorContext; 18 import akka.actor.ActorContext;
19 import akka.actor.ActorRef; 19 import akka.actor.ActorRef;
20 import akka.actor.Props; 20 import akka.actor.Props;
21 -import akka.event.LoggingAdapter;  
22 -import com.datastax.driver.core.utils.UUIDs;  
23 -  
24 -import java.util.Optional;  
25 -  
26 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
  22 +import org.thingsboard.rule.engine.api.TbRelationTypes;
27 import org.thingsboard.server.actors.ActorSystemContext; 23 import org.thingsboard.server.actors.ActorSystemContext;
28 -import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;  
29 import org.thingsboard.server.actors.service.DefaultActorService; 24 import org.thingsboard.server.actors.service.DefaultActorService;
30 import org.thingsboard.server.actors.shared.ComponentMsgProcessor; 25 import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
31 import org.thingsboard.server.common.data.EntityType; 26 import org.thingsboard.server.common.data.EntityType;
@@ -39,11 +34,19 @@ import org.thingsboard.server.common.data.relation.EntityRelation; @@ -39,11 +34,19 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
39 import org.thingsboard.server.common.data.rule.RuleChain; 34 import org.thingsboard.server.common.data.rule.RuleChain;
40 import org.thingsboard.server.common.data.rule.RuleNode; 35 import org.thingsboard.server.common.data.rule.RuleNode;
41 import org.thingsboard.server.common.msg.TbMsg; 36 import org.thingsboard.server.common.msg.TbMsg;
42 -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;  
43 -import org.thingsboard.server.common.msg.cluster.ServerAddress;  
44 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 37 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
45 -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; 38 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
  39 +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
  40 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  41 +import org.thingsboard.server.common.msg.queue.RuleNodeException;
  42 +import org.thingsboard.server.common.msg.queue.ServiceType;
  43 +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
46 import org.thingsboard.server.dao.rule.RuleChainService; 44 import org.thingsboard.server.dao.rule.RuleChainService;
  45 +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
  46 +import org.thingsboard.server.queue.TbQueueCallback;
  47 +import org.thingsboard.server.queue.common.MultipleTbQueueTbMsgCallbackWrapper;
  48 +import org.thingsboard.server.queue.common.TbQueueTbMsgCallbackWrapper;
  49 +import org.thingsboard.server.service.queue.TbClusterService;
47 50
48 import java.util.ArrayList; 51 import java.util.ArrayList;
49 import java.util.Collections; 52 import java.util.Collections;
@@ -59,27 +62,28 @@ import java.util.stream.Collectors; @@ -59,27 +62,28 @@ import java.util.stream.Collectors;
59 @Slf4j 62 @Slf4j
60 public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { 63 public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> {
61 64
62 - private static final long DEFAULT_CLUSTER_PARTITION = 0L;  
63 private final ActorRef parent; 65 private final ActorRef parent;
64 private final ActorRef self; 66 private final ActorRef self;
65 private final Map<RuleNodeId, RuleNodeCtx> nodeActors; 67 private final Map<RuleNodeId, RuleNodeCtx> nodeActors;
66 private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes; 68 private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes;
67 private final RuleChainService service; 69 private final RuleChainService service;
  70 + private final TbClusterService clusterService;
  71 + private String ruleChainName;
68 72
69 private RuleNodeId firstId; 73 private RuleNodeId firstId;
70 private RuleNodeCtx firstNode; 74 private RuleNodeCtx firstNode;
71 private boolean started; 75 private boolean started;
72 - private String ruleChainName;  
73 76
74 - RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext 77 + RuleChainActorMessageProcessor(TenantId tenantId, RuleChain ruleChain, ActorSystemContext systemContext
75 , ActorRef parent, ActorRef self) { 78 , ActorRef parent, ActorRef self) {
76 - super(systemContext, tenantId, ruleChainId); 79 + super(systemContext, tenantId, ruleChain.getId());
  80 + this.ruleChainName = ruleChain.getName();
77 this.parent = parent; 81 this.parent = parent;
78 this.self = self; 82 this.self = self;
79 this.nodeActors = new HashMap<>(); 83 this.nodeActors = new HashMap<>();
80 this.nodeRoutes = new HashMap<>(); 84 this.nodeRoutes = new HashMap<>();
81 this.service = systemContext.getRuleChainService(); 85 this.service = systemContext.getRuleChainService();
82 - this.ruleChainName = ruleChainId.toString(); 86 + this.clusterService = systemContext.getClusterService();
83 } 87 }
84 88
85 @Override 89 @Override
@@ -92,7 +96,6 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -92,7 +96,6 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
92 if (!started) { 96 if (!started) {
93 RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); 97 RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
94 if (ruleChain != null) { 98 if (ruleChain != null) {
95 - ruleChainName = ruleChain.getName();  
96 List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); 99 List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
97 log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); 100 log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
98 // Creating and starting the actors; 101 // Creating and starting the actors;
@@ -152,8 +155,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -152,8 +155,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
152 } 155 }
153 156
154 @Override 157 @Override
155 - public void onClusterEventMsg(ClusterEventMsg msg) {  
156 - 158 + public void onPartitionChangeMsg(PartitionChangeMsg msg) {
  159 + nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(actorRef -> actorRef.tell(msg, self));
157 } 160 }
158 161
159 private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) { 162 private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) {
@@ -192,100 +195,123 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -192,100 +195,123 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
192 state = ComponentLifecycleState.ACTIVE; 195 state = ComponentLifecycleState.ACTIVE;
193 } 196 }
194 197
195 - void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) {  
196 - log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, envelope.getTbMsg().getId(), envelope.getTbMsg());  
197 - checkActive();  
198 - if (firstNode != null) {  
199 - log.trace("[{}][{}] Pushing message to first rule node", entityId, firstId);  
200 - pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getTbMsg()), "");  
201 - }  
202 - }  
203 -  
204 - void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) {  
205 - checkActive();  
206 - if (firstNode != null) {  
207 - pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getTbMsg()), ""); 198 + void onQueueToRuleEngineMsg(QueueToRuleEngineMsg envelope) {
  199 + TbMsg msg = envelope.getTbMsg();
  200 + log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, msg.getId(), msg);
  201 + if (envelope.getRelationTypes() == null || envelope.getRelationTypes().isEmpty()) {
  202 + try {
  203 + checkActive();
  204 + RuleNodeId targetId = msg.getRuleNodeId();
  205 + RuleNodeCtx targetCtx;
  206 + if (targetId == null) {
  207 + targetCtx = firstNode;
  208 + msg = msg.copyWithRuleChainId(entityId);
  209 + } else {
  210 + targetCtx = nodeActors.get(targetId);
  211 + }
  212 + if (targetCtx != null) {
  213 + log.trace("[{}][{}] Pushing message to target rule node", entityId, targetId);
  214 + pushMsgToNode(targetCtx, msg, "");
  215 + } else {
  216 + log.trace("[{}][{}] Rule node does not exist. Probably old message", entityId, targetId);
  217 + msg.getCallback().onSuccess();
  218 + }
  219 + } catch (Exception e) {
  220 + envelope.getTbMsg().getCallback().onFailure(new RuleEngineException(e.getMessage()));
  221 + }
  222 + } else {
  223 + onTellNext(envelope.getTbMsg(), envelope.getTbMsg().getRuleNodeId(), envelope.getRelationTypes(), envelope.getFailureMessage());
208 } 224 }
209 } 225 }
210 226
211 void onRuleChainToRuleChainMsg(RuleChainToRuleChainMsg envelope) { 227 void onRuleChainToRuleChainMsg(RuleChainToRuleChainMsg envelope) {
212 checkActive(); 228 checkActive();
213 - if (envelope.isEnqueue()) {  
214 - if (firstNode != null) {  
215 - pushMsgToNode(firstNode, enrichWithRuleChainId(envelope.getMsg()), envelope.getFromRelationType());  
216 - } 229 + if (firstNode != null) {
  230 + pushMsgToNode(firstNode, envelope.getMsg(), envelope.getFromRelationType());
217 } else { 231 } else {
218 - if (firstNode != null) {  
219 - pushMsgToNode(firstNode, envelope.getMsg(), envelope.getFromRelationType());  
220 - } else {  
221 -// TODO: Ack this message in Kafka  
222 -// TbMsg msg = envelope.getMsg();  
223 -// EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId();  
224 -// queue.ack(tenantId, envelope.getMsg(), ackId.getId(), msg.getClusterPartition());  
225 - } 232 + envelope.getMsg().getCallback().onSuccess();
226 } 233 }
227 } 234 }
228 235
229 void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { 236 void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) {
230 - checkActive();  
231 - TbMsg msg = envelope.getMsg();  
232 - EntityId originatorEntityId = msg.getOriginator();  
233 - Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(originatorEntityId); 237 + onTellNext(envelope.getMsg(), envelope.getOriginator(), envelope.getRelationTypes(), envelope.getFailureMessage());
  238 + }
234 239
235 - if (address.isPresent()) {  
236 - onRemoteTellNext(address.get(), envelope);  
237 - } else {  
238 - onLocalTellNext(envelope); 240 + private void onTellNext(TbMsg msg, RuleNodeId originatorNodeId, Set<String> relationTypes, String failureMessage) {
  241 + try {
  242 + checkActive();
  243 + EntityId entityId = msg.getOriginator();
  244 + TopicPartitionInfo tpi = systemContext.resolve(ServiceType.TB_RULE_ENGINE, tenantId, entityId);
  245 + List<RuleNodeRelation> relations = nodeRoutes.get(originatorNodeId).stream()
  246 + .filter(r -> contains(relationTypes, r.getType()))
  247 + .collect(Collectors.toList());
  248 + int relationsCount = relations.size();
  249 + if (relationsCount == 0) {
  250 + log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId());
  251 + if (relationTypes.contains(TbRelationTypes.FAILURE)) {
  252 + RuleNodeCtx ruleNodeCtx = nodeActors.get(originatorNodeId);
  253 + if (ruleNodeCtx != null) {
  254 + msg.getCallback().onFailure(new RuleNodeException(failureMessage, ruleChainName, ruleNodeCtx.getSelf()));
  255 + } else {
  256 + log.debug("[{}] Failure during message processing by Rule Node [{}]. Enable and see debug events for more info", entityId, originatorNodeId.getId());
  257 + msg.getCallback().onFailure(new RuleEngineException("Failure during message processing by Rule Node [" + originatorNodeId.getId().toString() + "]"));
  258 + }
  259 + } else {
  260 + msg.getCallback().onSuccess();
  261 + }
  262 + } else if (relationsCount == 1) {
  263 + for (RuleNodeRelation relation : relations) {
  264 + log.trace("[{}][{}][{}] Pushing message to single target: [{}]", tenantId, entityId, msg.getId(), relation.getOut());
  265 + pushToTarget(tpi, msg, relation.getOut(), relation.getType());
  266 + }
  267 + } else {
  268 + MultipleTbQueueTbMsgCallbackWrapper callbackWrapper = new MultipleTbQueueTbMsgCallbackWrapper(relationsCount, msg.getCallback());
  269 + log.trace("[{}][{}][{}] Pushing message to multiple targets: [{}]", tenantId, entityId, msg.getId(), relations);
  270 + for (RuleNodeRelation relation : relations) {
  271 + EntityId target = relation.getOut();
  272 + putToQueue(tpi, msg, callbackWrapper, target);
  273 + }
  274 + }
  275 + } catch (Exception e) {
  276 + msg.getCallback().onFailure(new RuleEngineException("onTellNext - " + e.getMessage()));
239 } 277 }
240 } 278 }
241 279
242 - private void onRemoteTellNext(ServerAddress serverAddress, RuleNodeToRuleChainTellNextMsg envelope) {  
243 - TbMsg msg = envelope.getMsg();  
244 - log.debug("Forwarding [{}] msg to remote server [{}] due to changed originator id: [{}]", msg.getId(), serverAddress, msg.getOriginator());  
245 - envelope = new RemoteToRuleChainTellNextMsg(envelope, tenantId, entityId);  
246 - systemContext.getRpcService().tell(systemContext.getEncodingService().convertToProtoDataMessage(serverAddress, envelope)); 280 + private void putToQueue(TopicPartitionInfo tpi, TbMsg msg, TbQueueCallback callbackWrapper, EntityId target) {
  281 + switch (target.getEntityType()) {
  282 + case RULE_NODE:
  283 + putToQueue(tpi, msg.copyWithRuleNodeId(entityId, new RuleNodeId(target.getId())), callbackWrapper);
  284 + break;
  285 + case RULE_CHAIN:
  286 + putToQueue(tpi, msg.copyWithRuleChainId(new RuleChainId(target.getId())), callbackWrapper);
  287 + break;
  288 + }
247 } 289 }
248 290
249 - private void onLocalTellNext(RuleNodeToRuleChainTellNextMsg envelope) {  
250 - TbMsg msg = envelope.getMsg();  
251 - RuleNodeId originatorNodeId = envelope.getOriginator();  
252 - List<RuleNodeRelation> relations = nodeRoutes.get(originatorNodeId).stream()  
253 - .filter(r -> contains(envelope.getRelationTypes(), r.getType()))  
254 - .collect(Collectors.toList());  
255 - int relationsCount = relations.size();  
256 - EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId();  
257 - if (relationsCount == 0) {  
258 - log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId());  
259 - if (ackId != null) {  
260 -// TODO: Ack this message in Kafka  
261 -// queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition());  
262 - }  
263 - } else if (relationsCount == 1) {  
264 - for (RuleNodeRelation relation : relations) {  
265 - log.trace("[{}][{}][{}] Pushing message to single target: [{}]", tenantId, entityId, msg.getId(), relation.getOut());  
266 - pushToTarget(msg, relation.getOut(), relation.getType()); 291 + private void pushToTarget(TopicPartitionInfo tpi, TbMsg msg, EntityId target, String fromRelationType) {
  292 + if (tpi.isMyPartition()) {
  293 + switch (target.getEntityType()) {
  294 + case RULE_NODE:
  295 + pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg, fromRelationType);
  296 + break;
  297 + case RULE_CHAIN:
  298 + parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, fromRelationType), self);
  299 + break;
267 } 300 }
268 } else { 301 } else {
269 - for (RuleNodeRelation relation : relations) {  
270 - EntityId target = relation.getOut();  
271 - log.trace("[{}][{}][{}] Pushing message to multiple targets: [{}]", tenantId, entityId, msg.getId(), relation.getOut());  
272 - switch (target.getEntityType()) {  
273 - case RULE_NODE:  
274 - enqueueAndForwardMsgCopyToNode(msg, target, relation.getType());  
275 - break;  
276 - case RULE_CHAIN:  
277 - enqueueAndForwardMsgCopyToChain(msg, target, relation.getType());  
278 - break;  
279 - }  
280 - }  
281 - //TODO: Ideally this should happen in async way when all targets confirm that the copied messages are successfully written to corresponding target queues.  
282 - if (ackId != null) {  
283 -// TODO: Ack this message in Kafka  
284 -// queue.ack(tenantId, msg, ackId.getId(), msg.getClusterPartition());  
285 - } 302 + putToQueue(tpi, msg, new TbQueueTbMsgCallbackWrapper(msg.getCallback()), target);
286 } 303 }
287 } 304 }
288 305
  306 + private void putToQueue(TopicPartitionInfo tpi, TbMsg newMsg, TbQueueCallback callbackWrapper) {
  307 + ToRuleEngineMsg toQueueMsg = ToRuleEngineMsg.newBuilder()
  308 + .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
  309 + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
  310 + .setTbMsg(TbMsg.toByteString(newMsg))
  311 + .build();
  312 + clusterService.pushMsgToRuleEngine(tpi, newMsg.getId(), toQueueMsg, callbackWrapper);
  313 + }
  314 +
289 private boolean contains(Set<String> relationTypes, String type) { 315 private boolean contains(Set<String> relationTypes, String type) {
290 if (relationTypes == null) { 316 if (relationTypes == null) {
291 return true; 317 return true;
@@ -298,38 +324,13 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -298,38 +324,13 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
298 return false; 324 return false;
299 } 325 }
300 326
301 - private void enqueueAndForwardMsgCopyToChain(TbMsg msg, EntityId target, String fromRelationType) {  
302 - RuleChainId targetRCId = new RuleChainId(target.getId());  
303 - TbMsg copyMsg = msg.copy(UUIDs.timeBased(), targetRCId, null, DEFAULT_CLUSTER_PARTITION);  
304 - parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, copyMsg, fromRelationType, true), self);  
305 - }  
306 -  
307 - private void enqueueAndForwardMsgCopyToNode(TbMsg msg, EntityId target, String fromRelationType) {  
308 - RuleNodeId targetId = new RuleNodeId(target.getId());  
309 - RuleNodeCtx targetNodeCtx = nodeActors.get(targetId);  
310 - TbMsg copy = msg.copy(UUIDs.timeBased(), entityId, targetId, DEFAULT_CLUSTER_PARTITION);  
311 - pushMsgToNode(targetNodeCtx, copy, fromRelationType);  
312 - }  
313 -  
314 - private void pushToTarget(TbMsg msg, EntityId target, String fromRelationType) {  
315 - switch (target.getEntityType()) {  
316 - case RULE_NODE:  
317 - pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg, fromRelationType);  
318 - break;  
319 - case RULE_CHAIN:  
320 - parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, fromRelationType, false), self);  
321 - break;  
322 - }  
323 - }  
324 -  
325 private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) { 327 private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) {
326 if (nodeCtx != null) { 328 if (nodeCtx != null) {
327 nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg, fromRelationType), self); 329 nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg, fromRelationType), self);
  330 + } else {
  331 + log.error("[{}][{}] RuleNodeCtx is empty", entityId, ruleChainName);
  332 + msg.getCallback().onFailure(new RuleEngineException("Rule Node CTX is empty"));
328 } 333 }
329 } 334 }
330 335
331 - private TbMsg enrichWithRuleChainId(TbMsg tbMsg) {  
332 - // We don't put firstNodeId because it may change over time;  
333 - return new TbMsg(tbMsg.getId(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData().copy(), tbMsg.getData(), entityId, null, systemContext.getQueuePartitionId());  
334 - }  
335 } 336 }
@@ -15,43 +15,89 @@ @@ -15,43 +15,89 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
  18 +import akka.actor.ActorContext;
18 import akka.actor.ActorRef; 19 import akka.actor.ActorRef;
  20 +import akka.actor.Props;
  21 +import com.google.common.collect.BiMap;
  22 +import com.google.common.collect.HashBiMap;
  23 +import lombok.Getter;
19 import org.thingsboard.server.actors.ActorSystemContext; 24 import org.thingsboard.server.actors.ActorSystemContext;
20 import org.thingsboard.server.actors.service.ContextAwareActor; 25 import org.thingsboard.server.actors.service.ContextAwareActor;
21 -import org.thingsboard.server.actors.shared.rulechain.RuleChainManager; 26 +import org.thingsboard.server.actors.service.DefaultActorService;
  27 +import org.thingsboard.server.common.data.EntityType;
22 import org.thingsboard.server.common.data.id.EntityId; 28 import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.RuleChainId; 29 import org.thingsboard.server.common.data.id.RuleChainId;
  30 +import org.thingsboard.server.common.data.id.TenantId;
  31 +import org.thingsboard.server.common.data.page.PageDataIterable;
  32 +import org.thingsboard.server.common.data.rule.RuleChain;
24 import org.thingsboard.server.dao.rule.RuleChainService; 33 import org.thingsboard.server.dao.rule.RuleChainService;
25 34
  35 +import java.util.function.Function;
  36 +
26 /** 37 /**
27 * Created by ashvayka on 15.03.18. 38 * Created by ashvayka on 15.03.18.
28 */ 39 */
29 public abstract class RuleChainManagerActor extends ContextAwareActor { 40 public abstract class RuleChainManagerActor extends ContextAwareActor {
30 41
31 - protected final RuleChainManager ruleChainManager;  
32 - protected final RuleChainService ruleChainService; 42 + protected final TenantId tenantId;
  43 + private final RuleChainService ruleChainService;
  44 + private final BiMap<RuleChainId, ActorRef> actors;
  45 + @Getter
  46 + protected RuleChain rootChain;
  47 + @Getter
  48 + protected ActorRef rootChainActor;
33 49
34 - public RuleChainManagerActor(ActorSystemContext systemContext, RuleChainManager ruleChainManager) { 50 + public RuleChainManagerActor(ActorSystemContext systemContext, TenantId tenantId) {
35 super(systemContext); 51 super(systemContext);
36 - this.ruleChainManager = ruleChainManager; 52 + this.tenantId = tenantId;
  53 + this.actors = HashBiMap.create();
37 this.ruleChainService = systemContext.getRuleChainService(); 54 this.ruleChainService = systemContext.getRuleChainService();
38 } 55 }
39 56
40 protected void initRuleChains() { 57 protected void initRuleChains() {
41 - ruleChainManager.init(this.context()); 58 + for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChains(tenantId, link), ContextAwareActor.ENTITY_PACK_LIMIT)) {
  59 + RuleChainId ruleChainId = ruleChain.getId();
  60 + log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId());
  61 + //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.
  62 + ActorRef actorRef = getOrCreateActor(this.context(), ruleChainId, id -> ruleChain);
  63 + visit(ruleChain, actorRef);
  64 + log.debug("[{}|{}] Rule Chain actor created.", ruleChainId.getEntityType(), ruleChainId.getId());
  65 + }
  66 + }
  67 +
  68 + protected void visit(RuleChain entity, ActorRef actorRef) {
  69 + if (entity != null && entity.isRoot()) {
  70 + rootChain = entity;
  71 + rootChainActor = actorRef;
  72 + }
  73 + }
  74 +
  75 + public ActorRef getOrCreateActor(akka.actor.ActorContext context, RuleChainId ruleChainId) {
  76 + return getOrCreateActor(context, ruleChainId, eId -> ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, eId));
  77 + }
  78 +
  79 + public ActorRef getOrCreateActor(akka.actor.ActorContext context, RuleChainId ruleChainId, Function<RuleChainId, RuleChain> provider) {
  80 + return actors.computeIfAbsent(ruleChainId, eId -> {
  81 + RuleChain ruleChain = provider.apply(eId);
  82 + return context.actorOf(Props.create(new RuleChainActor.ActorCreator(systemContext, tenantId, ruleChain))
  83 + .withDispatcher(DefaultActorService.TENANT_RULE_DISPATCHER_NAME), eId.toString());
  84 + });
42 } 85 }
43 86
44 protected ActorRef getEntityActorRef(EntityId entityId) { 87 protected ActorRef getEntityActorRef(EntityId entityId) {
45 ActorRef target = null; 88 ActorRef target = null;
46 - switch (entityId.getEntityType()) {  
47 - case RULE_CHAIN:  
48 - target = ruleChainManager.getOrCreateActor(this.context(), (RuleChainId) entityId);  
49 - break; 89 + if (entityId.getEntityType() == EntityType.RULE_CHAIN) {
  90 + target = getOrCreateActor(this.context(), (RuleChainId) entityId);
50 } 91 }
51 return target; 92 return target;
52 } 93 }
53 94
54 protected void broadcast(Object msg) { 95 protected void broadcast(Object msg) {
55 - ruleChainManager.broadcast(msg); 96 + actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
56 } 97 }
  98 +
  99 + public ActorRef get(RuleChainId id) {
  100 + return actors.get(id);
  101 + }
  102 +
57 } 103 }
@@ -32,7 +32,6 @@ public final class RuleChainToRuleChainMsg implements TbActorMsg, RuleChainAware @@ -32,7 +32,6 @@ public final class RuleChainToRuleChainMsg implements TbActorMsg, RuleChainAware
32 private final RuleChainId source; 32 private final RuleChainId source;
33 private final TbMsg msg; 33 private final TbMsg msg;
34 private final String fromRelationType; 34 private final String fromRelationType;
35 - private final boolean enqueue;  
36 35
37 @Override 36 @Override
38 public RuleChainId getRuleChainId() { 37 public RuleChainId getRuleChainId() {
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId; @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
23 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.msg.TbActorMsg; 24 import org.thingsboard.server.common.msg.TbActorMsg;
25 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 25 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
  26 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
26 27
27 public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> { 28 public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> {
28 29
@@ -53,6 +54,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa @@ -53,6 +54,9 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
53 case STATS_PERSIST_TICK_MSG: 54 case STATS_PERSIST_TICK_MSG:
54 onStatsPersistTick(id); 55 onStatsPersistTick(id);
55 break; 56 break;
  57 + case PARTITION_CHANGE_MSG:
  58 + onClusterEventMsg((PartitionChangeMsg) msg);
  59 + break;
56 default: 60 default:
57 return false; 61 return false;
58 } 62 }
@@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId; @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
27 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
28 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; 28 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
29 import org.thingsboard.server.common.data.rule.RuleNode; 29 import org.thingsboard.server.common.data.rule.RuleNode;
30 -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 30 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
31 import org.thingsboard.server.dao.rule.RuleChainService; 31 import org.thingsboard.server.dao.rule.RuleChainService;
32 32
33 /** 33 /**
@@ -40,7 +40,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -40,7 +40,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
40 private final RuleChainService service; 40 private final RuleChainService service;
41 private RuleNode ruleNode; 41 private RuleNode ruleNode;
42 private TbNode tbNode; 42 private TbNode tbNode;
43 - private TbContext defaultCtx; 43 + private DefaultTbContext defaultCtx;
44 44
45 RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext 45 RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext
46 , ActorRef parent, ActorRef self) { 46 , ActorRef parent, ActorRef self) {
@@ -84,9 +84,9 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -84,9 +84,9 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
84 } 84 }
85 85
86 @Override 86 @Override
87 - public void onClusterEventMsg(ClusterEventMsg msg) { 87 + public void onPartitionChangeMsg(PartitionChangeMsg msg) {
88 if (tbNode != null) { 88 if (tbNode != null) {
89 - tbNode.onClusterEventMsg(defaultCtx, msg); 89 + tbNode.onPartitionChangeMsg(defaultCtx, msg);
90 } 90 }
91 } 91 }
92 92
@@ -34,6 +34,7 @@ class RuleNodeToRuleChainTellNextMsg implements TbActorMsg, Serializable { @@ -34,6 +34,7 @@ class RuleNodeToRuleChainTellNextMsg implements TbActorMsg, Serializable {
34 private final RuleNodeId originator; 34 private final RuleNodeId originator;
35 private final Set<String> relationTypes; 35 private final Set<String> relationTypes;
36 private final TbMsg msg; 36 private final TbMsg msg;
  37 + private final String failureMessage;
37 38
38 @Override 39 @Override
39 public MsgType getMsgType() { 40 public MsgType getMsgType() {
@@ -15,24 +15,7 @@ @@ -15,24 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
18 -import org.thingsboard.server.common.data.id.DeviceId;  
19 -import org.thingsboard.server.common.data.id.EntityId;  
20 -import org.thingsboard.server.common.data.id.TenantId;  
21 -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;  
22 -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;  
23 -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;  
24 -import org.thingsboard.server.common.transport.SessionMsgProcessor;  
25 -import org.thingsboard.server.service.cluster.discovery.DiscoveryServiceListener;  
26 -import org.thingsboard.server.service.cluster.rpc.RpcMsgListener; 18 +public interface ActorService {
27 19
28 -public interface ActorService extends SessionMsgProcessor, RpcMsgListener, DiscoveryServiceListener {  
29 -  
30 - void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state);  
31 -  
32 - void onMsg(SendToClusterMsg msg);  
33 -  
34 - void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId);  
35 -  
36 - void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType);  
37 20
38 } 21 }
@@ -22,7 +22,7 @@ import org.thingsboard.server.actors.stats.StatsPersistMsg; @@ -22,7 +22,7 @@ import org.thingsboard.server.actors.stats.StatsPersistMsg;
22 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 24 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
25 -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 25 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
26 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 26 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
27 27
28 /** 28 /**
@@ -115,9 +115,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -115,9 +115,9 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
115 } 115 }
116 } 116 }
117 117
118 - protected void onClusterEventMsg(ClusterEventMsg msg) { 118 + protected void onClusterEventMsg(PartitionChangeMsg msg) {
119 try { 119 try {
120 - processor.onClusterEventMsg(msg); 120 + processor.onPartitionChangeMsg(msg);
121 } catch (Exception e) { 121 } catch (Exception e) {
122 logAndPersist("onClusterEventMsg", e); 122 logAndPersist("onClusterEventMsg", e);
123 } 123 }
@@ -16,14 +16,14 @@ @@ -16,14 +16,14 @@
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
18 import akka.actor.Terminated; 18 import akka.actor.Terminated;
19 -import akka.actor.UntypedActor; 19 +import akka.actor.UntypedAbstractActor;
20 import org.slf4j.Logger; 20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory; 21 import org.slf4j.LoggerFactory;
22 import org.thingsboard.server.actors.ActorSystemContext; 22 import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.common.msg.TbActorMsg; 23 import org.thingsboard.server.common.msg.TbActorMsg;
24 24
25 25
26 -public abstract class ContextAwareActor extends UntypedActor { 26 +public abstract class ContextAwareActor extends UntypedAbstractActor {
27 27
28 protected final Logger log = LoggerFactory.getLogger(getClass()); 28 protected final Logger log = LoggerFactory.getLogger(getClass());
29 29
@@ -19,7 +19,6 @@ import akka.actor.ActorRef; @@ -19,7 +19,6 @@ import akka.actor.ActorRef;
19 import akka.actor.ActorSystem; 19 import akka.actor.ActorSystem;
20 import akka.actor.Props; 20 import akka.actor.Props;
21 import akka.actor.Terminated; 21 import akka.actor.Terminated;
22 -import com.google.protobuf.ByteString;  
23 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
24 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.beans.factory.annotation.Value; 24 import org.springframework.beans.factory.annotation.Value;
@@ -27,44 +26,20 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; @@ -27,44 +26,20 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
27 import org.springframework.context.event.EventListener; 26 import org.springframework.context.event.EventListener;
28 import org.springframework.scheduling.annotation.Scheduled; 27 import org.springframework.scheduling.annotation.Scheduled;
29 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
30 -import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;  
31 -import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;  
32 import org.thingsboard.server.actors.ActorSystemContext; 29 import org.thingsboard.server.actors.ActorSystemContext;
33 import org.thingsboard.server.actors.app.AppActor; 30 import org.thingsboard.server.actors.app.AppActor;
34 import org.thingsboard.server.actors.app.AppInitMsg; 31 import org.thingsboard.server.actors.app.AppInitMsg;
35 -import org.thingsboard.server.actors.rpc.RpcBroadcastMsg;  
36 -import org.thingsboard.server.actors.rpc.RpcManagerActor;  
37 -import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg;  
38 import org.thingsboard.server.actors.stats.StatsActor; 32 import org.thingsboard.server.actors.stats.StatsActor;
39 -import org.thingsboard.server.common.data.Device;  
40 -import org.thingsboard.server.common.data.id.DeviceId;  
41 -import org.thingsboard.server.common.data.id.EntityId;  
42 -import org.thingsboard.server.common.data.id.TenantId;  
43 -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;  
44 -import org.thingsboard.server.common.msg.TbActorMsg;  
45 -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;  
46 -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;  
47 -import org.thingsboard.server.common.msg.cluster.ServerAddress;  
48 -import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;  
49 -import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;  
50 -import org.thingsboard.server.gen.cluster.ClusterAPIProtos;  
51 -import org.thingsboard.server.service.cluster.discovery.DiscoveryService;  
52 -import org.thingsboard.server.service.cluster.discovery.ServerInstance;  
53 -import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;  
54 -import org.thingsboard.server.service.state.DeviceStateService;  
55 -import org.thingsboard.server.service.transport.RuleEngineStats; 33 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
  34 +import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
56 import scala.concurrent.Await; 35 import scala.concurrent.Await;
57 import scala.concurrent.Future; 36 import scala.concurrent.Future;
58 import scala.concurrent.duration.Duration; 37 import scala.concurrent.duration.Duration;
59 38
60 import javax.annotation.PostConstruct; 39 import javax.annotation.PostConstruct;
61 import javax.annotation.PreDestroy; 40 import javax.annotation.PreDestroy;
62 -import java.util.concurrent.Executors;  
63 -import java.util.concurrent.ScheduledExecutorService;  
64 import java.util.concurrent.atomic.AtomicInteger; 41 import java.util.concurrent.atomic.AtomicInteger;
65 42
66 -import static org.thingsboard.server.gen.cluster.ClusterAPIProtos.MessageType.CLUSTER_ACTOR_MESSAGE;  
67 -  
68 @Service 43 @Service
69 @Slf4j 44 @Slf4j
70 public class DefaultActorService implements ActorService { 45 public class DefaultActorService implements ActorService {
@@ -75,26 +50,14 @@ public class DefaultActorService implements ActorService { @@ -75,26 +50,14 @@ public class DefaultActorService implements ActorService {
75 public static final String CORE_DISPATCHER_NAME = "core-dispatcher"; 50 public static final String CORE_DISPATCHER_NAME = "core-dispatcher";
76 public static final String SYSTEM_RULE_DISPATCHER_NAME = "system-rule-dispatcher"; 51 public static final String SYSTEM_RULE_DISPATCHER_NAME = "system-rule-dispatcher";
77 public static final String TENANT_RULE_DISPATCHER_NAME = "rule-dispatcher"; 52 public static final String TENANT_RULE_DISPATCHER_NAME = "rule-dispatcher";
78 - public static final String RPC_DISPATCHER_NAME = "rpc-dispatcher";  
79 53
80 @Autowired 54 @Autowired
81 private ActorSystemContext actorContext; 55 private ActorSystemContext actorContext;
82 56
83 - @Autowired  
84 - private ClusterRpcService rpcService;  
85 -  
86 - @Autowired  
87 - private DiscoveryService discoveryService;  
88 -  
89 - @Autowired  
90 - private DeviceStateService deviceStateService;  
91 -  
92 private ActorSystem system; 57 private ActorSystem system;
93 58
94 private ActorRef appActor; 59 private ActorRef appActor;
95 60
96 - private ActorRef rpcManagerActor;  
97 -  
98 @PostConstruct 61 @PostConstruct
99 public void initActorSystem() { 62 public void initActorSystem() {
100 log.info("Initializing Actor system."); 63 log.info("Initializing Actor system.");
@@ -105,13 +68,9 @@ public class DefaultActorService implements ActorService { @@ -105,13 +68,9 @@ public class DefaultActorService implements ActorService {
105 appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor"); 68 appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor");
106 actorContext.setAppActor(appActor); 69 actorContext.setAppActor(appActor);
107 70
108 - rpcManagerActor = system.actorOf(Props.create(new RpcManagerActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME),  
109 - "rpcManagerActor");  
110 -  
111 ActorRef statsActor = system.actorOf(Props.create(new StatsActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), "statsActor"); 71 ActorRef statsActor = system.actorOf(Props.create(new StatsActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), "statsActor");
112 actorContext.setStatsActor(statsActor); 72 actorContext.setStatsActor(statsActor);
113 73
114 - rpcService.init(this);  
115 log.info("Actor system initialized."); 74 log.info("Actor system initialized.");
116 } 75 }
117 76
@@ -121,6 +80,12 @@ public class DefaultActorService implements ActorService { @@ -121,6 +80,12 @@ public class DefaultActorService implements ActorService {
121 appActor.tell(new AppInitMsg(), ActorRef.noSender()); 80 appActor.tell(new AppInitMsg(), ActorRef.noSender());
122 } 81 }
123 82
  83 + @EventListener(PartitionChangeEvent.class)
  84 + public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) {
  85 + log.info("Received partition change event.");
  86 + this.appActor.tell(new PartitionChangeMsg(partitionChangeEvent.getServiceQueueKey(), partitionChangeEvent.getPartitions()), ActorRef.noSender());
  87 + }
  88 +
124 @PreDestroy 89 @PreDestroy
125 public void stopActorSystem() { 90 public void stopActorSystem() {
126 Future<Terminated> status = system.terminate(); 91 Future<Terminated> status = system.terminate();
@@ -132,157 +97,4 @@ public class DefaultActorService implements ActorService { @@ -132,157 +97,4 @@ public class DefaultActorService implements ActorService {
132 } 97 }
133 } 98 }
134 99
135 - @Override  
136 - public void onMsg(SendToClusterMsg msg) {  
137 - appActor.tell(msg, ActorRef.noSender());  
138 - }  
139 -  
140 - @Override  
141 - public void onServerAdded(ServerInstance server) {  
142 - log.trace("Processing onServerAdded msg: {}", server);  
143 - broadcast(new ClusterEventMsg(server.getServerAddress(), true));  
144 - }  
145 -  
146 - @Override  
147 - public void onServerUpdated(ServerInstance server) {  
148 - //Do nothing  
149 - }  
150 -  
151 - @Override  
152 - public void onServerRemoved(ServerInstance server) {  
153 - log.trace("Processing onServerRemoved msg: {}", server);  
154 - broadcast(new ClusterEventMsg(server.getServerAddress(), false));  
155 - }  
156 -  
157 - @Override  
158 - public void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state) {  
159 - log.trace("[{}] Processing {} state change event: {}", tenantId, entityId.getEntityType(), state);  
160 - broadcast(new ComponentLifecycleMsg(tenantId, entityId, state));  
161 - }  
162 -  
163 - @Override  
164 - public void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId) {  
165 - DeviceCredentialsUpdateNotificationMsg msg = new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceId);  
166 - appActor.tell(new SendToClusterMsg(deviceId, msg), ActorRef.noSender());  
167 - }  
168 -  
169 - @Override  
170 - public void onDeviceNameOrTypeUpdate(TenantId tenantId, DeviceId deviceId, String deviceName, String deviceType) {  
171 - log.trace("[{}] Processing onDeviceNameOrTypeUpdate event, deviceName: {}, deviceType: {}", deviceId, deviceName, deviceType);  
172 - DeviceNameOrTypeUpdateMsg msg = new DeviceNameOrTypeUpdateMsg(tenantId, deviceId, deviceName, deviceType);  
173 - appActor.tell(new SendToClusterMsg(deviceId, msg), ActorRef.noSender());  
174 - }  
175 -  
176 - public void broadcast(ToAllNodesMsg msg) {  
177 - actorContext.getEncodingService().encode(msg);  
178 - rpcService.broadcast(new RpcBroadcastMsg(ClusterAPIProtos.ClusterMessage  
179 - .newBuilder()  
180 - .setPayload(ByteString  
181 - .copyFrom(actorContext.getEncodingService().encode(msg)))  
182 - .setMessageType(CLUSTER_ACTOR_MESSAGE)  
183 - .build()));  
184 - appActor.tell(msg, ActorRef.noSender());  
185 - }  
186 -  
187 - private void broadcast(ClusterEventMsg msg) {  
188 - this.appActor.tell(msg, ActorRef.noSender());  
189 - this.rpcManagerActor.tell(msg, ActorRef.noSender());  
190 - }  
191 -  
192 - @Value("${cluster.stats.enabled:false}")  
193 - private boolean statsEnabled;  
194 -  
195 - private final AtomicInteger sentClusterMsgs = new AtomicInteger(0);  
196 - private final AtomicInteger receivedClusterMsgs = new AtomicInteger(0);  
197 -  
198 -  
199 - @Scheduled(fixedDelayString = "${cluster.stats.print_interval_ms}")  
200 - public void printStats() {  
201 - if (statsEnabled) {  
202 - int sent = sentClusterMsgs.getAndSet(0);  
203 - int received = receivedClusterMsgs.getAndSet(0);  
204 - if (sent > 0 || received > 0) {  
205 - log.info("Cluster msgs sent [{}] received [{}]", sent, received);  
206 - }  
207 - }  
208 - }  
209 -  
210 - @Override  
211 - public void onReceivedMsg(ServerAddress source, ClusterAPIProtos.ClusterMessage msg) {  
212 - if (statsEnabled) {  
213 - receivedClusterMsgs.incrementAndGet();  
214 - }  
215 - ServerAddress serverAddress = new ServerAddress(source.getHost(), source.getPort(), source.getServerType());  
216 - if (log.isDebugEnabled()) {  
217 - log.info("Received msg [{}] from [{}]", msg.getMessageType().name(), serverAddress);  
218 - log.info("MSG: {}", msg);  
219 - }  
220 - switch (msg.getMessageType()) {  
221 - case CLUSTER_ACTOR_MESSAGE:  
222 - java.util.Optional<TbActorMsg> decodedMsg = actorContext.getEncodingService()  
223 - .decode(msg.getPayload().toByteArray());  
224 - if (decodedMsg.isPresent()) {  
225 - appActor.tell(decodedMsg.get(), ActorRef.noSender());  
226 - } else {  
227 - log.error("Error during decoding cluster proto message");  
228 - }  
229 - break;  
230 - case TO_ALL_NODES_MSG:  
231 - //TODO  
232 - break;  
233 - case CLUSTER_TELEMETRY_SUBSCRIPTION_CREATE_MESSAGE:  
234 - actorContext.getTsSubService().onNewRemoteSubscription(serverAddress, msg.getPayload().toByteArray());  
235 - break;  
236 - case CLUSTER_TELEMETRY_SUBSCRIPTION_UPDATE_MESSAGE:  
237 - actorContext.getTsSubService().onRemoteSubscriptionUpdate(serverAddress, msg.getPayload().toByteArray());  
238 - break;  
239 - case CLUSTER_TELEMETRY_SUBSCRIPTION_CLOSE_MESSAGE:  
240 - actorContext.getTsSubService().onRemoteSubscriptionClose(serverAddress, msg.getPayload().toByteArray());  
241 - break;  
242 - case CLUSTER_TELEMETRY_SESSION_CLOSE_MESSAGE:  
243 - actorContext.getTsSubService().onRemoteSessionClose(serverAddress, msg.getPayload().toByteArray());  
244 - break;  
245 - case CLUSTER_TELEMETRY_ATTR_UPDATE_MESSAGE:  
246 - actorContext.getTsSubService().onRemoteAttributesUpdate(serverAddress, msg.getPayload().toByteArray());  
247 - break;  
248 - case CLUSTER_TELEMETRY_TS_UPDATE_MESSAGE:  
249 - actorContext.getTsSubService().onRemoteTsUpdate(serverAddress, msg.getPayload().toByteArray());  
250 - break;  
251 - case CLUSTER_RPC_FROM_DEVICE_RESPONSE_MESSAGE:  
252 - actorContext.getDeviceRpcService().processResponseToServerSideRPCRequestFromRemoteServer(serverAddress, msg.getPayload().toByteArray());  
253 - break;  
254 - case CLUSTER_DEVICE_STATE_SERVICE_MESSAGE:  
255 - actorContext.getDeviceStateService().onRemoteMsg(serverAddress, msg.getPayload().toByteArray());  
256 - break;  
257 - case CLUSTER_TRANSACTION_SERVICE_MESSAGE:  
258 - actorContext.getRuleChainTransactionService().onRemoteTransactionMsg(serverAddress, msg.getPayload().toByteArray());  
259 - break;  
260 - }  
261 - }  
262 -  
263 - @Override  
264 - public void onSendMsg(ClusterAPIProtos.ClusterMessage msg) {  
265 - if (statsEnabled) {  
266 - sentClusterMsgs.incrementAndGet();  
267 - }  
268 - rpcManagerActor.tell(msg, ActorRef.noSender());  
269 - }  
270 -  
271 - @Override  
272 - public void onRpcSessionCreateRequestMsg(RpcSessionCreateRequestMsg msg) {  
273 - if (statsEnabled) {  
274 - sentClusterMsgs.incrementAndGet();  
275 - }  
276 - rpcManagerActor.tell(msg, ActorRef.noSender());  
277 - }  
278 -  
279 - @Override  
280 - public void onBroadcastMsg(RpcBroadcastMsg msg) {  
281 - rpcManagerActor.tell(msg, ActorRef.noSender());  
282 - }  
283 -  
284 - @Override  
285 - public void onDeviceAdded(Device device) {  
286 - deviceStateService.onDeviceAdded(device);  
287 - }  
288 } 100 }
@@ -16,20 +16,13 @@ @@ -16,20 +16,13 @@
16 package org.thingsboard.server.actors.shared; 16 package org.thingsboard.server.actors.shared;
17 17
18 import akka.actor.ActorContext; 18 import akka.actor.ActorContext;
19 -import akka.event.LoggingAdapter;  
20 -import com.google.common.util.concurrent.FutureCallback;  
21 -import com.google.common.util.concurrent.Futures;  
22 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
23 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
24 import org.thingsboard.server.actors.stats.StatsPersistTick; 21 import org.thingsboard.server.actors.stats.StatsPersistTick;
25 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
26 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; 24 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
28 -import org.thingsboard.server.common.msg.TbMsg;  
29 -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;  
30 -  
31 -import javax.annotation.Nullable;  
32 -import java.util.function.Consumer; 25 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
33 26
34 @Slf4j 27 @Slf4j
35 public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor { 28 public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor {
@@ -50,7 +43,7 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract @@ -50,7 +43,7 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract
50 43
51 public abstract void stop(ActorContext context) throws Exception; 44 public abstract void stop(ActorContext context) throws Exception;
52 45
53 - public abstract void onClusterEventMsg(ClusterEventMsg msg) throws Exception; 46 + public abstract void onPartitionChangeMsg(PartitionChangeMsg msg) throws Exception;
54 47
55 public void onCreated(ActorContext context) throws Exception { 48 public void onCreated(ActorContext context) throws Exception {
56 start(context); 49 start(context);
1 -/**  
2 - * Copyright © 2016-2020 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.shared;  
17 -  
18 -import akka.actor.ActorContext;  
19 -import akka.actor.ActorRef;  
20 -import akka.actor.Props;  
21 -import akka.actor.UntypedActor;  
22 -import akka.japi.Creator;  
23 -import com.google.common.collect.BiMap;  
24 -import com.google.common.collect.HashBiMap;  
25 -import lombok.extern.slf4j.Slf4j;  
26 -import org.thingsboard.server.actors.ActorSystemContext;  
27 -import org.thingsboard.server.actors.service.ContextAwareActor;  
28 -import org.thingsboard.server.common.data.SearchTextBased;  
29 -import org.thingsboard.server.common.data.id.EntityId;  
30 -import org.thingsboard.server.common.data.id.TenantId;  
31 -import org.thingsboard.server.common.data.id.UUIDBased;  
32 -import org.thingsboard.server.common.data.page.PageDataIterable;  
33 -  
34 -import java.util.HashMap;  
35 -import java.util.Map;  
36 -  
37 -/**  
38 - * Created by ashvayka on 15.03.18.  
39 - */  
40 -@Slf4j  
41 -public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> {  
42 -  
43 - protected final ActorSystemContext systemContext;  
44 - protected final BiMap<T, ActorRef> actors;  
45 -  
46 - public EntityActorsManager(ActorSystemContext systemContext) {  
47 - this.systemContext = systemContext;  
48 - this.actors = HashBiMap.create();  
49 - }  
50 -  
51 - protected abstract TenantId getTenantId();  
52 -  
53 - protected abstract String getDispatcherName();  
54 -  
55 - protected abstract Creator<A> creator(T entityId);  
56 -  
57 - protected abstract PageDataIterable.FetchFunction<M> getFetchEntitiesFunction();  
58 -  
59 - public void init(ActorContext context) {  
60 - for (M entity : new PageDataIterable<>(getFetchEntitiesFunction(), ContextAwareActor.ENTITY_PACK_LIMIT)) {  
61 - T entityId = (T) entity.getId();  
62 - log.debug("[{}|{}] Creating entity actor", entityId.getEntityType(), entityId.getId());  
63 - //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.  
64 - ActorRef actorRef = getOrCreateActor(context, entityId);  
65 - visit(entity, actorRef);  
66 - log.debug("[{}|{}] Entity actor created.", entityId.getEntityType(), entityId.getId());  
67 - }  
68 - }  
69 -  
70 - public void visit(M entity, ActorRef actorRef) {  
71 - }  
72 -  
73 - public ActorRef getOrCreateActor(ActorContext context, T entityId) {  
74 - return actors.computeIfAbsent(entityId, eId ->  
75 - context.actorOf(Props.create(creator(eId))  
76 - .withDispatcher(getDispatcherName()), eId.toString()));  
77 - }  
78 -  
79 - public void broadcast(Object msg) {  
80 - actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));  
81 - }  
82 -  
83 - public void remove(T id) {  
84 - actors.remove(id);  
85 - }  
86 -  
87 -}  
@@ -24,7 +24,6 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; @@ -24,7 +24,6 @@ import org.thingsboard.server.actors.service.ContextBasedCreator;
24 import org.thingsboard.server.common.data.DataConstants; 24 import org.thingsboard.server.common.data.DataConstants;
25 import org.thingsboard.server.common.data.Event; 25 import org.thingsboard.server.common.data.Event;
26 import org.thingsboard.server.common.msg.TbActorMsg; 26 import org.thingsboard.server.common.msg.TbActorMsg;
27 -import org.thingsboard.server.common.msg.cluster.ServerAddress;  
28 27
29 @Slf4j 28 @Slf4j
30 public class StatsActor extends ContextAwareActor { 29 public class StatsActor extends ContextAwareActor {
@@ -58,12 +57,12 @@ public class StatsActor extends ContextAwareActor { @@ -58,12 +57,12 @@ public class StatsActor extends ContextAwareActor {
58 event.setEntityId(msg.getEntityId()); 57 event.setEntityId(msg.getEntityId());
59 event.setTenantId(msg.getTenantId()); 58 event.setTenantId(msg.getTenantId());
60 event.setType(DataConstants.STATS); 59 event.setType(DataConstants.STATS);
61 - event.setBody(toBodyJson(systemContext.getDiscoveryService().getCurrentServer().getServerAddress(), msg.getMessagesProcessed(), msg.getErrorsOccurred())); 60 + event.setBody(toBodyJson(systemContext.getServiceInfoProvider().getServiceId(), msg.getMessagesProcessed(), msg.getErrorsOccurred()));
62 systemContext.getEventService().save(event); 61 systemContext.getEventService().save(event);
63 } 62 }
64 63
65 - private JsonNode toBodyJson(ServerAddress server, long messagesProcessed, long errorsOccurred) {  
66 - return mapper.createObjectNode().put("server", server.toString()).put("messagesProcessed", messagesProcessed).put("errorsOccurred", errorsOccurred); 64 + private JsonNode toBodyJson(String serviceId, long messagesProcessed, long errorsOccurred) {
  65 + return mapper.createObjectNode().put("server", serviceId).put("messagesProcessed", messagesProcessed).put("errorsOccurred", errorsOccurred);
67 } 66 }
68 67
69 public static class ActorCreator extends ContextBasedCreator<StatsActor> { 68 public static class ActorCreator extends ContextBasedCreator<StatsActor> {
@@ -22,41 +22,43 @@ import akka.actor.OneForOneStrategy; @@ -22,41 +22,43 @@ import akka.actor.OneForOneStrategy;
22 import akka.actor.Props; 22 import akka.actor.Props;
23 import akka.actor.SupervisorStrategy; 23 import akka.actor.SupervisorStrategy;
24 import akka.actor.Terminated; 24 import akka.actor.Terminated;
25 -import akka.japi.Function;  
26 import com.google.common.collect.BiMap; 25 import com.google.common.collect.BiMap;
27 import com.google.common.collect.HashBiMap; 26 import com.google.common.collect.HashBiMap;
28 -import lombok.extern.slf4j.Slf4j;  
29 import org.thingsboard.server.actors.ActorSystemContext; 27 import org.thingsboard.server.actors.ActorSystemContext;
30 import org.thingsboard.server.actors.device.DeviceActorCreator; 28 import org.thingsboard.server.actors.device.DeviceActorCreator;
31 -import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;  
32 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; 29 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
33 import org.thingsboard.server.actors.service.ContextBasedCreator; 30 import org.thingsboard.server.actors.service.ContextBasedCreator;
34 import org.thingsboard.server.actors.service.DefaultActorService; 31 import org.thingsboard.server.actors.service.DefaultActorService;
35 -import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager;  
36 import org.thingsboard.server.common.data.EntityType; 32 import org.thingsboard.server.common.data.EntityType;
  33 +import org.thingsboard.server.common.data.Tenant;
37 import org.thingsboard.server.common.data.id.DeviceId; 34 import org.thingsboard.server.common.data.id.DeviceId;
38 import org.thingsboard.server.common.data.id.RuleChainId; 35 import org.thingsboard.server.common.data.id.RuleChainId;
39 import org.thingsboard.server.common.data.id.TenantId; 36 import org.thingsboard.server.common.data.id.TenantId;
40 -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;  
41 import org.thingsboard.server.common.data.rule.RuleChain; 37 import org.thingsboard.server.common.data.rule.RuleChain;
  38 +import org.thingsboard.server.common.msg.MsgType;
42 import org.thingsboard.server.common.msg.TbActorMsg; 39 import org.thingsboard.server.common.msg.TbActorMsg;
  40 +import org.thingsboard.server.common.msg.TbMsg;
43 import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; 41 import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
44 import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; 42 import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg;
45 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 43 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
46 -import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; 44 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
  45 +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
  46 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  47 +import org.thingsboard.server.common.msg.queue.ServiceType;
47 import scala.concurrent.duration.Duration; 48 import scala.concurrent.duration.Duration;
48 49
49 -import java.util.HashMap;  
50 -import java.util.Map; 50 +import java.util.List;
  51 +import java.util.Optional;
  52 +import java.util.stream.Collectors;
51 53
52 public class TenantActor extends RuleChainManagerActor { 54 public class TenantActor extends RuleChainManagerActor {
53 55
54 - private final TenantId tenantId;  
55 private final BiMap<DeviceId, ActorRef> deviceActors; 56 private final BiMap<DeviceId, ActorRef> deviceActors;
  57 + private boolean isRuleEngineForCurrentTenant;
  58 + private boolean isCore;
56 59
57 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { 60 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) {
58 - super(systemContext, new TenantRuleChainManager(systemContext, tenantId));  
59 - this.tenantId = tenantId; 61 + super(systemContext, tenantId);
60 this.deviceActors = HashBiMap.create(); 62 this.deviceActors = HashBiMap.create();
61 } 63 }
62 64
@@ -65,12 +67,37 @@ public class TenantActor extends RuleChainManagerActor { @@ -65,12 +67,37 @@ public class TenantActor extends RuleChainManagerActor {
65 return strategy; 67 return strategy;
66 } 68 }
67 69
  70 + boolean cantFindTenant = false;
  71 +
68 @Override 72 @Override
69 public void preStart() { 73 public void preStart() {
70 log.info("[{}] Starting tenant actor.", tenantId); 74 log.info("[{}] Starting tenant actor.", tenantId);
71 try { 75 try {
72 - initRuleChains();  
73 - log.info("[{}] Tenant actor started.", tenantId); 76 + Tenant tenant = systemContext.getTenantService().findTenantById(tenantId);
  77 + if (tenant == null) {
  78 + cantFindTenant = true;
  79 + log.info("[{}] Started tenant actor for missing tenant.", tenantId);
  80 + } else {
  81 + // This Service may be started for specific tenant only.
  82 + Optional<TenantId> isolatedTenantId = systemContext.getServiceInfoProvider().getIsolatedTenant();
  83 +
  84 + isRuleEngineForCurrentTenant = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE);
  85 + isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE);
  86 +
  87 + if (isRuleEngineForCurrentTenant) {
  88 + try {
  89 + if (isolatedTenantId.map(id -> id.equals(tenantId)).orElseGet(() -> !tenant.isIsolatedTbRuleEngine())) {
  90 + log.info("[{}] Going to init rule chains", tenantId);
  91 + initRuleChains();
  92 + } else {
  93 + isRuleEngineForCurrentTenant = false;
  94 + }
  95 + } catch (Exception e) {
  96 + cantFindTenant = true;
  97 + }
  98 + }
  99 + log.info("[{}] Tenant actor started.", tenantId);
  100 + }
74 } catch (Exception e) { 101 } catch (Exception e) {
75 log.warn("[{}] Unknown failure", tenantId, e); 102 log.warn("[{}] Unknown failure", tenantId, e);
76 } 103 }
@@ -83,18 +110,36 @@ public class TenantActor extends RuleChainManagerActor { @@ -83,18 +110,36 @@ public class TenantActor extends RuleChainManagerActor {
83 110
84 @Override 111 @Override
85 protected boolean process(TbActorMsg msg) { 112 protected boolean process(TbActorMsg msg) {
  113 + if (cantFindTenant) {
  114 + log.info("[{}] Processing missing Tenant msg: {}", tenantId, msg);
  115 + if (msg.getMsgType().equals(MsgType.QUEUE_TO_RULE_ENGINE_MSG)) {
  116 + QueueToRuleEngineMsg queueMsg = (QueueToRuleEngineMsg) msg;
  117 + queueMsg.getTbMsg().getCallback().onSuccess();
  118 + }
  119 + return true;
  120 + }
86 switch (msg.getMsgType()) { 121 switch (msg.getMsgType()) {
87 - case CLUSTER_EVENT_MSG:  
88 - broadcast(msg); 122 + case PARTITION_CHANGE_MSG:
  123 + PartitionChangeMsg partitionChangeMsg = (PartitionChangeMsg) msg;
  124 + ServiceType serviceType = partitionChangeMsg.getServiceQueueKey().getServiceType();
  125 + if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) {
  126 + //To Rule Chain Actors
  127 + broadcast(msg);
  128 + } else if (ServiceType.TB_CORE.equals(serviceType)) {
  129 + //To Device Actors
  130 + List<DeviceId> repartitionedDevices =
  131 + deviceActors.keySet().stream().filter(deviceId -> !isMyPartition(deviceId)).collect(Collectors.toList());
  132 + for (DeviceId deviceId : repartitionedDevices) {
  133 + ActorRef deviceActor = deviceActors.remove(deviceId);
  134 + context().stop(deviceActor);
  135 + }
  136 + }
89 break; 137 break;
90 case COMPONENT_LIFE_CYCLE_MSG: 138 case COMPONENT_LIFE_CYCLE_MSG:
91 onComponentLifecycleMsg((ComponentLifecycleMsg) msg); 139 onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
92 break; 140 break;
93 - case SERVICE_TO_RULE_ENGINE_MSG:  
94 - onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);  
95 - break;  
96 - case DEVICE_ACTOR_TO_RULE_ENGINE_MSG:  
97 - onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); 141 + case QUEUE_TO_RULE_ENGINE_MSG:
  142 + onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg);
98 break; 143 break;
99 case TRANSPORT_TO_DEVICE_ACTOR_MSG: 144 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
100 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 145 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
@@ -105,7 +150,6 @@ public class TenantActor extends RuleChainManagerActor { @@ -105,7 +150,6 @@ public class TenantActor extends RuleChainManagerActor {
105 onToDeviceActorMsg((DeviceAwareMsg) msg); 150 onToDeviceActorMsg((DeviceAwareMsg) msg);
106 break; 151 break;
107 case RULE_CHAIN_TO_RULE_CHAIN_MSG: 152 case RULE_CHAIN_TO_RULE_CHAIN_MSG:
108 - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:  
109 onRuleChainMsg((RuleChainAwareMsg) msg); 153 onRuleChainMsg((RuleChainAwareMsg) msg);
110 break; 154 break;
111 default: 155 default:
@@ -114,41 +158,59 @@ public class TenantActor extends RuleChainManagerActor { @@ -114,41 +158,59 @@ public class TenantActor extends RuleChainManagerActor {
114 return true; 158 return true;
115 } 159 }
116 160
117 - private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) {  
118 - if (ruleChainManager.getRootChainActor() != null) {  
119 - ruleChainManager.getRootChainActor().tell(msg, self());  
120 - } else {  
121 - log.info("[{}] No Root Chain: {}", tenantId, msg);  
122 - } 161 + private boolean isMyPartition(DeviceId deviceId) {
  162 + return systemContext.resolve(ServiceType.TB_CORE, tenantId, deviceId).isMyPartition();
123 } 163 }
124 164
125 - private void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg msg) {  
126 - if (ruleChainManager.getRootChainActor() != null) {  
127 - ruleChainManager.getRootChainActor().tell(msg, self()); 165 + private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) {
  166 + if (!isRuleEngineForCurrentTenant) {
  167 + log.warn("RECEIVED INVALID MESSAGE: {}", msg);
  168 + return;
  169 + }
  170 + TbMsg tbMsg = msg.getTbMsg();
  171 + if (tbMsg.getRuleChainId() == null) {
  172 + if (getRootChainActor() != null) {
  173 + getRootChainActor().tell(msg, self());
  174 + } else {
  175 + tbMsg.getCallback().onFailure(new RuleEngineException("No Root Rule Chain available!"));
  176 + log.info("[{}] No Root Chain: {}", tenantId, msg);
  177 + }
128 } else { 178 } else {
129 - log.info("[{}] No Root Chain: {}", tenantId, msg); 179 + ActorRef ruleChainActor = get(tbMsg.getRuleChainId());
  180 + if (ruleChainActor != null) {
  181 + ruleChainActor.tell(msg, self());
  182 + } else {
  183 + log.trace("Received message for non-existing rule chain: [{}]", tbMsg.getRuleChainId());
  184 + //TODO: 3.1 Log it to dead letters queue;
  185 + tbMsg.getCallback().onSuccess();
  186 + }
130 } 187 }
131 } 188 }
132 189
133 private void onRuleChainMsg(RuleChainAwareMsg msg) { 190 private void onRuleChainMsg(RuleChainAwareMsg msg) {
134 - ruleChainManager.getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self()); 191 + getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self());
135 } 192 }
136 193
137 private void onToDeviceActorMsg(DeviceAwareMsg msg) { 194 private void onToDeviceActorMsg(DeviceAwareMsg msg) {
  195 + if (!isCore) {
  196 + log.warn("RECEIVED INVALID MESSAGE: {}", msg);
  197 + }
138 getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); 198 getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender());
139 } 199 }
140 200
141 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 201 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
142 - ActorRef target = getEntityActorRef(msg.getEntityId());  
143 - if (target != null) {  
144 - if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {  
145 - RuleChain ruleChain = systemContext.getRuleChainService().  
146 - findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId()));  
147 - ruleChainManager.visit(ruleChain, target); 202 + if (isRuleEngineForCurrentTenant) {
  203 + ActorRef target = getEntityActorRef(msg.getEntityId());
  204 + if (target != null) {
  205 + if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
  206 + RuleChain ruleChain = systemContext.getRuleChainService().
  207 + findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId()));
  208 + visit(ruleChain, target);
  209 + }
  210 + target.tell(msg, ActorRef.noSender());
  211 + } else {
  212 + log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg);
148 } 213 }
149 - target.tell(msg, ActorRef.noSender());  
150 - } else {  
151 - log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg);  
152 } 214 }
153 } 215 }
154 216
@@ -172,7 +234,7 @@ public class TenantActor extends RuleChainManagerActor { @@ -172,7 +234,7 @@ public class TenantActor extends RuleChainManagerActor {
172 if (removed) { 234 if (removed) {
173 log.debug("[{}] Removed actor:", terminated); 235 log.debug("[{}] Removed actor:", terminated);
174 } else { 236 } else {
175 - log.warn("[{}] Removed actor was not found in the device map!"); 237 + log.debug("Removed actor was not found in the device map!");
176 } 238 }
177 } else { 239 } else {
178 throw new IllegalStateException("Remote actors are not supported!"); 240 throw new IllegalStateException("Remote actors are not supported!");
@@ -195,15 +257,12 @@ public class TenantActor extends RuleChainManagerActor { @@ -195,15 +257,12 @@ public class TenantActor extends RuleChainManagerActor {
195 } 257 }
196 } 258 }
197 259
198 - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() {  
199 - @Override  
200 - public SupervisorStrategy.Directive apply(Throwable t) {  
201 - log.warn("[{}] Unknown failure", tenantId, t);  
202 - if (t instanceof ActorInitializationException) {  
203 - return SupervisorStrategy.stop();  
204 - } else {  
205 - return SupervisorStrategy.resume();  
206 - } 260 + private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> {
  261 + log.warn("[{}] Unknown failure", tenantId, t);
  262 + if (t instanceof ActorInitializationException) {
  263 + return SupervisorStrategy.stop();
  264 + } else {
  265 + return SupervisorStrategy.resume();
207 } 266 }
208 }); 267 });
209 268