Commit e33a336ed93362a12658611a7b9660b4dba8e5e7

Authored by Viacheslav Klimov
2 parents 3b17d14f f12903ba

Merge remote-tracking branch 'origin/master' into feature/bulk-import/device-credentials

# Conflicts:
#	application/src/main/java/org/thingsboard/server/controller/DeviceController.java
#	application/src/main/java/org/thingsboard/server/controller/EdgeController.java
#	common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
#	ui-ngx/src/app/core/http/device.service.ts
Showing 100 changed files with 1270 additions and 830 deletions

Too many changes to show.

To preserve performance only 100 of 261 files are displayed.

@@ -66,6 +66,10 @@ @@ -66,6 +66,10 @@
66 <artifactId>rule-engine-api</artifactId> 66 <artifactId>rule-engine-api</artifactId>
67 </dependency> 67 </dependency>
68 <dependency> 68 <dependency>
  69 + <groupId>org.thingsboard.common</groupId>
  70 + <artifactId>cluster-api</artifactId>
  71 + </dependency>
  72 + <dependency>
69 <groupId>org.thingsboard.rule-engine</groupId> 73 <groupId>org.thingsboard.rule-engine</groupId>
70 <artifactId>rule-engine-components</artifactId> 74 <artifactId>rule-engine-components</artifactId>
71 </dependency> 75 </dependency>
@@ -290,6 +294,11 @@ @@ -290,6 +294,11 @@
290 <scope>test</scope> 294 <scope>test</scope>
291 </dependency> 295 </dependency>
292 <dependency> 296 <dependency>
  297 + <groupId>org.awaitility</groupId>
  298 + <artifactId>awaitility</artifactId>
  299 + <scope>test</scope>
  300 + </dependency>
  301 + <dependency>
293 <groupId>org.mockito</groupId> 302 <groupId>org.mockito</groupId>
294 <artifactId>mockito-core</artifactId> 303 <artifactId>mockito-core</artifactId>
295 <scope>test</scope> 304 <scope>test</scope>
@@ -18,8 +18,8 @@ @@ -18,8 +18,8 @@
18 "resources": [], 18 "resources": [],
19 "templateHtml": "<div style=\"height: 100%; overflow-y: auto;\" id=\"device-terminal\"></div>", 19 "templateHtml": "<div style=\"height: 100%; overflow-y: auto;\" id=\"device-terminal\"></div>",
20 "templateCss": ".cmd .cursor.blink {\n -webkit-animation-name: terminal-underline;\n -moz-animation-name: terminal-underline;\n -ms-animation-name: terminal-underline;\n animation-name: terminal-underline;\n}\n.terminal .inverted, .cmd .inverted {\n border-bottom-color: #aaa;\n}\n\n", 20 "templateCss": ".cmd .cursor.blink {\n -webkit-animation-name: terminal-underline;\n -moz-animation-name: terminal-underline;\n -ms-animation-name: terminal-underline;\n animation-name: terminal-underline;\n}\n.terminal .inverted, .cmd .inverted {\n border-bottom-color: #aaa;\n}\n\n",
21 - "controllerScript": "var requestTimeout = 500;\nvar requestPersistent = false;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n var rpcEnabled = subscription.rpcEnabled;\n var deviceName = 'Simulated';\n var prompt;\n if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n deviceName = subscription.targetDeviceName;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n if (self.ctx.settings.requestPersistent) {\n requestPersistent = self.ctx.settings.requestPersistent;\n }\n var greetings = 'Welcome to ThingsBoard RPC debug terminal.\\n\\n';\n if (!rpcEnabled) {\n greetings += 'Target device is not set!\\n\\n';\n prompt = '';\n } else {\n greetings += 'Current target device for RPC commands: [[b;#fff;]' + deviceName + ']\\n\\n';\n greetings += 'Please type [[b;#fff;]\\'help\\'] to see usage.\\n';\n prompt = '[[b;#8bc34a;]' + deviceName +']> ';\n }\n \n var terminal = $('#device-terminal', self.ctx.$container).terminal(\n function(command) {\n if (command !== '') {\n try {\n var localCommand = command.trim();\n var requestUUID = uuidv4();\n if (localCommand === 'help') {\n printUsage(this);\n } else {\n var spaceIndex = localCommand.indexOf(' ');\n if (spaceIndex === -1 && !localCommand.length) {\n this.error(\"Wrong number of arguments!\");\n this.echo(' ');\n } else {\n var params;\n if (spaceIndex === -1) {\n spaceIndex = localCommand.length;\n }\n var name = localCommand.substr(0, spaceIndex);\n var args = localCommand.substr(spaceIndex + 1);\n if (args.length) {\n try {\n params = JSON.parse(args);\n } catch (e) {\n params = args;\n }\n }\n performRpc(this, name, params, requestUUID);\n }\n }\n } catch(e) {\n this.error(new String(e));\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: greetings,\n prompt: prompt,\n enabled: rpcEnabled\n });\n \n if (!rpcEnabled) {\n terminal.error('No RPC target detected!').pause();\n }\n}\n\n\nfunction printUsage(terminal) {\n var commandsListText = '\\n[[b;#fff;]Usage:]\\n';\n commandsListText += ' <method> [params body]]\\n\\n';\n commandsListText += '[[b;#fff;]Example 1:]\\n'; \n commandsListText += ' myRemoteMethod1 myText\\n\\n'; \n commandsListText += '[[b;#fff;]Example 2:]\\n'; \n commandsListText += ' myOtherRemoteMethod \"{\\\\\"key1\\\\\": 2, \\\\\"key2\\\\\": \\\\\"myVal\\\\\"}\"\\n'; \n terminal.echo(new String(commandsListText));\n}\n\n\nfunction performRpc(terminal, method, params, requestUUID) {\n terminal.pause();\n self.ctx.controlApi.sendTwoWayCommand(method, params, requestTimeout, requestPersistent, requestUUID).subscribe(\n function success(responseBody) {\n terminal.echo(JSON.stringify(responseBody));\n terminal.echo(' ');\n terminal.resume();\n },\n function fail() {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.echo(' ');\n terminal.resume();\n }\n );\n}\n\n\nfunction uuidv4() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\n \nself.onDestroy = function() {\n}",  
22 - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"requestTimeout\",\n \"requestPersistent\"\n ]\n}", 21 + "controllerScript": "var requestTimeout = 500;\nvar requestPersistent = false;\nvar persistentPollingInterval = 5000;\n\nself.onInit = function() {\n var subscription = self.ctx.defaultSubscription;\n var rpcEnabled = subscription.rpcEnabled;\n var deviceName = 'Simulated';\n var prompt;\n if (subscription.targetDeviceName && subscription.targetDeviceName.length) {\n deviceName = subscription.targetDeviceName;\n }\n if (self.ctx.settings.requestTimeout) {\n requestTimeout = self.ctx.settings.requestTimeout;\n }\n if (self.ctx.settings.requestPersistent) {\n requestPersistent = self.ctx.settings.requestPersistent;\n }\n if (self.ctx.settings.persistentPollingInterval) {\n persistentPollingInterval = self.ctx.settings.persistentPollingInterval;\n }\n var greetings = 'Welcome to ThingsBoard RPC debug terminal.\\n\\n';\n if (!rpcEnabled) {\n greetings += 'Target device is not set!\\n\\n';\n prompt = '';\n } else {\n greetings += 'Current target device for RPC commands: [[b;#fff;]' + deviceName + ']\\n\\n';\n greetings += 'Please type [[b;#fff;]\\'help\\'] to see usage.\\n';\n prompt = '[[b;#8bc34a;]' + deviceName +']> ';\n }\n \n var terminal = $('#device-terminal', self.ctx.$container).terminal(\n function(command) {\n if (command !== '') {\n try {\n var localCommand = command.trim();\n var requestUUID = uuidv4();\n if (localCommand === 'help') {\n printUsage(this);\n } else {\n var spaceIndex = localCommand.indexOf(' ');\n if (spaceIndex === -1 && !localCommand.length) {\n this.error(\"Wrong number of arguments!\");\n this.echo(' ');\n } else {\n var params;\n if (spaceIndex === -1) {\n spaceIndex = localCommand.length;\n }\n var name = localCommand.substr(0, spaceIndex);\n var args = localCommand.substr(spaceIndex + 1);\n if (args.length) {\n try {\n params = JSON.parse(args);\n } catch (e) {\n params = args;\n }\n }\n performRpc(this, name, params, requestUUID);\n }\n }\n } catch(e) {\n this.error(new String(e));\n }\n } else {\n this.echo('');\n }\n }, {\n greetings: greetings,\n prompt: prompt,\n enabled: rpcEnabled\n });\n \n if (!rpcEnabled) {\n terminal.error('No RPC target detected!').pause();\n }\n}\n\n\nfunction printUsage(terminal) {\n var commandsListText = '\\n[[b;#fff;]Usage:]\\n';\n commandsListText += ' <method> [params body]]\\n\\n';\n commandsListText += '[[b;#fff;]Example 1:]\\n'; \n commandsListText += ' myRemoteMethod1 myText\\n\\n'; \n commandsListText += '[[b;#fff;]Example 2:]\\n'; \n commandsListText += ' myOtherRemoteMethod \"{\\\\\"key1\\\\\": 2, \\\\\"key2\\\\\": \\\\\"myVal\\\\\"}\"\\n'; \n terminal.echo(new String(commandsListText));\n}\n\n\nfunction performRpc(terminal, method, params, requestUUID) {\n terminal.pause();\n self.ctx.controlApi.sendTwoWayCommand(method, params, requestTimeout, requestPersistent, persistentPollingInterval, requestUUID).subscribe(\n function success(responseBody) {\n terminal.echo(JSON.stringify(responseBody));\n terminal.echo(' ');\n terminal.resume();\n },\n function fail() {\n var errorText = self.ctx.defaultSubscription.rpcErrorText;\n terminal.error(errorText);\n terminal.echo(' ');\n terminal.resume();\n }\n );\n}\n\n\nfunction uuidv4() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n}\n\n \nself.onDestroy = function() {\n self.ctx.controlApi.completedCommand();\n}",
  22 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}",
23 "dataKeySettingsSchema": "{}\n", 23 "dataKeySettingsSchema": "{}\n",
24 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#010101\",\"color\":\"rgba(255, 254, 254, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"RPC debug terminal\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" 24 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#010101\",\"color\":\"rgba(255, 254, 254, 0.87)\",\"padding\":\"0px\",\"settings\":{\"parseGpioStatusFunction\":\"return body[pin] === true;\",\"gpioStatusChangeRequest\":{\"method\":\"setGpioStatus\",\"paramsBody\":\"{\\n \\\"pin\\\": \\\"{$pin}\\\",\\n \\\"enabled\\\": \\\"{$enabled}\\\"\\n}\"},\"requestTimeout\":500,\"switchPanelBackgroundColor\":\"#b71c1c\",\"gpioStatusRequest\":{\"method\":\"getGpioStatus\",\"paramsBody\":\"{}\"},\"gpioList\":[{\"pin\":1,\"label\":\"GPIO 1\",\"row\":0,\"col\":0,\"_uniqueKey\":0},{\"pin\":2,\"label\":\"GPIO 2\",\"row\":0,\"col\":1,\"_uniqueKey\":1},{\"pin\":3,\"label\":\"GPIO 3\",\"row\":1,\"col\":0,\"_uniqueKey\":2}]},\"title\":\"RPC debug terminal\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
25 } 25 }
@@ -55,7 +55,7 @@ @@ -55,7 +55,7 @@
55 "templateHtml": "<tb-knob [ctx]='ctx'></tb-knob>", 55 "templateHtml": "<tb-knob [ctx]='ctx'></tb-knob>",
56 "templateCss": "", 56 "templateCss": "",
57 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", 57 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n",
58 - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\",\n \"default\": 0\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\",\n \"default\": 100\n },\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"number\",\n \"default\": 50\n },\n \"title\": {\n \"title\": \"Knob title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"Set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"minValue\", \"maxValue\", \"getValueMethod\", \"setValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"minValue\",\n \"maxValue\",\n \"initialValue\",\n \"title\",\n \"getValueMethod\",\n \"setValueMethod\",\n \"requestTimeout\"\n ]\n}", 58 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"minValue\": {\n \"title\": \"Minimum value\",\n \"type\": \"number\",\n \"default\": 0\n },\n \"maxValue\": {\n \"title\": \"Maximum value\",\n \"type\": \"number\",\n \"default\": 100\n },\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"number\",\n \"default\": 50\n },\n \"title\": {\n \"title\": \"Knob title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"Set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"minValue\", \"maxValue\", \"getValueMethod\", \"setValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"minValue\",\n \"maxValue\",\n \"initialValue\",\n \"title\",\n \"getValueMethod\",\n \"setValueMethod\",\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}",
59 "dataKeySettingsSchema": "{}\n", 59 "dataKeySettingsSchema": "{}\n",
60 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" 60 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"maxValue\":100,\"initialValue\":50,\"minValue\":0,\"title\":\"Knob control\",\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\"},\"title\":\"Knob Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
61 } 61 }
@@ -73,7 +73,7 @@ @@ -73,7 +73,7 @@
73 "templateHtml": "<tb-switch [ctx]='ctx'></tb-switch>", 73 "templateHtml": "<tb-switch [ctx]='ctx'></tb-switch>",
74 "templateCss": "", 74 "templateCss": "",
75 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", 75 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n",
76 - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showOnOffLabels\": {\n \"title\": \"Show on/off labels\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"showOnOffLabels\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", 76 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"showOnOffLabels\": {\n \"title\": \"Show on/off labels\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"showOnOffLabels\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}",
77 "dataKeySettingsSchema": "{}\n", 77 "dataKeySettingsSchema": "{}\n",
78 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" 78 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
79 } 79 }
@@ -91,7 +91,7 @@ @@ -91,7 +91,7 @@
91 "templateHtml": "<tb-round-switch [ctx]='ctx'></tb-round-switch>", 91 "templateHtml": "<tb-round-switch [ctx]='ctx'></tb-round-switch>",
92 "templateCss": "", 92 "templateCss": "",
93 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", 93 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n",
94 - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", 94 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve on/off value using method\",\n \"type\": \"string\",\n \"default\": \"rpc\"\n },\n \"valueKey\": {\n \"title\": \"Attribute/Timeseries value key (only when subscribe for attribute/timeseries method)\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"getValueMethod\": {\n \"title\": \"RPC get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"RPC set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"convertValueFunction\": {\n \"title\": \"Convert value function, f(value), returns payload used by RPC set value method\",\n \"type\": \"string\",\n \"default\": \"return value;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"none\",\n \"label\": \"Don't retrieve\"\n },\n {\n \"value\": \"rpc\",\n \"label\": \"Call RPC get value method\"\n },\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueKey\",\n \"getValueMethod\",\n \"setValueMethod\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n {\n \"key\": \"convertValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}",
95 "dataKeySettingsSchema": "{}\n", 95 "dataKeySettingsSchema": "{}\n",
96 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" 96 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"title\":\"Round switch\",\"retrieveValueMethod\":\"rpc\",\"valueKey\":\"value\",\"parseValueFunction\":\"return data ? true : false;\",\"convertValueFunction\":\"return value;\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
97 } 97 }
@@ -109,7 +109,7 @@ @@ -109,7 +109,7 @@
109 "templateHtml": "<tb-led-indicator [ctx]='ctx'></tb-led-indicator>", 109 "templateHtml": "<tb-led-indicator [ctx]='ctx'></tb-led-indicator>",
110 "templateCss": "", 110 "templateCss": "",
111 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n", 111 "controllerScript": "self.onInit = function() {\n}\n\nself.onResize = function() {\n}\n\nself.onDestroy = function() {\n}\n",
112 - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"performCheckStatus\": {\n \"title\": \"Perform RPC device status check\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"checkStatusMethod\": {\n \"title\": \"RPC check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve led status value using method\",\n \"type\": \"string\",\n \"default\": \"attribute\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute/timeseries containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse led status value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"performCheckStatus\",\n \"checkStatusMethod\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueAttribute\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\"\n ]\n}", 112 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"performCheckStatus\": {\n \"title\": \"Perform RPC device status check\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"checkStatusMethod\": {\n \"title\": \"RPC check device status method\",\n \"type\": \"string\",\n \"default\": \"checkStatus\"\n },\n \"retrieveValueMethod\": {\n \"title\": \"Retrieve led status value using method\",\n \"type\": \"string\",\n \"default\": \"attribute\"\n },\n \"valueAttribute\": {\n \"title\": \"Device attribute/timeseries containing led status value\",\n \"type\": \"string\",\n \"default\": \"value\"\n },\n \"parseValueFunction\": {\n \"title\": \"Parse led status value function, f(data), returns boolean\",\n \"type\": \"string\",\n \"default\": \"return data ? true : false;\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n }\n },\n \"required\": [\"valueAttribute\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"performCheckStatus\",\n \"checkStatusMethod\",\n {\n \"key\": \"retrieveValueMethod\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"attribute\",\n \"label\": \"Subscribe for attribute\"\n },\n {\n \"value\": \"timeseries\",\n \"label\": \"Subscribe for timeseries\"\n }\n ]\n },\n \"valueAttribute\",\n {\n \"key\": \"parseValueFunction\",\n \"type\": \"javascript\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n }\n ]\n}",
113 "dataKeySettingsSchema": "{}\n", 113 "dataKeySettingsSchema": "{}\n",
114 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}" 114 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valueAttribute\":\"value\",\"retrieveValueMethod\":\"attribute\",\"parseValueFunction\":\"return data ? true : false;\",\"performCheckStatus\":true,\"checkStatusMethod\":\"checkStatus\"},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
115 } 115 }
@@ -126,8 +126,8 @@ @@ -126,8 +126,8 @@
126 "resources": [], 126 "resources": [],
127 "templateHtml": "<div class=\"tb-rpc-button\" fxLayout=\"column\">\n <div fxFlex=\"20\" class=\"title-container\" fxLayout=\"row\"\n fxLayoutAlign=\"center center\" [fxShow]=\"showTitle\">\n <span class=\"button-title\">{{title}}</span>\n </div>\n <div fxFlex=\"{{showTitle ? 80 : 100}}\" [ngStyle]=\"{paddingTop: showTitle ? '5px': '10px'}\"\n class=\"button-container\" fxLayout=\"column\" fxLayoutAlign=\"center center\">\n <div>\n <button mat-button (click)=\"sendCommand()\"\n [class.mat-raised-button]=\"styleButton?.isRaised\"\n [color]=\"styleButton?.isPrimary ? 'primary' : ''\"\n [ngStyle]=\"customStyle\">\n {{buttonLable}}\n </button>\n </div>\n </div>\n <div class=\"error-container\" [ngStyle]=\"{'background': error?.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n fxLayout=\"row\" fxLayoutAlign=\"center center\">\n <span class=\"button-error\">{{ error }}</span>\n </div>\n</div>", 127 "templateHtml": "<div class=\"tb-rpc-button\" fxLayout=\"column\">\n <div fxFlex=\"20\" class=\"title-container\" fxLayout=\"row\"\n fxLayoutAlign=\"center center\" [fxShow]=\"showTitle\">\n <span class=\"button-title\">{{title}}</span>\n </div>\n <div fxFlex=\"{{showTitle ? 80 : 100}}\" [ngStyle]=\"{paddingTop: showTitle ? '5px': '10px'}\"\n class=\"button-container\" fxLayout=\"column\" fxLayoutAlign=\"center center\">\n <div>\n <button mat-button (click)=\"sendCommand()\"\n [class.mat-raised-button]=\"styleButton?.isRaised\"\n [color]=\"styleButton?.isPrimary ? 'primary' : ''\"\n [ngStyle]=\"customStyle\">\n {{buttonLable}}\n </button>\n </div>\n </div>\n <div class=\"error-container\" [ngStyle]=\"{'background': error?.length ? 'rgba(255,255,255,0.25)' : 'none'}\"\n fxLayout=\"row\" fxLayoutAlign=\"center center\">\n <span class=\"button-error\">{{ error }}</span>\n </div>\n</div>",
128 "templateCss": ".tb-rpc-button {\n width: 100%;\n height: 100%;\n}\n\n.tb-rpc-button .title-container {\n font-weight: 500;\n white-space: nowrap;\n margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n min-width: 80%\n}\n\n.tb-rpc-button .button-container .mat-button{\n width: 100%;\n margin: 0;\n}\n\n.tb-rpc-button .error-container {\n position: absolute;\n top: 2%;\n right: 0;\n left: 0;\n z-index: 4;\n height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n color: #ff3315;\n white-space: nowrap;\n}", 128 "templateCss": ".tb-rpc-button {\n width: 100%;\n height: 100%;\n}\n\n.tb-rpc-button .title-container {\n font-weight: 500;\n white-space: nowrap;\n margin: 10px 0;\n}\n\n.tb-rpc-button .button-container div{\n min-width: 80%\n}\n\n.tb-rpc-button .button-container .mat-button{\n width: 100%;\n margin: 0;\n}\n\n.tb-rpc-button .error-container {\n position: absolute;\n top: 2%;\n right: 0;\n left: 0;\n z-index: 4;\n height: 14px;\n}\n\n.tb-rpc-button .error-container .button-error {\n color: #ff3315;\n white-space: nowrap;\n}",
129 - "controllerScript": "self.onInit = function() {\n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges();\n });\n};\n\nfunction init() {\n let rpcEnabled = self.ctx.defaultSubscription.rpcEnabled;\n\n self.ctx.$scope.buttonLable = self.ctx.settings.buttonText;\n self.ctx.$scope.showTitle = self.ctx.settings.title &&\n self.ctx.settings.title.length ? true : false;\n self.ctx.$scope.title = self.ctx.settings.title;\n self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n\n if (self.ctx.settings.styleButton.isPrimary ===\n false) {\n self.ctx.$scope.customStyle = {\n 'background-color': self.ctx.$scope.styleButton.bgColor,\n 'color': self.ctx.$scope.styleButton.textColor\n };\n }\n\n if (!rpcEnabled) {\n self.ctx.$scope.error =\n 'Target device is not set!';\n }\n\n self.ctx.$scope.sendCommand = function() {\n var rpcMethod = self.ctx.settings.methodName;\n var rpcParams = self.ctx.settings.methodParams;\n var timeout = self.ctx.settings.requestTimeout;\n var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ?\n true : false;\n\n var commandPromise;\n if (oneWayElseTwoWay) {\n commandPromise = self.ctx.controlApi.sendOneWayCommand(\n rpcMethod, rpcParams, timeout);\n } else {\n commandPromise = self.ctx.controlApi.sendTwoWayCommand(\n rpcMethod, rpcParams, timeout);\n }\n commandPromise.subscribe(\n function success() {\n self.ctx.$scope.error = \"\";\n self.ctx.detectChanges();\n },\n function fail(rejection) {\n if (self.ctx.settings.showError) {\n self.ctx.$scope.error =\n rejection.status + \": \" +\n rejection.statusText;\n self.ctx.detectChanges();\n }\n }\n );\n };\n}\n",  
130 - "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"title\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"buttonText\": {\n \"title\": \"Button label\",\n \"type\": \"string\",\n \"default\": \"Send RPC\"\n },\n \"oneWayElseTwoWay\": {\n \"title\": \"Is One Way Command\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showError\": {\n \"title\": \"Show RPC command execution error\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"methodName\": {\n \"title\": \"RPC method\",\n \"type\": \"string\",\n \"default\": \"rpcCommand\"\n },\n \"methodParams\": {\n \"title\": \"RPC method params\",\n \"type\": \"string\",\n \"default\": \"{}\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 5000\n },\n \"styleButton\": {\n \"type\": \"object\",\n \"title\": \"Button Style\",\n \"properties\": {\n \"isRaised\": {\n \"type\": \"boolean\",\n \"title\": \"Raised\",\n \"default\": true\n },\n \"isPrimary\": {\n \"type\": \"boolean\",\n \"title\": \"Primary color\",\n \"default\": false\n },\n \"bgColor\": {\n \"type\": \"string\",\n \"title\": \"Button background color\",\n \"default\": null\n },\n \"textColor\": {\n \"type\": \"string\",\n \"title\": \"Button text color\",\n \"default\": null\n }\n }\n },\n \"required\": []\n }\n },\n \"form\": [\n \"title\",\n \"buttonText\",\n \"oneWayElseTwoWay\",\n \"showError\",\n \"methodName\",\n {\n \"key\": \"methodParams\",\n \"type\": \"json\"\n },\n \"requestTimeout\",\n {\n \"key\": \"styleButton\",\n \"items\": [\n \"styleButton.isRaised\",\n \"styleButton.isPrimary\",\n {\n \"key\": \"styleButton.bgColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"styleButton.textColor\",\n \"type\": \"color\"\n }\n ]\n }\n ]\n\n}", 129 + "controllerScript": "var requestPersistent = false;\nvar persistentPollingInterval = 5000;\n\nself.onInit = function() {\n if (self.ctx.settings.requestPersistent) {\n requestPersistent = self.ctx.settings.requestPersistent;\n }\n if (self.ctx.settings.persistentPollingInterval) {\n persistentPollingInterval = self.ctx.settings.persistentPollingInterval;\n }\n \n self.ctx.ngZone.run(function() {\n init(); \n self.ctx.detectChanges();\n });\n};\n\nfunction init() {\n let rpcEnabled = self.ctx.defaultSubscription.rpcEnabled;\n\n self.ctx.$scope.buttonLable = self.ctx.settings.buttonText;\n self.ctx.$scope.showTitle = self.ctx.settings.title &&\n self.ctx.settings.title.length ? true : false;\n self.ctx.$scope.title = self.ctx.settings.title;\n self.ctx.$scope.styleButton = self.ctx.settings.styleButton;\n\n if (self.ctx.settings.styleButton.isPrimary ===\n false) {\n self.ctx.$scope.customStyle = {\n 'background-color': self.ctx.$scope.styleButton.bgColor,\n 'color': self.ctx.$scope.styleButton.textColor\n };\n }\n\n if (!rpcEnabled) {\n self.ctx.$scope.error =\n 'Target device is not set!';\n }\n\n self.ctx.$scope.sendCommand = function() {\n var rpcMethod = self.ctx.settings.methodName;\n var rpcParams = self.ctx.settings.methodParams;\n var timeout = self.ctx.settings.requestTimeout;\n var oneWayElseTwoWay = self.ctx.settings.oneWayElseTwoWay ?\n true : false;\n\n var commandPromise;\n if (oneWayElseTwoWay) {\n commandPromise = self.ctx.controlApi.sendOneWayCommand(\n rpcMethod, rpcParams, timeout, requestPersistent, persistentPollingInterval);\n } else {\n commandPromise = self.ctx.controlApi.sendTwoWayCommand(\n rpcMethod, rpcParams, timeout, requestPersistent, persistentPollingInterval);\n }\n commandPromise.subscribe(\n function success() {\n self.ctx.$scope.error = \"\";\n self.ctx.detectChanges();\n },\n function fail(rejection) {\n if (self.ctx.settings.showError) {\n self.ctx.$scope.error =\n rejection.status + \": \" +\n rejection.statusText;\n self.ctx.detectChanges();\n }\n }\n );\n };\n}\n\nself.onDestroy = function() {\n self.ctx.controlApi.completedCommand();\n}\n",
  130 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"title\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"buttonText\": {\n \"title\": \"Button label\",\n \"type\": \"string\",\n \"default\": \"Send RPC\"\n },\n \"oneWayElseTwoWay\": {\n \"title\": \"Is One Way Command\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showError\": {\n \"title\": \"Show RPC command execution error\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"methodName\": {\n \"title\": \"RPC method\",\n \"type\": \"string\",\n \"default\": \"rpcCommand\"\n },\n \"methodParams\": {\n \"title\": \"RPC method params\",\n \"type\": \"string\",\n \"default\": \"{}\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 5000\n },\n \"requestPersistent\": {\n \"title\": \"RPC request persistent\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"persistentPollingInterval\": {\n \"title\": \"Polling interval in milliseconds to get persistent RPC command response\",\n \"type\": \"number\",\n \"default\": 5000,\n \"minimum\": 1000\n },\n \"styleButton\": {\n \"type\": \"object\",\n \"title\": \"Button Style\",\n \"properties\": {\n \"isRaised\": {\n \"type\": \"boolean\",\n \"title\": \"Raised\",\n \"default\": true\n },\n \"isPrimary\": {\n \"type\": \"boolean\",\n \"title\": \"Primary color\",\n \"default\": false\n },\n \"bgColor\": {\n \"type\": \"string\",\n \"title\": \"Button background color\",\n \"default\": null\n },\n \"textColor\": {\n \"type\": \"string\",\n \"title\": \"Button text color\",\n \"default\": null\n }\n }\n },\n \"required\": []\n }\n },\n \"form\": [\n \"title\",\n \"buttonText\",\n \"oneWayElseTwoWay\",\n \"showError\",\n \"methodName\",\n {\n \"key\": \"methodParams\",\n \"type\": \"json\"\n },\n \"requestTimeout\",\n \"requestPersistent\",\n {\n \"key\": \"persistentPollingInterval\",\n \"condition\": \"model.requestPersistent === true\"\n },\n {\n \"key\": \"styleButton\",\n \"items\": [\n \"styleButton.isRaised\",\n \"styleButton.isPrimary\",\n {\n \"key\": \"styleButton.bgColor\",\n \"type\": \"color\"\n },\n {\n \"key\": \"styleButton.textColor\",\n \"type\": \"color\"\n }\n ]\n }\n ]\n\n}",
131 "dataKeySettingsSchema": "{}\n", 131 "dataKeySettingsSchema": "{}\n",
132 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":5000,\"oneWayElseTwoWay\":true,\"buttonText\":\"Send RPC\",\"styleButton\":{\"isRaised\":true,\"isPrimary\":false},\"methodName\":\"rpcCommand\",\"methodParams\":\"{}\"},\"title\":\"RPC Button\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" 132 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#e6e7e8\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":5000,\"oneWayElseTwoWay\":true,\"buttonText\":\"Send RPC\",\"styleButton\":{\"isRaised\":true,\"isPrimary\":false},\"methodName\":\"rpcCommand\",\"methodParams\":\"{}\"},\"title\":\"RPC Button\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
133 } 133 }
@@ -209,6 +209,7 @@ CREATE TABLE IF NOT EXISTS rpc ( @@ -209,6 +209,7 @@ CREATE TABLE IF NOT EXISTS rpc (
209 expiration_time bigint NOT NULL, 209 expiration_time bigint NOT NULL,
210 request varchar(10000000) NOT NULL, 210 request varchar(10000000) NOT NULL,
211 response varchar(10000000), 211 response varchar(10000000),
  212 + additional_info varchar(10000000),
212 status varchar(255) NOT NULL 213 status varchar(255) NOT NULL
213 ); 214 );
214 215
@@ -81,7 +81,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService; @@ -81,7 +81,7 @@ import org.thingsboard.server.service.executors.ExternalCallExecutorService;
81 import org.thingsboard.server.service.executors.SharedEventLoopGroupService; 81 import org.thingsboard.server.service.executors.SharedEventLoopGroupService;
82 import org.thingsboard.server.service.mail.MailExecutorService; 82 import org.thingsboard.server.service.mail.MailExecutorService;
83 import org.thingsboard.server.service.profile.TbDeviceProfileCache; 83 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
84 -import org.thingsboard.server.service.queue.TbClusterService; 84 +import org.thingsboard.server.cluster.TbClusterService;
85 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; 85 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
86 import org.thingsboard.server.service.rpc.TbRpcService; 86 import org.thingsboard.server.service.rpc.TbRpcService;
87 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; 87 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
@@ -55,7 +55,7 @@ public class AppActor extends ContextAwareActor { @@ -55,7 +55,7 @@ public class AppActor extends ContextAwareActor {
55 private final TbTenantProfileCache tenantProfileCache; 55 private final TbTenantProfileCache tenantProfileCache;
56 private final TenantService tenantService; 56 private final TenantService tenantService;
57 private final Set<TenantId> deletedTenants; 57 private final Set<TenantId> deletedTenants;
58 - private boolean ruleChainsInitialized; 58 + private volatile boolean ruleChainsInitialized;
59 59
60 private AppActor(ActorSystemContext systemContext) { 60 private AppActor(ActorSystemContext systemContext) {
61 super(systemContext); 61 super(systemContext);
@@ -69,7 +69,7 @@ public class AppActor extends ContextAwareActor { @@ -69,7 +69,7 @@ public class AppActor extends ContextAwareActor {
69 if (!ruleChainsInitialized) { 69 if (!ruleChainsInitialized) {
70 initTenantActors(); 70 initTenantActors();
71 ruleChainsInitialized = true; 71 ruleChainsInitialized = true;
72 - if (msg.getMsgType() != MsgType.APP_INIT_MSG) { 72 + if (msg.getMsgType() != MsgType.APP_INIT_MSG && msg.getMsgType() != MsgType.PARTITION_CHANGE_MSG) {
73 log.warn("Rule Chains initialized by unexpected message: {}", msg); 73 log.warn("Rule Chains initialized by unexpected message: {}", msg);
74 } 74 }
75 } 75 }
@@ -95,6 +95,7 @@ public class AppActor extends ContextAwareActor { @@ -95,6 +95,7 @@ public class AppActor extends ContextAwareActor {
95 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 95 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
96 case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: 96 case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
97 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: 97 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
  98 + case REMOVE_RPC_TO_DEVICE_ACTOR_MSG:
98 onToDeviceActorMsg((TenantAwareMsg) msg, true); 99 onToDeviceActorMsg((TenantAwareMsg) msg, true);
99 break; 100 break;
100 case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG: 101 case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG:
@@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.TenantId;
28 import org.thingsboard.server.common.msg.TbActorMsg; 28 import org.thingsboard.server.common.msg.TbActorMsg;
29 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; 29 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
30 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; 30 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg;
  31 +import org.thingsboard.server.service.rpc.RemoveRpcActorMsg;
31 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 32 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
32 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; 33 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
33 34
@@ -84,6 +85,9 @@ public class DeviceActor extends ContextAwareActor { @@ -84,6 +85,9 @@ public class DeviceActor extends ContextAwareActor {
84 case DEVICE_EDGE_UPDATE_TO_DEVICE_ACTOR_MSG: 85 case DEVICE_EDGE_UPDATE_TO_DEVICE_ACTOR_MSG:
85 processor.processEdgeUpdate((DeviceEdgeUpdateMsg) msg); 86 processor.processEdgeUpdate((DeviceEdgeUpdateMsg) msg);
86 break; 87 break;
  88 + case REMOVE_RPC_TO_DEVICE_ACTOR_MSG:
  89 + processor.processRemoveRpc(ctx, (RemoveRpcActorMsg) msg);
  90 + break;
87 default: 91 default:
88 return false; 92 return false;
89 } 93 }
@@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j; @@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
26 import org.apache.commons.collections.CollectionUtils; 26 import org.apache.commons.collections.CollectionUtils;
27 import org.thingsboard.common.util.JacksonUtil; 27 import org.thingsboard.common.util.JacksonUtil;
28 import org.thingsboard.common.util.LinkedHashMapRemoveEldest; 28 import org.thingsboard.common.util.LinkedHashMapRemoveEldest;
29 -import org.thingsboard.rule.engine.api.RpcError; 29 +import org.thingsboard.server.common.data.rpc.RpcError;
30 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; 30 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
31 import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; 31 import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
32 import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg; 32 import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg;
@@ -86,8 +86,9 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; @@ -86,8 +86,9 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
86 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; 86 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto;
87 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; 87 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
88 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; 88 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
89 -import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 89 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
90 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; 90 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg;
  91 +import org.thingsboard.server.service.rpc.RemoveRpcActorMsg;
91 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 92 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
92 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; 93 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
93 94
@@ -97,11 +98,9 @@ import java.util.Arrays; @@ -97,11 +98,9 @@ import java.util.Arrays;
97 import java.util.Collections; 98 import java.util.Collections;
98 import java.util.HashMap; 99 import java.util.HashMap;
99 import java.util.HashSet; 100 import java.util.HashSet;
100 -import java.util.LinkedHashMap;  
101 import java.util.List; 101 import java.util.List;
102 import java.util.Map; 102 import java.util.Map;
103 import java.util.Objects; 103 import java.util.Objects;
104 -import java.util.Optional;  
105 import java.util.Set; 104 import java.util.Set;
106 import java.util.UUID; 105 import java.util.UUID;
107 import java.util.function.Consumer; 106 import java.util.function.Consumer;
@@ -236,6 +235,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -236,6 +235,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
236 rpc.setExpirationTime(request.getExpirationTime()); 235 rpc.setExpirationTime(request.getExpirationTime());
237 rpc.setRequest(JacksonUtil.valueToTree(request)); 236 rpc.setRequest(JacksonUtil.valueToTree(request));
238 rpc.setStatus(status); 237 rpc.setStatus(status);
  238 + rpc.setAdditionalInfo(JacksonUtil.valueToTree(request.getAdditionalInfo()));
239 return systemContext.getTbRpcService().save(tenantId, rpc); 239 return systemContext.getTbRpcService().save(tenantId, rpc);
240 } 240 }
241 241
@@ -264,6 +264,21 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -264,6 +264,21 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
264 } 264 }
265 } 265 }
266 266
  267 + void processRemoveRpc(TbActorCtx context, RemoveRpcActorMsg msg) {
  268 + log.debug("[{}] Processing remove rpc command", msg.getRequestId());
  269 + Integer requestId = null;
  270 + for (Map.Entry<Integer, ToDeviceRpcRequestMetadata> entry : toDeviceRpcPendingMap.entrySet()) {
  271 + if (entry.getValue().getMsg().getMsg().getId().equals(msg.getRequestId())) {
  272 + requestId = entry.getKey();
  273 + break;
  274 + }
  275 + }
  276 +
  277 + if (requestId != null) {
  278 + toDeviceRpcPendingMap.remove(requestId);
  279 + }
  280 + }
  281 +
267 private void registerPendingRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { 282 private void registerPendingRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) {
268 toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); 283 toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent));
269 DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); 284 DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout);
@@ -383,11 +398,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -383,11 +398,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
383 } 398 }
384 399
385 private void reportSessionOpen() { 400 private void reportSessionOpen() {
386 - systemContext.getDeviceStateService().onDeviceConnect(deviceId); 401 + systemContext.getDeviceStateService().onDeviceConnect(tenantId, deviceId);
387 } 402 }
388 403
389 private void reportSessionClose() { 404 private void reportSessionClose() {
390 - systemContext.getDeviceStateService().onDeviceDisconnect(deviceId); 405 + systemContext.getDeviceStateService().onDeviceDisconnect(tenantId, deviceId);
391 } 406 }
392 407
393 private void handleGetAttributesRequest(TbActorCtx context, SessionInfoProto sessionInfo, GetAttributeRequestMsg request) { 408 private void handleGetAttributesRequest(TbActorCtx context, SessionInfoProto sessionInfo, GetAttributeRequestMsg request) {
@@ -586,13 +601,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -586,13 +601,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
586 log.debug("[{}] Received duplicate session open event [{}]", deviceId, sessionId); 601 log.debug("[{}] Received duplicate session open event [{}]", deviceId, sessionId);
587 return; 602 return;
588 } 603 }
589 - log.info("[{}] Processing new session [{}]. Current sessions size {}", deviceId, sessionId, sessions.size()); 604 + log.debug("[{}] Processing new session [{}]. Current sessions size {}", deviceId, sessionId, sessions.size());
590 605
591 sessions.put(sessionId, new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfo.getNodeId()))); 606 sessions.put(sessionId, new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfo.getNodeId())));
592 if (sessions.size() == 1) { 607 if (sessions.size() == 1) {
593 reportSessionOpen(); 608 reportSessionOpen();
594 } 609 }
595 - systemContext.getDeviceStateService().onDeviceActivity(deviceId, System.currentTimeMillis()); 610 + systemContext.getDeviceStateService().onDeviceActivity(tenantId, deviceId, System.currentTimeMillis());
596 dumpSessions(); 611 dumpSessions();
597 } else if (msg.getEvent() == SessionEvent.CLOSED) { 612 } else if (msg.getEvent() == SessionEvent.CLOSED) {
598 log.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); 613 log.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId);
@@ -622,7 +637,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -622,7 +637,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
622 if (subscriptionInfo.getRpcSubscription()) { 637 if (subscriptionInfo.getRpcSubscription()) {
623 rpcSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo()); 638 rpcSubscriptions.putIfAbsent(sessionId, sessionMD.getSessionInfo());
624 } 639 }
625 - systemContext.getDeviceStateService().onDeviceActivity(deviceId, subscriptionInfo.getLastActivityTime()); 640 + systemContext.getDeviceStateService().onDeviceActivity(tenantId, deviceId, subscriptionInfo.getLastActivityTime());
626 dumpSessions(); 641 dumpSessions();
627 } 642 }
628 643
@@ -729,18 +744,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -729,18 +744,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
729 edgeEvent.setBody(body); 744 edgeEvent.setBody(body);
730 745
731 edgeEvent.setEdgeId(edgeId); 746 edgeEvent.setEdgeId(edgeId);
732 - ListenableFuture<EdgeEvent> future = systemContext.getEdgeEventService().saveAsync(edgeEvent);  
733 - Futures.addCallback(future, new FutureCallback<EdgeEvent>() {  
734 - @Override  
735 - public void onSuccess(EdgeEvent result) {  
736 - systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId);  
737 - }  
738 -  
739 - @Override  
740 - public void onFailure(Throwable t) {  
741 - log.warn("[{}] Can't save edge event [{}] for edge [{}]", tenantId.getId(), edgeEvent, edgeId.getId(), t);  
742 - }  
743 - }, systemContext.getDbCallbackExecutor()); 747 + systemContext.getEdgeEventService().save(edgeEvent);
  748 + systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId);
744 } 749 }
745 750
746 private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) { 751 private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) {
@@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbRelationTypes; @@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbRelationTypes;
33 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; 33 import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
34 import org.thingsboard.server.actors.ActorSystemContext; 34 import org.thingsboard.server.actors.ActorSystemContext;
35 import org.thingsboard.server.actors.TbActorRef; 35 import org.thingsboard.server.actors.TbActorRef;
  36 +import org.thingsboard.server.cluster.TbClusterService;
36 import org.thingsboard.server.common.data.Customer; 37 import org.thingsboard.server.common.data.Customer;
37 import org.thingsboard.server.common.data.DataConstants; 38 import org.thingsboard.server.common.data.DataConstants;
38 import org.thingsboard.server.common.data.Device; 39 import org.thingsboard.server.common.data.Device;
@@ -454,6 +455,11 @@ class DefaultTbContext implements TbContext { @@ -454,6 +455,11 @@ class DefaultTbContext implements TbContext {
454 } 455 }
455 456
456 @Override 457 @Override
  458 + public TbClusterService getClusterService() {
  459 + return mainCtx.getClusterService();
  460 + }
  461 +
  462 + @Override
457 public DashboardService getDashboardService() { 463 public DashboardService getDashboardService() {
458 return mainCtx.getDashboardService(); 464 return mainCtx.getDashboardService();
459 } 465 }
@@ -49,7 +49,7 @@ import org.thingsboard.server.queue.TbQueueCallback; @@ -49,7 +49,7 @@ import org.thingsboard.server.queue.TbQueueCallback;
49 import org.thingsboard.server.queue.common.MultipleTbQueueTbMsgCallbackWrapper; 49 import org.thingsboard.server.queue.common.MultipleTbQueueTbMsgCallbackWrapper;
50 import org.thingsboard.server.queue.common.TbQueueTbMsgCallbackWrapper; 50 import org.thingsboard.server.queue.common.TbQueueTbMsgCallbackWrapper;
51 import org.thingsboard.server.queue.usagestats.TbApiUsageClient; 51 import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
52 -import org.thingsboard.server.service.queue.TbClusterService; 52 +import org.thingsboard.server.cluster.TbClusterService;
53 53
54 import java.util.ArrayList; 54 import java.util.ArrayList;
55 import java.util.Collections; 55 import java.util.Collections;
@@ -165,6 +165,7 @@ public class TenantActor extends RuleChainManagerActor { @@ -165,6 +165,7 @@ public class TenantActor extends RuleChainManagerActor {
165 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 165 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
166 case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: 166 case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
167 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: 167 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
  168 + case REMOVE_RPC_TO_DEVICE_ACTOR_MSG:
168 onToDeviceActorMsg((DeviceAwareMsg) msg, true); 169 onToDeviceActorMsg((DeviceAwareMsg) msg, true);
169 break; 170 break;
170 case RULE_CHAIN_TO_RULE_CHAIN_MSG: 171 case RULE_CHAIN_TO_RULE_CHAIN_MSG:
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.google.common.util.concurrent.FutureCallback;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.beans.factory.annotation.Value;
  23 +import org.springframework.http.HttpStatus;
  24 +import org.springframework.http.ResponseEntity;
  25 +import org.springframework.util.StringUtils;
  26 +import org.springframework.web.context.request.async.DeferredResult;
  27 +import org.thingsboard.common.util.JacksonUtil;
  28 +import org.thingsboard.server.common.data.rpc.RpcError;
  29 +import org.thingsboard.server.common.data.DataConstants;
  30 +import org.thingsboard.server.common.data.audit.ActionType;
  31 +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
  32 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  33 +import org.thingsboard.server.common.data.id.DeviceId;
  34 +import org.thingsboard.server.common.data.id.EntityId;
  35 +import org.thingsboard.server.common.data.id.TenantId;
  36 +import org.thingsboard.server.common.data.id.UUIDBased;
  37 +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
  38 +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
  39 +import org.thingsboard.server.queue.util.TbCoreComponent;
  40 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
  41 +import org.thingsboard.server.service.rpc.LocalRequestMetaData;
  42 +import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
  43 +import org.thingsboard.server.service.security.AccessValidator;
  44 +import org.thingsboard.server.service.security.model.SecurityUser;
  45 +import org.thingsboard.server.service.security.permission.Operation;
  46 +import org.thingsboard.server.service.telemetry.exception.ToErrorResponseEntity;
  47 +
  48 +import javax.annotation.Nullable;
  49 +import java.util.Optional;
  50 +import java.util.UUID;
  51 +
  52 +/**
  53 + * Created by ashvayka on 22.03.18.
  54 + */
  55 +@TbCoreComponent
  56 +@Slf4j
  57 +public abstract class AbstractRpcController extends BaseController {
  58 +
  59 + @Autowired
  60 + protected TbCoreDeviceRpcService deviceRpcService;
  61 +
  62 + @Autowired
  63 + private AccessValidator accessValidator;
  64 +
  65 + @Value("${server.rest.server_side_rpc.min_timeout:5000}")
  66 + protected long minTimeout;
  67 +
  68 + @Value("${server.rest.server_side_rpc.default_timeout:10000}")
  69 + protected long defaultTimeout;
  70 +
  71 + protected DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody, HttpStatus timeoutStatus, HttpStatus noActiveConnectionStatus) throws ThingsboardException {
  72 + try {
  73 + JsonNode rpcRequestBody = JacksonUtil.toJsonNode(requestBody);
  74 + ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(rpcRequestBody.get("method").asText(), JacksonUtil.toString(rpcRequestBody.get("params")));
  75 + SecurityUser currentUser = getCurrentUser();
  76 + TenantId tenantId = currentUser.getTenantId();
  77 + final DeferredResult<ResponseEntity> response = new DeferredResult<>();
  78 + long timeout = rpcRequestBody.has("timeout") ? rpcRequestBody.get("timeout").asLong() : defaultTimeout;
  79 + long expTime = System.currentTimeMillis() + Math.max(minTimeout, timeout);
  80 + UUID rpcRequestUUID = rpcRequestBody.has("requestUUID") ? UUID.fromString(rpcRequestBody.get("requestUUID").asText()) : UUID.randomUUID();
  81 + boolean persisted = rpcRequestBody.has(DataConstants.PERSISTENT) && rpcRequestBody.get(DataConstants.PERSISTENT).asBoolean();
  82 + String additionalInfo = JacksonUtil.toString(rpcRequestBody.get(DataConstants.ADDITIONAL_INFO));
  83 + accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<>() {
  84 + @Override
  85 + public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {
  86 + ToDeviceRpcRequest rpcRequest = new ToDeviceRpcRequest(rpcRequestUUID,
  87 + tenantId,
  88 + deviceId,
  89 + oneWay,
  90 + expTime,
  91 + body,
  92 + persisted,
  93 + additionalInfo
  94 + );
  95 + deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse, timeoutStatus, noActiveConnectionStatus), currentUser);
  96 + }
  97 +
  98 + @Override
  99 + public void onFailure(Throwable e) {
  100 + ResponseEntity entity;
  101 + if (e instanceof ToErrorResponseEntity) {
  102 + entity = ((ToErrorResponseEntity) e).toErrorResponseEntity();
  103 + } else {
  104 + entity = new ResponseEntity(HttpStatus.UNAUTHORIZED);
  105 + }
  106 + logRpcCall(currentUser, deviceId, body, oneWay, Optional.empty(), e);
  107 + response.setResult(entity);
  108 + }
  109 + }));
  110 + return response;
  111 + } catch (IllegalArgumentException ioe) {
  112 + throw new ThingsboardException("Invalid request body", ioe, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
  113 + }
  114 + }
  115 +
  116 + public void reply(LocalRequestMetaData rpcRequest, FromDeviceRpcResponse response, HttpStatus timeoutStatus, HttpStatus noActiveConnectionStatus) {
  117 + Optional<RpcError> rpcError = response.getError();
  118 + DeferredResult<ResponseEntity> responseWriter = rpcRequest.getResponseWriter();
  119 + if (rpcError.isPresent()) {
  120 + logRpcCall(rpcRequest, rpcError, null);
  121 + RpcError error = rpcError.get();
  122 + switch (error) {
  123 + case TIMEOUT:
  124 + responseWriter.setResult(new ResponseEntity<>(timeoutStatus));
  125 + break;
  126 + case NO_ACTIVE_CONNECTION:
  127 + responseWriter.setResult(new ResponseEntity<>(noActiveConnectionStatus));
  128 + break;
  129 + default:
  130 + responseWriter.setResult(new ResponseEntity<>(timeoutStatus));
  131 + break;
  132 + }
  133 + } else {
  134 + Optional<String> responseData = response.getResponse();
  135 + if (responseData.isPresent() && !StringUtils.isEmpty(responseData.get())) {
  136 + String data = responseData.get();
  137 + try {
  138 + logRpcCall(rpcRequest, rpcError, null);
  139 + responseWriter.setResult(new ResponseEntity<>(JacksonUtil.toJsonNode(data), HttpStatus.OK));
  140 + } catch (IllegalArgumentException e) {
  141 + log.debug("Failed to decode device response: {}", data, e);
  142 + logRpcCall(rpcRequest, rpcError, e);
  143 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE));
  144 + }
  145 + } else {
  146 + logRpcCall(rpcRequest, rpcError, null);
  147 + responseWriter.setResult(new ResponseEntity<>(HttpStatus.OK));
  148 + }
  149 + }
  150 + }
  151 +
  152 + private void logRpcCall(LocalRequestMetaData rpcRequest, Optional<RpcError> rpcError, Throwable e) {
  153 + logRpcCall(rpcRequest.getUser(), rpcRequest.getRequest().getDeviceId(), rpcRequest.getRequest().getBody(), rpcRequest.getRequest().isOneway(), rpcError, null);
  154 + }
  155 +
  156 +
  157 + private void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e) {
  158 + String rpcErrorStr = "";
  159 + if (rpcError.isPresent()) {
  160 + rpcErrorStr = "RPC Error: " + rpcError.get().name();
  161 + }
  162 + String method = body.getMethod();
  163 + String params = body.getParams();
  164 +
  165 + auditLogService.logEntityAction(
  166 + user.getTenantId(),
  167 + user.getCustomerId(),
  168 + user.getId(),
  169 + user.getName(),
  170 + (UUIDBased & EntityId) entityId,
  171 + null,
  172 + ActionType.RPC_CALL,
  173 + BaseController.toException(e),
  174 + rpcErrorStr,
  175 + oneWay,
  176 + method,
  177 + params);
  178 + }
  179 +
  180 +
  181 +}
@@ -26,12 +26,12 @@ import org.springframework.web.bind.annotation.ResponseBody; @@ -26,12 +26,12 @@ import org.springframework.web.bind.annotation.ResponseBody;
26 import org.springframework.web.bind.annotation.RestController; 26 import org.springframework.web.bind.annotation.RestController;
27 import org.thingsboard.rule.engine.api.MailService; 27 import org.thingsboard.rule.engine.api.MailService;
28 import org.thingsboard.rule.engine.api.SmsService; 28 import org.thingsboard.rule.engine.api.SmsService;
29 -import org.thingsboard.server.common.data.sms.config.TestSmsRequest;  
30 import org.thingsboard.server.common.data.AdminSettings; 29 import org.thingsboard.server.common.data.AdminSettings;
31 import org.thingsboard.server.common.data.UpdateMessage; 30 import org.thingsboard.server.common.data.UpdateMessage;
32 import org.thingsboard.server.common.data.exception.ThingsboardException; 31 import org.thingsboard.server.common.data.exception.ThingsboardException;
33 import org.thingsboard.server.common.data.id.TenantId; 32 import org.thingsboard.server.common.data.id.TenantId;
34 import org.thingsboard.server.common.data.security.model.SecuritySettings; 33 import org.thingsboard.server.common.data.security.model.SecuritySettings;
  34 +import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
35 import org.thingsboard.server.dao.settings.AdminSettingsService; 35 import org.thingsboard.server.dao.settings.AdminSettingsService;
36 import org.thingsboard.server.queue.util.TbCoreComponent; 36 import org.thingsboard.server.queue.util.TbCoreComponent;
37 import org.thingsboard.server.service.security.permission.Operation; 37 import org.thingsboard.server.service.security.permission.Operation;
@@ -67,7 +67,7 @@ public class AdminController extends BaseController { @@ -67,7 +67,7 @@ public class AdminController extends BaseController {
67 accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ); 67 accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
68 AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key)); 68 AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key));
69 if (adminSettings.getKey().equals("mail")) { 69 if (adminSettings.getKey().equals("mail")) {
70 - ((ObjectNode) adminSettings.getJsonValue()).put("password", ""); 70 + ((ObjectNode) adminSettings.getJsonValue()).remove("password");
71 } 71 }
72 return adminSettings; 72 return adminSettings;
73 } catch (Exception e) { 73 } catch (Exception e) {
@@ -84,7 +84,7 @@ public class AdminController extends BaseController { @@ -84,7 +84,7 @@ public class AdminController extends BaseController {
84 adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings)); 84 adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings));
85 if (adminSettings.getKey().equals("mail")) { 85 if (adminSettings.getKey().equals("mail")) {
86 mailService.updateMailConfiguration(); 86 mailService.updateMailConfiguration();
87 - ((ObjectNode) adminSettings.getJsonValue()).put("password", ""); 87 + ((ObjectNode) adminSettings.getJsonValue()).remove("password");
88 } else if (adminSettings.getKey().equals("sms")) { 88 } else if (adminSettings.getKey().equals("sms")) {
89 smsService.updateSmsConfiguration(); 89 smsService.updateSmsConfiguration();
90 } 90 }
@@ -126,6 +126,10 @@ public class AdminController extends BaseController { @@ -126,6 +126,10 @@ public class AdminController extends BaseController {
126 accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ); 126 accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
127 adminSettings = checkNotNull(adminSettings); 127 adminSettings = checkNotNull(adminSettings);
128 if (adminSettings.getKey().equals("mail")) { 128 if (adminSettings.getKey().equals("mail")) {
  129 + if(!adminSettings.getJsonValue().has("password")) {
  130 + AdminSettings mailSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"));
  131 + ((ObjectNode) adminSettings.getJsonValue()).put("password", mailSettings.getJsonValue().get("password").asText());
  132 + }
129 String email = getCurrentUser().getEmail(); 133 String email = getCurrentUser().getEmail();
130 mailService.sendTestMail(adminSettings.getJsonValue(), email); 134 mailService.sendTestMail(adminSettings.getJsonValue(), email);
131 } 135 }
@@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.edge.EdgeEventActionType;
38 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; 38 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
39 import org.thingsboard.server.common.data.exception.ThingsboardException; 39 import org.thingsboard.server.common.data.exception.ThingsboardException;
40 import org.thingsboard.server.common.data.id.AlarmId; 40 import org.thingsboard.server.common.data.id.AlarmId;
  41 +import org.thingsboard.server.common.data.id.EdgeId;
41 import org.thingsboard.server.common.data.id.EntityId; 42 import org.thingsboard.server.common.data.id.EntityId;
42 import org.thingsboard.server.common.data.id.EntityIdFactory; 43 import org.thingsboard.server.common.data.id.EntityIdFactory;
43 import org.thingsboard.server.common.data.page.PageData; 44 import org.thingsboard.server.common.data.page.PageData;
@@ -46,6 +47,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @@ -46,6 +47,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
46 import org.thingsboard.server.service.security.permission.Operation; 47 import org.thingsboard.server.service.security.permission.Operation;
47 import org.thingsboard.server.service.security.permission.Resource; 48 import org.thingsboard.server.service.security.permission.Resource;
48 49
  50 +import java.util.List;
  51 +
49 @RestController 52 @RestController
50 @TbCoreComponent 53 @TbCoreComponent
51 @RequestMapping("/api") 54 @RequestMapping("/api")
@@ -112,10 +115,13 @@ public class AlarmController extends BaseController { @@ -112,10 +115,13 @@ public class AlarmController extends BaseController {
112 AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); 115 AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
113 Alarm alarm = checkAlarmId(alarmId, Operation.WRITE); 116 Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
114 117
  118 + List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(getTenantId(), alarm.getOriginator());
  119 +
115 logEntityAction(alarm.getOriginator(), alarm, 120 logEntityAction(alarm.getOriginator(), alarm,
116 getCurrentUser().getCustomerId(), 121 getCurrentUser().getCustomerId(),
117 ActionType.ALARM_DELETE, null); 122 ActionType.ALARM_DELETE, null);
118 - sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.DELETED); 123 +
  124 + sendAlarmDeleteNotificationMsg(getTenantId(), alarmId, relatedEdgeIds, alarm);
119 125
120 return alarmService.deleteAlarm(getTenantId(), alarmId); 126 return alarmService.deleteAlarm(getTenantId(), alarmId);
121 } catch (Exception e) { 127 } catch (Exception e) {
@@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.DashboardInfo; @@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.DashboardInfo;
33 import org.thingsboard.server.common.data.Device; 33 import org.thingsboard.server.common.data.Device;
34 import org.thingsboard.server.common.data.DeviceInfo; 34 import org.thingsboard.server.common.data.DeviceInfo;
35 import org.thingsboard.server.common.data.DeviceProfile; 35 import org.thingsboard.server.common.data.DeviceProfile;
36 -import org.thingsboard.server.common.data.EdgeUtils;  
37 import org.thingsboard.server.common.data.EntityType; 36 import org.thingsboard.server.common.data.EntityType;
38 import org.thingsboard.server.common.data.EntityView; 37 import org.thingsboard.server.common.data.EntityView;
39 import org.thingsboard.server.common.data.EntityViewInfo; 38 import org.thingsboard.server.common.data.EntityViewInfo;
@@ -118,7 +117,6 @@ import org.thingsboard.server.dao.user.UserService; @@ -118,7 +117,6 @@ import org.thingsboard.server.dao.user.UserService;
118 import org.thingsboard.server.dao.widget.WidgetTypeService; 117 import org.thingsboard.server.dao.widget.WidgetTypeService;
119 import org.thingsboard.server.dao.widget.WidgetsBundleService; 118 import org.thingsboard.server.dao.widget.WidgetsBundleService;
120 import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; 119 import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
121 -import org.thingsboard.server.gen.transport.TransportProtos;  
122 import org.thingsboard.server.queue.discovery.PartitionService; 120 import org.thingsboard.server.queue.discovery.PartitionService;
123 import org.thingsboard.server.queue.provider.TbQueueProducerProvider; 121 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
124 import org.thingsboard.server.queue.util.TbCoreComponent; 122 import org.thingsboard.server.queue.util.TbCoreComponent;
@@ -129,7 +127,7 @@ import org.thingsboard.server.service.edge.rpc.EdgeRpcService; @@ -129,7 +127,7 @@ import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
129 import org.thingsboard.server.service.lwm2m.LwM2MServerSecurityInfoRepository; 127 import org.thingsboard.server.service.lwm2m.LwM2MServerSecurityInfoRepository;
130 import org.thingsboard.server.service.ota.OtaPackageStateService; 128 import org.thingsboard.server.service.ota.OtaPackageStateService;
131 import org.thingsboard.server.service.profile.TbDeviceProfileCache; 129 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
132 -import org.thingsboard.server.service.queue.TbClusterService; 130 +import org.thingsboard.server.cluster.TbClusterService;
133 import org.thingsboard.server.service.resource.TbResourceService; 131 import org.thingsboard.server.service.resource.TbResourceService;
134 import org.thingsboard.server.service.security.model.SecurityUser; 132 import org.thingsboard.server.service.security.model.SecurityUser;
135 import org.thingsboard.server.service.security.permission.AccessControlService; 133 import org.thingsboard.server.service.security.permission.AccessControlService;
@@ -846,13 +844,25 @@ public abstract class BaseController { @@ -846,13 +844,25 @@ public abstract class BaseController {
846 } 844 }
847 845
848 protected void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds) { 846 protected void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds) {
  847 + sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null);
  848 + }
  849 +
  850 + protected void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, String body) {
849 if (edgeIds != null && !edgeIds.isEmpty()) { 851 if (edgeIds != null && !edgeIds.isEmpty()) {
850 for (EdgeId edgeId : edgeIds) { 852 for (EdgeId edgeId : edgeIds) {
851 - sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, null, EdgeEventActionType.DELETED); 853 + sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED);
852 } 854 }
853 } 855 }
854 } 856 }
855 857
  858 + protected void sendAlarmDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, Alarm alarm) {
  859 + try {
  860 + sendDeleteNotificationMsg(tenantId, entityId, edgeIds, json.writeValueAsString(alarm));
  861 + } catch (Exception e) {
  862 + log.warn("Failed to push delete alarm msg to core: {}", alarm, e);
  863 + }
  864 + }
  865 +
856 protected void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) { 866 protected void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) {
857 try { 867 try {
858 sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action); 868 sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action);
@@ -870,42 +880,7 @@ public abstract class BaseController { @@ -870,42 +880,7 @@ public abstract class BaseController {
870 } 880 }
871 881
872 private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) { 882 private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) {
873 - if (!edgesEnabled) {  
874 - return;  
875 - }  
876 - if (type == null) {  
877 - if (entityId != null) {  
878 - type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());  
879 - } else {  
880 - log.trace("[{}] entity id and type are null. Ignoring this notification", tenantId);  
881 - return;  
882 - }  
883 - if (type == null) {  
884 - log.trace("[{}] edge event type is null. Ignoring this notification [{}]", tenantId, entityId);  
885 - return;  
886 - }  
887 - }  
888 - TransportProtos.EdgeNotificationMsgProto.Builder builder = TransportProtos.EdgeNotificationMsgProto.newBuilder();  
889 - builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());  
890 - builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());  
891 - builder.setType(type.name());  
892 - builder.setAction(action.name());  
893 - if (entityId != null) {  
894 - builder.setEntityIdMSB(entityId.getId().getMostSignificantBits());  
895 - builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits());  
896 - builder.setEntityType(entityId.getEntityType().name());  
897 - }  
898 - if (edgeId != null) {  
899 - builder.setEdgeIdMSB(edgeId.getId().getMostSignificantBits());  
900 - builder.setEdgeIdLSB(edgeId.getId().getLeastSignificantBits());  
901 - }  
902 - if (body != null) {  
903 - builder.setBody(body);  
904 - }  
905 - TransportProtos.EdgeNotificationMsgProto msg = builder.build();  
906 - log.trace("[{}] sending notification to edge service {}", tenantId.getId(), msg);  
907 - tbClusterService.pushMsgToCore(tenantId, entityId != null ? entityId : tenantId,  
908 - TransportProtos.ToCoreMsg.newBuilder().setEdgeNotificationMsg(msg).build(), null); 883 + tbClusterService.sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, type, action);
909 } 884 }
910 885
911 protected List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) { 886 protected List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) {
@@ -149,7 +149,7 @@ public class CustomerController extends BaseController { @@ -149,7 +149,7 @@ public class CustomerController extends BaseController {
149 ActionType.DELETED, null, strCustomerId); 149 ActionType.DELETED, null, strCustomerId);
150 150
151 sendDeleteNotificationMsg(getTenantId(), customerId, relatedEdgeIds); 151 sendDeleteNotificationMsg(getTenantId(), customerId, relatedEdgeIds);
152 - tbClusterService.onEntityStateChange(getTenantId(), customerId, ComponentLifecycleEvent.DELETED); 152 + tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), customerId, ComponentLifecycleEvent.DELETED);
153 } catch (Exception e) { 153 } catch (Exception e) {
154 154
155 logEntityAction(emptyId(EntityType.CUSTOMER), 155 logEntityAction(emptyId(EntityType.CUSTOMER),
@@ -36,7 +36,6 @@ import org.springframework.web.bind.annotation.RestController; @@ -36,7 +36,6 @@ import org.springframework.web.bind.annotation.RestController;
36 import org.springframework.web.context.request.async.DeferredResult; 36 import org.springframework.web.context.request.async.DeferredResult;
37 import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; 37 import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
38 import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg; 38 import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg;
39 -import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;  
40 import org.thingsboard.server.common.data.ClaimRequest; 39 import org.thingsboard.server.common.data.ClaimRequest;
41 import org.thingsboard.server.common.data.Customer; 40 import org.thingsboard.server.common.data.Customer;
42 import org.thingsboard.server.common.data.DataConstants; 41 import org.thingsboard.server.common.data.DataConstants;
@@ -60,7 +59,6 @@ import org.thingsboard.server.common.data.ota.OtaPackageType; @@ -60,7 +59,6 @@ import org.thingsboard.server.common.data.ota.OtaPackageType;
60 import org.thingsboard.server.common.data.page.PageData; 59 import org.thingsboard.server.common.data.page.PageData;
61 import org.thingsboard.server.common.data.page.PageLink; 60 import org.thingsboard.server.common.data.page.PageLink;
62 import org.thingsboard.server.common.data.page.TimePageLink; 61 import org.thingsboard.server.common.data.page.TimePageLink;
63 -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;  
64 import org.thingsboard.server.common.data.security.DeviceCredentials; 62 import org.thingsboard.server.common.data.security.DeviceCredentials;
65 import org.thingsboard.server.common.msg.TbMsg; 63 import org.thingsboard.server.common.msg.TbMsg;
66 import org.thingsboard.server.common.msg.TbMsgDataType; 64 import org.thingsboard.server.common.msg.TbMsgDataType;
@@ -134,20 +132,16 @@ public class DeviceController extends BaseController { @@ -134,20 +132,16 @@ public class DeviceController extends BaseController {
134 try { 132 try {
135 device.setTenantId(getCurrentUser().getTenantId()); 133 device.setTenantId(getCurrentUser().getTenantId());
136 134
137 - checkEntity(device.getId(), device, Resource.DEVICE);  
138 -  
139 - Device oldDevice; 135 + Device oldDevice = null;
140 if (!created) { 136 if (!created) {
141 - oldDevice = deviceService.findDeviceById(getTenantId(), device.getId()); 137 + oldDevice = checkDeviceId(device.getId(), Operation.WRITE);
142 } else { 138 } else {
143 - oldDevice = null; 139 + checkEntity(null, device, Resource.DEVICE);
144 } 140 }
145 141
146 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); 142 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
147 143
148 - onDeviceCreatedOrUpdated(savedDevice, !created);  
149 -  
150 - otaPackageStateService.update(savedDevice, oldDevice); 144 + onDeviceCreatedOrUpdated(savedDevice, oldDevice, !created);
151 145
152 return savedDevice; 146 return savedDevice;
153 } catch (Exception e) { 147 } catch (Exception e) {
@@ -158,29 +152,16 @@ public class DeviceController extends BaseController { @@ -158,29 +152,16 @@ public class DeviceController extends BaseController {
158 152
159 } 153 }
160 154
161 - private void onDeviceCreatedOrUpdated(Device device, boolean updated) {  
162 - tbClusterService.onDeviceChange(device, null);  
163 - tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(device.getTenantId(),  
164 - device.getId(), device.getName(), device.getType()), null);  
165 - tbClusterService.onEntityStateChange(device.getTenantId(), device.getId(), updated ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED);  
166 -  
167 - if (updated) {  
168 - sendEntityNotificationMsg(device.getTenantId(), device.getId(), EdgeEventActionType.UPDATED);  
169 - } 155 + private void onDeviceCreatedOrUpdated(Device savedDevice, Device oldDevice, boolean updated) {
  156 + tbClusterService.onDeviceUpdated(savedDevice, oldDevice);
170 157
171 try { 158 try {
172 - logEntityAction(device.getId(), device,  
173 - device.getCustomerId(), 159 + logEntityAction(savedDevice.getId(), savedDevice,
  160 + savedDevice.getCustomerId(),
174 updated ? ActionType.UPDATED : ActionType.ADDED, null); 161 updated ? ActionType.UPDATED : ActionType.ADDED, null);
175 } catch (ThingsboardException e) { 162 } catch (ThingsboardException e) {
176 log.error("Failed to log entity action", e); 163 log.error("Failed to log entity action", e);
177 } 164 }
178 -  
179 - if (updated) {  
180 - deviceStateService.onDeviceUpdated(device);  
181 - } else {  
182 - deviceStateService.onDeviceAdded(device);  
183 - }  
184 } 165 }
185 166
186 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 167 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@@ -197,15 +178,12 @@ public class DeviceController extends BaseController { @@ -197,15 +178,12 @@ public class DeviceController extends BaseController {
197 deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId); 178 deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId);
198 179
199 tbClusterService.onDeviceDeleted(device, null); 180 tbClusterService.onDeviceDeleted(device, null);
200 - tbClusterService.onEntityStateChange(device.getTenantId(), deviceId, ComponentLifecycleEvent.DELETED);  
201 181
202 logEntityAction(deviceId, device, 182 logEntityAction(deviceId, device,
203 device.getCustomerId(), 183 device.getCustomerId(),
204 ActionType.DELETED, null, strDeviceId); 184 ActionType.DELETED, null, strDeviceId);
205 185
206 sendDeleteNotificationMsg(getTenantId(), deviceId, relatedEdgeIds); 186 sendDeleteNotificationMsg(getTenantId(), deviceId, relatedEdgeIds);
207 -  
208 - deviceStateService.onDeviceDeleted(device);  
209 } catch (Exception e) { 187 } catch (Exception e) {
210 logEntityAction(emptyId(EntityType.DEVICE), 188 logEntityAction(emptyId(EntityType.DEVICE),
211 null, 189 null,
@@ -819,8 +797,7 @@ public class DeviceController extends BaseController { @@ -819,8 +797,7 @@ public class DeviceController extends BaseController {
819 @PostMapping("/device/bulk_import") 797 @PostMapping("/device/bulk_import")
820 public BulkImportResult<Device> processDevicesBulkImport(@RequestBody BulkImportRequest request) throws Exception { 798 public BulkImportResult<Device> processDevicesBulkImport(@RequestBody BulkImportRequest request) throws Exception {
821 return deviceBulkImportService.processBulkImport(request, getCurrentUser(), importedDeviceInfo -> { 799 return deviceBulkImportService.processBulkImport(request, getCurrentUser(), importedDeviceInfo -> {
822 - onDeviceCreatedOrUpdated(importedDeviceInfo.getEntity(), importedDeviceInfo.isUpdated());  
823 - otaPackageStateService.update(importedDeviceInfo.getEntity(), importedDeviceInfo.getOldEntity()); 800 + onDeviceCreatedOrUpdated(importedDeviceInfo.getEntity(), importedDeviceInfo.getOldEntity(), importedDeviceInfo.isUpdated());
824 }); 801 });
825 } 802 }
826 803
@@ -161,7 +161,7 @@ public class DeviceProfileController extends BaseController { @@ -161,7 +161,7 @@ public class DeviceProfileController extends BaseController {
161 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); 161 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
162 162
163 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); 163 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
164 - tbClusterService.onEntityStateChange(deviceProfile.getTenantId(), savedDeviceProfile.getId(), 164 + tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), savedDeviceProfile.getId(),
165 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 165 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
166 166
167 logEntityAction(savedDeviceProfile.getId(), savedDeviceProfile, 167 logEntityAction(savedDeviceProfile.getId(), savedDeviceProfile,
@@ -191,7 +191,7 @@ public class DeviceProfileController extends BaseController { @@ -191,7 +191,7 @@ public class DeviceProfileController extends BaseController {
191 deviceProfileService.deleteDeviceProfile(getTenantId(), deviceProfileId); 191 deviceProfileService.deleteDeviceProfile(getTenantId(), deviceProfileId);
192 192
193 tbClusterService.onDeviceProfileDelete(deviceProfile, null); 193 tbClusterService.onDeviceProfileDelete(deviceProfile, null);
194 - tbClusterService.onEntityStateChange(deviceProfile.getTenantId(), deviceProfile.getId(), ComponentLifecycleEvent.DELETED); 194 + tbClusterService.broadcastEntityStateChangeEvent(deviceProfile.getTenantId(), deviceProfile.getId(), ComponentLifecycleEvent.DELETED);
195 195
196 logEntityAction(deviceProfileId, deviceProfile, 196 logEntityAction(deviceProfileId, deviceProfile,
197 null, 197 null,
@@ -153,7 +153,7 @@ public class EdgeController extends BaseController { @@ -153,7 +153,7 @@ public class EdgeController extends BaseController {
153 edgeService.assignDefaultRuleChainsToEdge(tenantId, edge.getId()); 153 edgeService.assignDefaultRuleChainsToEdge(tenantId, edge.getId());
154 } 154 }
155 155
156 - tbClusterService.onEntityStateChange(edge.getTenantId(), edge.getId(), 156 + tbClusterService.broadcastEntityStateChangeEvent(edge.getTenantId(), edge.getId(),
157 updated ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED); 157 updated ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED);
158 158
159 logEntityAction(edge.getId(), edge, null, updated ? ActionType.UPDATED : ActionType.ADDED, null); 159 logEntityAction(edge.getId(), edge, null, updated ? ActionType.UPDATED : ActionType.ADDED, null);
@@ -169,7 +169,7 @@ public class EdgeController extends BaseController { @@ -169,7 +169,7 @@ public class EdgeController extends BaseController {
169 Edge edge = checkEdgeId(edgeId, Operation.DELETE); 169 Edge edge = checkEdgeId(edgeId, Operation.DELETE);
170 edgeService.deleteEdge(getTenantId(), edgeId); 170 edgeService.deleteEdge(getTenantId(), edgeId);
171 171
172 - tbClusterService.onEntityStateChange(getTenantId(), edgeId, 172 + tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
173 ComponentLifecycleEvent.DELETED); 173 ComponentLifecycleEvent.DELETED);
174 174
175 logEntityAction(edgeId, edge, 175 logEntityAction(edgeId, edge,
@@ -220,7 +220,7 @@ public class EdgeController extends BaseController { @@ -220,7 +220,7 @@ public class EdgeController extends BaseController {
220 220
221 Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId)); 221 Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId));
222 222
223 - tbClusterService.onEntityStateChange(getTenantId(), edgeId, 223 + tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
224 ComponentLifecycleEvent.UPDATED); 224 ComponentLifecycleEvent.UPDATED);
225 225
226 logEntityAction(edgeId, savedEdge, 226 logEntityAction(edgeId, savedEdge,
@@ -254,7 +254,7 @@ public class EdgeController extends BaseController { @@ -254,7 +254,7 @@ public class EdgeController extends BaseController {
254 254
255 Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId)); 255 Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId));
256 256
257 - tbClusterService.onEntityStateChange(getTenantId(), edgeId, 257 + tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
258 ComponentLifecycleEvent.UPDATED); 258 ComponentLifecycleEvent.UPDATED);
259 259
260 logEntityAction(edgeId, edge, 260 logEntityAction(edgeId, edge,
@@ -284,7 +284,7 @@ public class EdgeController extends BaseController { @@ -284,7 +284,7 @@ public class EdgeController extends BaseController {
284 Customer publicCustomer = customerService.findOrCreatePublicCustomer(edge.getTenantId()); 284 Customer publicCustomer = customerService.findOrCreatePublicCustomer(edge.getTenantId());
285 Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, publicCustomer.getId())); 285 Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, publicCustomer.getId()));
286 286
287 - tbClusterService.onEntityStateChange(getTenantId(), edgeId, 287 + tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
288 ComponentLifecycleEvent.UPDATED); 288 ComponentLifecycleEvent.UPDATED);
289 289
290 logEntityAction(edgeId, savedEdge, 290 logEntityAction(edgeId, savedEdge,
@@ -376,7 +376,7 @@ public class EdgeController extends BaseController { @@ -376,7 +376,7 @@ public class EdgeController extends BaseController {
376 376
377 Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId); 377 Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId);
378 378
379 - tbClusterService.onEntityStateChange(updatedEdge.getTenantId(), updatedEdge.getId(), ComponentLifecycleEvent.UPDATED); 379 + tbClusterService.broadcastEntityStateChangeEvent(updatedEdge.getTenantId(), updatedEdge.getId(), ComponentLifecycleEvent.UPDATED);
380 380
381 logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null); 381 logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null);
382 382
@@ -24,13 +24,11 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -24,13 +24,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
24 import org.springframework.web.bind.annotation.RequestMethod; 24 import org.springframework.web.bind.annotation.RequestMethod;
25 import org.springframework.web.bind.annotation.ResponseBody; 25 import org.springframework.web.bind.annotation.ResponseBody;
26 import org.springframework.web.bind.annotation.RestController; 26 import org.springframework.web.bind.annotation.RestController;
27 -import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;  
28 import org.thingsboard.server.common.data.Device; 27 import org.thingsboard.server.common.data.Device;
29 import org.thingsboard.server.common.data.EntityType; 28 import org.thingsboard.server.common.data.EntityType;
30 import org.thingsboard.server.common.data.audit.ActionType; 29 import org.thingsboard.server.common.data.audit.ActionType;
31 import org.thingsboard.server.common.data.exception.ThingsboardException; 30 import org.thingsboard.server.common.data.exception.ThingsboardException;
32 import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; 31 import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig;
33 -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;  
34 import org.thingsboard.server.common.data.security.DeviceCredentials; 32 import org.thingsboard.server.common.data.security.DeviceCredentials;
35 import org.thingsboard.server.queue.util.TbCoreComponent; 33 import org.thingsboard.server.queue.util.TbCoreComponent;
36 import org.thingsboard.server.service.security.permission.Resource; 34 import org.thingsboard.server.service.security.permission.Resource;
@@ -66,22 +64,11 @@ public class Lwm2mController extends BaseController { @@ -66,22 +64,11 @@ public class Lwm2mController extends BaseController {
66 checkEntity(device.getId(), device, Resource.DEVICE); 64 checkEntity(device.getId(), device, Resource.DEVICE);
67 Device savedDevice = deviceService.saveDeviceWithCredentials(device, credentials); 65 Device savedDevice = deviceService.saveDeviceWithCredentials(device, credentials);
68 checkNotNull(savedDevice); 66 checkNotNull(savedDevice);
69 -  
70 - tbClusterService.onDeviceChange(savedDevice, null);  
71 - tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),  
72 - savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null);  
73 - tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(),  
74 - device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);  
75 - 67 + tbClusterService.onDeviceUpdated(savedDevice, device);
76 logEntityAction(savedDevice.getId(), savedDevice, 68 logEntityAction(savedDevice.getId(), savedDevice,
77 savedDevice.getCustomerId(), 69 savedDevice.getCustomerId(),
78 device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); 70 device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
79 71
80 - if (device.getId() == null) {  
81 - deviceStateService.onDeviceAdded(savedDevice);  
82 - } else {  
83 - deviceStateService.onDeviceUpdated(savedDevice);  
84 - }  
85 return savedDevice; 72 return savedDevice;
86 } catch (Exception e) { 73 } catch (Exception e) {
87 logEntityAction(emptyId(EntityType.DEVICE), device, 74 logEntityAction(emptyId(EntityType.DEVICE), device,
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.http.HttpStatus;
  20 +import org.springframework.http.ResponseEntity;
  21 +import org.springframework.security.access.prepost.PreAuthorize;
  22 +import org.springframework.web.bind.annotation.PathVariable;
  23 +import org.springframework.web.bind.annotation.RequestBody;
  24 +import org.springframework.web.bind.annotation.RequestMapping;
  25 +import org.springframework.web.bind.annotation.RequestMethod;
  26 +import org.springframework.web.bind.annotation.ResponseBody;
  27 +import org.springframework.web.bind.annotation.RestController;
  28 +import org.springframework.web.context.request.async.DeferredResult;
  29 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  30 +import org.thingsboard.server.common.data.id.DeviceId;
  31 +import org.thingsboard.server.queue.util.TbCoreComponent;
  32 +
  33 +import java.util.UUID;
  34 +
  35 +@RestController
  36 +@TbCoreComponent
  37 +@RequestMapping(TbUrlConstants.RPC_V1_URL_PREFIX)
  38 +@Slf4j
  39 +public class RpcV1Controller extends AbstractRpcController {
  40 +
  41 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
  42 + @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
  43 + @ResponseBody
  44 + public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException {
  45 + return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT);
  46 + }
  47 +
  48 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
  49 + @RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST)
  50 + @ResponseBody
  51 + public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException {
  52 + return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.REQUEST_TIMEOUT, HttpStatus.CONFLICT);
  53 + }
  54 +
  55 +}
application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java renamed from application/src/main/java/org/thingsboard/server/controller/RpcController.java
@@ -15,16 +15,10 @@ @@ -15,16 +15,10 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 -import com.fasterxml.jackson.databind.ObjectMapper;  
20 -import com.google.common.util.concurrent.FutureCallback;  
21 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
22 -import org.springframework.beans.factory.annotation.Autowired;  
23 -import org.springframework.beans.factory.annotation.Value;  
24 import org.springframework.http.HttpStatus; 19 import org.springframework.http.HttpStatus;
25 import org.springframework.http.ResponseEntity; 20 import org.springframework.http.ResponseEntity;
26 import org.springframework.security.access.prepost.PreAuthorize; 21 import org.springframework.security.access.prepost.PreAuthorize;
27 -import org.springframework.util.StringUtils;  
28 import org.springframework.web.bind.annotation.PathVariable; 22 import org.springframework.web.bind.annotation.PathVariable;
29 import org.springframework.web.bind.annotation.RequestBody; 23 import org.springframework.web.bind.annotation.RequestBody;
30 import org.springframework.web.bind.annotation.RequestMapping; 24 import org.springframework.web.bind.annotation.RequestMapping;
@@ -33,71 +27,43 @@ import org.springframework.web.bind.annotation.RequestParam; @@ -33,71 +27,43 @@ import org.springframework.web.bind.annotation.RequestParam;
33 import org.springframework.web.bind.annotation.ResponseBody; 27 import org.springframework.web.bind.annotation.ResponseBody;
34 import org.springframework.web.bind.annotation.RestController; 28 import org.springframework.web.bind.annotation.RestController;
35 import org.springframework.web.context.request.async.DeferredResult; 29 import org.springframework.web.context.request.async.DeferredResult;
36 -import org.thingsboard.rule.engine.api.RpcError;  
37 -import org.thingsboard.server.common.data.DataConstants;  
38 -import org.thingsboard.server.common.data.audit.ActionType;  
39 -import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; 30 +import org.thingsboard.common.util.JacksonUtil;
40 import org.thingsboard.server.common.data.exception.ThingsboardException; 31 import org.thingsboard.server.common.data.exception.ThingsboardException;
41 import org.thingsboard.server.common.data.id.DeviceId; 32 import org.thingsboard.server.common.data.id.DeviceId;
42 -import org.thingsboard.server.common.data.id.EntityId;  
43 import org.thingsboard.server.common.data.id.RpcId; 33 import org.thingsboard.server.common.data.id.RpcId;
44 import org.thingsboard.server.common.data.id.TenantId; 34 import org.thingsboard.server.common.data.id.TenantId;
45 -import org.thingsboard.server.common.data.id.UUIDBased;  
46 import org.thingsboard.server.common.data.page.PageData; 35 import org.thingsboard.server.common.data.page.PageData;
47 import org.thingsboard.server.common.data.page.PageLink; 36 import org.thingsboard.server.common.data.page.PageLink;
48 import org.thingsboard.server.common.data.rpc.Rpc; 37 import org.thingsboard.server.common.data.rpc.Rpc;
49 import org.thingsboard.server.common.data.rpc.RpcStatus; 38 import org.thingsboard.server.common.data.rpc.RpcStatus;
50 -import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;  
51 -import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 39 +import org.thingsboard.server.common.msg.TbMsg;
  40 +import org.thingsboard.server.common.msg.TbMsgMetaData;
52 import org.thingsboard.server.queue.util.TbCoreComponent; 41 import org.thingsboard.server.queue.util.TbCoreComponent;
53 -import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;  
54 -import org.thingsboard.server.service.rpc.LocalRequestMetaData;  
55 -import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;  
56 -import org.thingsboard.server.service.security.AccessValidator;  
57 -import org.thingsboard.server.service.security.model.SecurityUser; 42 +import org.thingsboard.server.service.rpc.RemoveRpcActorMsg;
58 import org.thingsboard.server.service.security.permission.Operation; 43 import org.thingsboard.server.service.security.permission.Operation;
59 -import org.thingsboard.server.service.telemetry.exception.ToErrorResponseEntity;  
60 44
61 -import javax.annotation.Nullable;  
62 -import java.io.IOException;  
63 -import java.util.Optional;  
64 import java.util.UUID; 45 import java.util.UUID;
65 46
66 -/**  
67 - * Created by ashvayka on 22.03.18.  
68 - */ 47 +import static org.thingsboard.server.common.data.DataConstants.RPC_DELETED;
  48 +
69 @RestController 49 @RestController
70 @TbCoreComponent 50 @TbCoreComponent
71 -@RequestMapping(TbUrlConstants.RPC_URL_PREFIX) 51 +@RequestMapping(TbUrlConstants.RPC_V2_URL_PREFIX)
72 @Slf4j 52 @Slf4j
73 -public class RpcController extends BaseController {  
74 -  
75 - protected final ObjectMapper jsonMapper = new ObjectMapper();  
76 -  
77 - @Autowired  
78 - private TbCoreDeviceRpcService deviceRpcService;  
79 -  
80 - @Autowired  
81 - private AccessValidator accessValidator;  
82 -  
83 - @Value("${server.rest.server_side_rpc.min_timeout:5000}")  
84 - private long minTimeout;  
85 -  
86 - @Value("${server.rest.server_side_rpc.default_timeout:10000}")  
87 - private long defaultTimeout; 53 +public class RpcV2Controller extends AbstractRpcController {
88 54
89 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 55 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
90 @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) 56 @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
91 @ResponseBody 57 @ResponseBody
92 public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { 58 public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException {
93 - return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody); 59 + return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
94 } 60 }
95 61
96 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 62 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
97 @RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST) 63 @RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST)
98 @ResponseBody 64 @ResponseBody
99 public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { 65 public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException {
100 - return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody); 66 + return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
101 } 67 }
102 68
103 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 69 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -140,118 +106,23 @@ public class RpcController extends BaseController { @@ -140,118 +106,23 @@ public class RpcController extends BaseController {
140 public void deleteResource(@PathVariable("rpcId") String strRpc) throws ThingsboardException { 106 public void deleteResource(@PathVariable("rpcId") String strRpc) throws ThingsboardException {
141 checkParameter("RpcId", strRpc); 107 checkParameter("RpcId", strRpc);
142 try { 108 try {
143 - rpcService.deleteRpc(getTenantId(), new RpcId(UUID.fromString(strRpc)));  
144 - } catch (Exception e) {  
145 - throw handleException(e);  
146 - }  
147 - } 109 + RpcId rpcId = new RpcId(UUID.fromString(strRpc));
  110 + Rpc rpc = checkRpcId(rpcId, Operation.DELETE);
148 111
149 - private DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody) throws ThingsboardException {  
150 - try {  
151 - JsonNode rpcRequestBody = jsonMapper.readTree(requestBody);  
152 - ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(rpcRequestBody.get("method").asText(), jsonMapper.writeValueAsString(rpcRequestBody.get("params")));  
153 - SecurityUser currentUser = getCurrentUser();  
154 - TenantId tenantId = currentUser.getTenantId();  
155 - final DeferredResult<ResponseEntity> response = new DeferredResult<>();  
156 - long timeout = rpcRequestBody.has("timeout") ? rpcRequestBody.get("timeout").asLong() : defaultTimeout;  
157 - long expTime = System.currentTimeMillis() + Math.max(minTimeout, timeout);  
158 - UUID rpcRequestUUID = rpcRequestBody.has("requestUUID") ? UUID.fromString(rpcRequestBody.get("requestUUID").asText()) : UUID.randomUUID();  
159 - boolean persisted = rpcRequestBody.has(DataConstants.PERSISTENT) && rpcRequestBody.get(DataConstants.PERSISTENT).asBoolean();  
160 - accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() {  
161 - @Override  
162 - public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {  
163 - ToDeviceRpcRequest rpcRequest = new ToDeviceRpcRequest(rpcRequestUUID,  
164 - tenantId,  
165 - deviceId,  
166 - oneWay,  
167 - expTime,  
168 - body,  
169 - persisted  
170 - );  
171 - deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse), currentUser); 112 + if (rpc != null) {
  113 + if (rpc.getStatus().equals(RpcStatus.QUEUED)) {
  114 + RemoveRpcActorMsg removeMsg = new RemoveRpcActorMsg(getTenantId(), rpc.getDeviceId(), rpc.getUuidId());
  115 + log.trace("[{}] Forwarding msg {} to queue actor!", rpc.getDeviceId(), rpc);
  116 + tbClusterService.pushMsgToCore(removeMsg, null);
172 } 117 }
173 118
174 - @Override  
175 - public void onFailure(Throwable e) {  
176 - ResponseEntity entity;  
177 - if (e instanceof ToErrorResponseEntity) {  
178 - entity = ((ToErrorResponseEntity) e).toErrorResponseEntity();  
179 - } else {  
180 - entity = new ResponseEntity(HttpStatus.UNAUTHORIZED);  
181 - }  
182 - logRpcCall(currentUser, deviceId, body, oneWay, Optional.empty(), e);  
183 - response.setResult(entity);  
184 - }  
185 - }));  
186 - return response;  
187 - } catch (IOException ioe) {  
188 - throw new ThingsboardException("Invalid request body", ioe, ThingsboardErrorCode.BAD_REQUEST_PARAMS);  
189 - }  
190 - } 119 + rpcService.deleteRpc(getTenantId(), rpcId);
191 120
192 - public void reply(LocalRequestMetaData rpcRequest, FromDeviceRpcResponse response) {  
193 - Optional<RpcError> rpcError = response.getError();  
194 - DeferredResult<ResponseEntity> responseWriter = rpcRequest.getResponseWriter();  
195 - if (rpcError.isPresent()) {  
196 - logRpcCall(rpcRequest, rpcError, null);  
197 - RpcError error = rpcError.get();  
198 - switch (error) {  
199 - case TIMEOUT:  
200 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));  
201 - break;  
202 - case NO_ACTIVE_CONNECTION:  
203 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.CONFLICT));  
204 - break;  
205 - default:  
206 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));  
207 - break;  
208 - }  
209 - } else {  
210 - Optional<String> responseData = response.getResponse();  
211 - if (responseData.isPresent() && !StringUtils.isEmpty(responseData.get())) {  
212 - String data = responseData.get();  
213 - try {  
214 - logRpcCall(rpcRequest, rpcError, null);  
215 - responseWriter.setResult(new ResponseEntity<>(jsonMapper.readTree(data), HttpStatus.OK));  
216 - } catch (IOException e) {  
217 - log.debug("Failed to decode device response: {}", data, e);  
218 - logRpcCall(rpcRequest, rpcError, e);  
219 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE));  
220 - }  
221 - } else {  
222 - logRpcCall(rpcRequest, rpcError, null);  
223 - responseWriter.setResult(new ResponseEntity<>(HttpStatus.OK)); 121 + TbMsg msg = TbMsg.newMsg(RPC_DELETED, rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc));
  122 + tbClusterService.pushMsgToRuleEngine(getTenantId(), rpc.getDeviceId(), msg, null);
224 } 123 }
  124 + } catch (Exception e) {
  125 + throw handleException(e);
225 } 126 }
226 } 127 }
227 -  
228 - private void logRpcCall(LocalRequestMetaData rpcRequest, Optional<RpcError> rpcError, Throwable e) {  
229 - logRpcCall(rpcRequest.getUser(), rpcRequest.getRequest().getDeviceId(), rpcRequest.getRequest().getBody(), rpcRequest.getRequest().isOneway(), rpcError, null);  
230 - }  
231 -  
232 -  
233 - private void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e) {  
234 - String rpcErrorStr = "";  
235 - if (rpcError.isPresent()) {  
236 - rpcErrorStr = "RPC Error: " + rpcError.get().name();  
237 - }  
238 - String method = body.getMethod();  
239 - String params = body.getParams();  
240 -  
241 - auditLogService.logEntityAction(  
242 - user.getTenantId(),  
243 - user.getCustomerId(),  
244 - user.getId(),  
245 - user.getName(),  
246 - (UUIDBased & EntityId) entityId,  
247 - null,  
248 - ActionType.RPC_CALL,  
249 - BaseController.toException(e),  
250 - rpcErrorStr,  
251 - oneWay,  
252 - method,  
253 - params);  
254 - }  
255 -  
256 -  
257 } 128 }
@@ -149,7 +149,7 @@ public class RuleChainController extends BaseController { @@ -149,7 +149,7 @@ public class RuleChainController extends BaseController {
149 RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); 149 RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain));
150 150
151 if (RuleChainType.CORE.equals(savedRuleChain.getType())) { 151 if (RuleChainType.CORE.equals(savedRuleChain.getType())) {
152 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(), 152 + tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), savedRuleChain.getId(),
153 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 153 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
154 } 154 }
155 155
@@ -183,7 +183,7 @@ public class RuleChainController extends BaseController { @@ -183,7 +183,7 @@ public class RuleChainController extends BaseController {
183 183
184 RuleChain savedRuleChain = installScripts.createDefaultRuleChain(getCurrentUser().getTenantId(), request.getName()); 184 RuleChain savedRuleChain = installScripts.createDefaultRuleChain(getCurrentUser().getTenantId(), request.getName());
185 185
186 - tbClusterService.onEntityStateChange(savedRuleChain.getTenantId(), savedRuleChain.getId(), ComponentLifecycleEvent.CREATED); 186 + tbClusterService.broadcastEntityStateChangeEvent(savedRuleChain.getTenantId(), savedRuleChain.getId(), ComponentLifecycleEvent.CREATED);
187 187
188 logEntityAction(savedRuleChain.getId(), savedRuleChain, null, ActionType.ADDED, null); 188 logEntityAction(savedRuleChain.getId(), savedRuleChain, null, ActionType.ADDED, null);
189 189
@@ -210,7 +210,7 @@ public class RuleChainController extends BaseController { @@ -210,7 +210,7 @@ public class RuleChainController extends BaseController {
210 if (previousRootRuleChain != null) { 210 if (previousRootRuleChain != null) {
211 previousRootRuleChain = ruleChainService.findRuleChainById(getTenantId(), previousRootRuleChain.getId()); 211 previousRootRuleChain = ruleChainService.findRuleChainById(getTenantId(), previousRootRuleChain.getId());
212 212
213 - tbClusterService.onEntityStateChange(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(), 213 + tbClusterService.broadcastEntityStateChangeEvent(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(),
214 ComponentLifecycleEvent.UPDATED); 214 ComponentLifecycleEvent.UPDATED);
215 215
216 logEntityAction(previousRootRuleChain.getId(), previousRootRuleChain, 216 logEntityAction(previousRootRuleChain.getId(), previousRootRuleChain,
@@ -218,7 +218,7 @@ public class RuleChainController extends BaseController { @@ -218,7 +218,7 @@ public class RuleChainController extends BaseController {
218 } 218 }
219 ruleChain = ruleChainService.findRuleChainById(getTenantId(), ruleChainId); 219 ruleChain = ruleChainService.findRuleChainById(getTenantId(), ruleChainId);
220 220
221 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), 221 + tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), ruleChain.getId(),
222 ComponentLifecycleEvent.UPDATED); 222 ComponentLifecycleEvent.UPDATED);
223 223
224 logEntityAction(ruleChain.getId(), ruleChain, 224 logEntityAction(ruleChain.getId(), ruleChain,
@@ -254,7 +254,7 @@ public class RuleChainController extends BaseController { @@ -254,7 +254,7 @@ public class RuleChainController extends BaseController {
254 RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId())); 254 RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId()));
255 255
256 if (RuleChainType.CORE.equals(ruleChain.getType())) { 256 if (RuleChainType.CORE.equals(ruleChain.getType())) {
257 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); 257 + tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
258 } 258 }
259 259
260 logEntityAction(ruleChain.getId(), ruleChain, 260 logEntityAction(ruleChain.getId(), ruleChain,
@@ -323,9 +323,9 @@ public class RuleChainController extends BaseController { @@ -323,9 +323,9 @@ public class RuleChainController extends BaseController {
323 323
324 if (RuleChainType.CORE.equals(ruleChain.getType())) { 324 if (RuleChainType.CORE.equals(ruleChain.getType())) {
325 referencingRuleChainIds.forEach(referencingRuleChainId -> 325 referencingRuleChainIds.forEach(referencingRuleChainId ->
326 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), referencingRuleChainId, ComponentLifecycleEvent.UPDATED)); 326 + tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), referencingRuleChainId, ComponentLifecycleEvent.UPDATED));
327 327
328 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED); 328 + tbClusterService.broadcastEntityStateChangeEvent(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED);
329 } 329 }
330 330
331 logEntityAction(ruleChainId, ruleChain, 331 logEntityAction(ruleChainId, ruleChain,
@@ -456,7 +456,7 @@ public class RuleChainController extends BaseController { @@ -456,7 +456,7 @@ public class RuleChainController extends BaseController {
456 List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite); 456 List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite);
457 if (!CollectionUtils.isEmpty(importResults)) { 457 if (!CollectionUtils.isEmpty(importResults)) {
458 for (RuleChainImportResult importResult : importResults) { 458 for (RuleChainImportResult importResult : importResults) {
459 - tbClusterService.onEntityStateChange(importResult.getTenantId(), importResult.getRuleChainId(), importResult.getLifecycleEvent()); 459 + tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(), importResult.getLifecycleEvent());
460 } 460 }
461 } 461 }
462 } catch (Exception e) { 462 } catch (Exception e) {
@@ -20,5 +20,6 @@ package org.thingsboard.server.controller; @@ -20,5 +20,6 @@ package org.thingsboard.server.controller;
20 */ 20 */
21 public class TbUrlConstants { 21 public class TbUrlConstants {
22 public static final String TELEMETRY_URL_PREFIX = "/api/plugins/telemetry"; 22 public static final String TELEMETRY_URL_PREFIX = "/api/plugins/telemetry";
23 - public static final String RPC_URL_PREFIX = "/api/plugins/rpc"; 23 + public static final String RPC_V1_URL_PREFIX = "/api/plugins/rpc";
  24 + public static final String RPC_V2_URL_PREFIX = "/api/rpc";
24 } 25 }
@@ -99,7 +99,7 @@ public class TenantController extends BaseController { @@ -99,7 +99,7 @@ public class TenantController extends BaseController {
99 } 99 }
100 tenantProfileCache.evict(tenant.getId()); 100 tenantProfileCache.evict(tenant.getId());
101 tbClusterService.onTenantChange(tenant, null); 101 tbClusterService.onTenantChange(tenant, null);
102 - tbClusterService.onEntityStateChange(tenant.getId(), tenant.getId(), 102 + tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(),
103 newTenant ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 103 newTenant ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
104 return tenant; 104 return tenant;
105 } catch (Exception e) { 105 } catch (Exception e) {
@@ -118,7 +118,7 @@ public class TenantController extends BaseController { @@ -118,7 +118,7 @@ public class TenantController extends BaseController {
118 tenantService.deleteTenant(tenantId); 118 tenantService.deleteTenant(tenantId);
119 tenantProfileCache.evict(tenantId); 119 tenantProfileCache.evict(tenantId);
120 tbClusterService.onTenantDelete(tenant, null); 120 tbClusterService.onTenantDelete(tenant, null);
121 - tbClusterService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED); 121 + tbClusterService.broadcastEntityStateChangeEvent(tenantId, tenantId, ComponentLifecycleEvent.DELETED);
122 } catch (Exception e) { 122 } catch (Exception e) {
123 throw handleException(e); 123 throw handleException(e);
124 } 124 }
@@ -34,7 +34,6 @@ import org.thingsboard.server.common.data.id.TenantProfileId; @@ -34,7 +34,6 @@ import org.thingsboard.server.common.data.id.TenantProfileId;
34 import org.thingsboard.server.common.data.page.PageData; 34 import org.thingsboard.server.common.data.page.PageData;
35 import org.thingsboard.server.common.data.page.PageLink; 35 import org.thingsboard.server.common.data.page.PageLink;
36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
37 -import org.thingsboard.server.dao.exception.DataValidationException;  
38 import org.thingsboard.server.queue.util.TbCoreComponent; 37 import org.thingsboard.server.queue.util.TbCoreComponent;
39 import org.thingsboard.server.service.security.permission.Operation; 38 import org.thingsboard.server.service.security.permission.Operation;
40 import org.thingsboard.server.service.security.permission.Resource; 39 import org.thingsboard.server.service.security.permission.Resource;
@@ -98,7 +97,7 @@ public class TenantProfileController extends BaseController { @@ -98,7 +97,7 @@ public class TenantProfileController extends BaseController {
98 tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile)); 97 tenantProfile = checkNotNull(tenantProfileService.saveTenantProfile(getTenantId(), tenantProfile));
99 tenantProfileCache.put(tenantProfile); 98 tenantProfileCache.put(tenantProfile);
100 tbClusterService.onTenantProfileChange(tenantProfile, null); 99 tbClusterService.onTenantProfileChange(tenantProfile, null);
101 - tbClusterService.onEntityStateChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(), 100 + tbClusterService.broadcastEntityStateChangeEvent(TenantId.SYS_TENANT_ID, tenantProfile.getId(),
102 newTenantProfile ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 101 newTenantProfile ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
103 return tenantProfile; 102 return tenantProfile;
104 } catch (Exception e) { 103 } catch (Exception e) {
@@ -41,7 +41,7 @@ import org.thingsboard.server.common.msg.TbMsgDataType; @@ -41,7 +41,7 @@ import org.thingsboard.server.common.msg.TbMsgDataType;
41 import org.thingsboard.server.common.msg.TbMsgMetaData; 41 import org.thingsboard.server.common.msg.TbMsgMetaData;
42 import org.thingsboard.server.dao.audit.AuditLogService; 42 import org.thingsboard.server.dao.audit.AuditLogService;
43 import org.thingsboard.server.queue.util.TbCoreComponent; 43 import org.thingsboard.server.queue.util.TbCoreComponent;
44 -import org.thingsboard.server.service.queue.TbClusterService; 44 +import org.thingsboard.server.cluster.TbClusterService;
45 45
46 import java.util.List; 46 import java.util.List;
47 import java.util.Map; 47 import java.util.Map;
@@ -61,7 +61,7 @@ import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; @@ -61,7 +61,7 @@ import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
61 import org.thingsboard.server.queue.discovery.PartitionService; 61 import org.thingsboard.server.queue.discovery.PartitionService;
62 import org.thingsboard.server.queue.discovery.TbApplicationEventListener; 62 import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
63 import org.thingsboard.server.queue.scheduler.SchedulerComponent; 63 import org.thingsboard.server.queue.scheduler.SchedulerComponent;
64 -import org.thingsboard.server.service.queue.TbClusterService; 64 +import org.thingsboard.server.cluster.TbClusterService;
65 import org.thingsboard.server.service.telemetry.InternalTelemetryService; 65 import org.thingsboard.server.service.telemetry.InternalTelemetryService;
66 66
67 import javax.annotation.PostConstruct; 67 import javax.annotation.PostConstruct;
@@ -29,6 +29,7 @@ import org.springframework.cache.CacheManager; @@ -29,6 +29,7 @@ import org.springframework.cache.CacheManager;
29 import org.springframework.stereotype.Service; 29 import org.springframework.stereotype.Service;
30 import org.springframework.util.StringUtils; 30 import org.springframework.util.StringUtils;
31 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; 31 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
  32 +import org.thingsboard.server.cluster.TbClusterService;
32 import org.thingsboard.server.common.data.Customer; 33 import org.thingsboard.server.common.data.Customer;
33 import org.thingsboard.server.common.data.DataConstants; 34 import org.thingsboard.server.common.data.DataConstants;
34 import org.thingsboard.server.common.data.Device; 35 import org.thingsboard.server.common.data.Device;
@@ -70,6 +71,8 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { @@ -70,6 +71,8 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
70 private static final ObjectMapper mapper = new ObjectMapper(); 71 private static final ObjectMapper mapper = new ObjectMapper();
71 72
72 @Autowired 73 @Autowired
  74 + private TbClusterService clusterService;
  75 + @Autowired
73 private DeviceService deviceService; 76 private DeviceService deviceService;
74 @Autowired 77 @Autowired
75 private AttributesService attributesService; 78 private AttributesService attributesService;
@@ -155,6 +158,7 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { @@ -155,6 +158,7 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
155 if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { 158 if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
156 device.setCustomerId(customerId); 159 device.setCustomerId(customerId);
157 Device savedDevice = deviceService.saveDevice(device); 160 Device savedDevice = deviceService.saveDevice(device);
  161 + clusterService.onDeviceUpdated(savedDevice, device);
158 return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS), MoreExecutors.directExecutor()); 162 return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS), MoreExecutors.directExecutor());
159 } 163 }
160 return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED), MoreExecutors.directExecutor()); 164 return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED), MoreExecutors.directExecutor());
@@ -179,13 +183,14 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { @@ -179,13 +183,14 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
179 cacheEviction(device.getId()); 183 cacheEviction(device.getId());
180 Customer unassignedCustomer = customerService.findCustomerById(tenantId, device.getCustomerId()); 184 Customer unassignedCustomer = customerService.findCustomerById(tenantId, device.getCustomerId());
181 device.setCustomerId(null); 185 device.setCustomerId(null);
182 - deviceService.saveDevice(device); 186 + Device savedDevice = deviceService.saveDevice(device);
  187 + clusterService.onDeviceUpdated(savedDevice, device);
183 if (isAllowedClaimingByDefault) { 188 if (isAllowedClaimingByDefault) {
184 return Futures.immediateFuture(new ReclaimResult(unassignedCustomer)); 189 return Futures.immediateFuture(new ReclaimResult(unassignedCustomer));
185 } 190 }
186 SettableFuture<ReclaimResult> result = SettableFuture.create(); 191 SettableFuture<ReclaimResult> result = SettableFuture.create();
187 telemetryService.saveAndNotify( 192 telemetryService.saveAndNotify(
188 - tenantId, device.getId(), DataConstants.SERVER_SCOPE, Collections.singletonList( 193 + tenantId, savedDevice.getId(), DataConstants.SERVER_SCOPE, Collections.singletonList(
189 new BaseAttributeKvEntry(new BooleanDataEntry(CLAIM_ATTRIBUTE_NAME, true), System.currentTimeMillis()) 194 new BaseAttributeKvEntry(new BooleanDataEntry(CLAIM_ATTRIBUTE_NAME, true), System.currentTimeMillis())
190 ), 195 ),
191 new FutureCallback<>() { 196 new FutureCallback<>() {
@@ -198,7 +203,7 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { @@ -198,7 +203,7 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
198 public void onFailure(Throwable t) { 203 public void onFailure(Throwable t) {
199 result.setException(t); 204 result.setException(t);
200 } 205 }
201 - }); 206 + });
202 return result; 207 return result;
203 } 208 }
204 cacheEviction(device.getId()); 209 cacheEviction(device.getId());
@@ -238,7 +243,7 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService { @@ -238,7 +243,7 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
238 public void onFailure(Throwable t) { 243 public void onFailure(Throwable t) {
239 result.setException(t); 244 result.setException(t);
240 } 245 }
241 - }); 246 + });
242 return result; 247 return result;
243 } 248 }
244 249
@@ -24,6 +24,7 @@ import org.apache.commons.lang3.RandomStringUtils; @@ -24,6 +24,7 @@ import org.apache.commons.lang3.RandomStringUtils;
24 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
26 import org.springframework.util.StringUtils; 26 import org.springframework.util.StringUtils;
  27 +import org.thingsboard.server.cluster.TbClusterService;
27 import org.thingsboard.server.common.data.DataConstants; 28 import org.thingsboard.server.common.data.DataConstants;
28 import org.thingsboard.server.common.data.Device; 29 import org.thingsboard.server.common.data.Device;
29 import org.thingsboard.server.common.data.DeviceProfile; 30 import org.thingsboard.server.common.data.DeviceProfile;
@@ -78,6 +79,9 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @@ -78,6 +79,9 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
78 private static final String PROVISIONED_STATE = "provisioned"; 79 private static final String PROVISIONED_STATE = "provisioned";
79 80
80 @Autowired 81 @Autowired
  82 + TbClusterService clusterService;
  83 +
  84 + @Autowired
81 DeviceDao deviceDao; 85 DeviceDao deviceDao;
82 86
83 @Autowired 87 @Autowired
@@ -190,8 +194,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @@ -190,8 +194,7 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
190 provisionRequest.setDeviceName(newDeviceName); 194 provisionRequest.setDeviceName(newDeviceName);
191 } 195 }
192 Device savedDevice = deviceService.saveDevice(provisionRequest, profile); 196 Device savedDevice = deviceService.saveDevice(provisionRequest, profile);
193 -  
194 - deviceStateService.onDeviceAdded(savedDevice); 197 + clusterService.onDeviceUpdated(savedDevice, null);
195 saveProvisionStateAttribute(savedDevice).get(); 198 saveProvisionStateAttribute(savedDevice).get();
196 pushDeviceCreatedEventToRuleEngine(savedDevice); 199 pushDeviceCreatedEventToRuleEngine(savedDevice);
197 notify(savedDevice, provisionRequest, DataConstants.PROVISION_SUCCESS, true); 200 notify(savedDevice, provisionRequest, DataConstants.PROVISION_SUCCESS, true);
@@ -16,11 +16,7 @@ @@ -16,11 +16,7 @@
16 package org.thingsboard.server.service.edge; 16 package org.thingsboard.server.service.edge;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 -import com.google.common.util.concurrent.FutureCallback;  
20 -import com.google.common.util.concurrent.Futures;  
21 -import com.google.common.util.concurrent.ListenableFuture;  
22 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
23 -import org.checkerframework.checker.nullness.qual.Nullable;  
24 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
26 import org.thingsboard.server.common.data.edge.Edge; 22 import org.thingsboard.server.common.data.edge.Edge;
@@ -41,8 +37,7 @@ import org.thingsboard.server.service.edge.rpc.processor.CustomerEdgeProcessor; @@ -41,8 +37,7 @@ import org.thingsboard.server.service.edge.rpc.processor.CustomerEdgeProcessor;
41 import org.thingsboard.server.service.edge.rpc.processor.EdgeProcessor; 37 import org.thingsboard.server.service.edge.rpc.processor.EdgeProcessor;
42 import org.thingsboard.server.service.edge.rpc.processor.EntityEdgeProcessor; 38 import org.thingsboard.server.service.edge.rpc.processor.EntityEdgeProcessor;
43 import org.thingsboard.server.service.edge.rpc.processor.RelationEdgeProcessor; 39 import org.thingsboard.server.service.edge.rpc.processor.RelationEdgeProcessor;
44 -import org.thingsboard.server.service.executors.DbCallbackExecutorService;  
45 -import org.thingsboard.server.service.queue.TbClusterService; 40 +import org.thingsboard.server.cluster.TbClusterService;
46 41
47 import javax.annotation.PostConstruct; 42 import javax.annotation.PostConstruct;
48 import javax.annotation.PreDestroy; 43 import javax.annotation.PreDestroy;
@@ -66,9 +61,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @@ -66,9 +61,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
66 private TbClusterService clusterService; 61 private TbClusterService clusterService;
67 62
68 @Autowired 63 @Autowired
69 - private DbCallbackExecutorService dbCallbackExecutorService;  
70 -  
71 - @Autowired  
72 private EdgeProcessor edgeProcessor; 64 private EdgeProcessor edgeProcessor;
73 65
74 @Autowired 66 @Autowired
@@ -123,23 +115,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @@ -123,23 +115,13 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
123 edgeEvent.setEntityId(entityId.getId()); 115 edgeEvent.setEntityId(entityId.getId());
124 } 116 }
125 edgeEvent.setBody(body); 117 edgeEvent.setBody(body);
126 - ListenableFuture<EdgeEvent> future = edgeEventService.saveAsync(edgeEvent);  
127 - Futures.addCallback(future, new FutureCallback<EdgeEvent>() {  
128 - @Override  
129 - public void onSuccess(@Nullable EdgeEvent result) {  
130 - clusterService.onEdgeEventUpdate(tenantId, edgeId);  
131 - }  
132 -  
133 - @Override  
134 - public void onFailure(Throwable t) {  
135 - log.warn("[{}] Can't save edge event [{}] for edge [{}]", tenantId.getId(), edgeEvent, edgeId.getId(), t);  
136 - }  
137 - }, dbCallbackExecutorService);  
138 - 118 + edgeEventService.save(edgeEvent);
  119 + clusterService.onEdgeEventUpdate(tenantId, edgeId);
139 } 120 }
140 121
141 @Override 122 @Override
142 public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { 123 public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) {
  124 + log.trace("Pushing notification to edge {}", edgeNotificationMsg);
143 try { 125 try {
144 TenantId tenantId = new TenantId(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); 126 TenantId tenantId = new TenantId(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB()));
145 EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); 127 EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
@@ -259,7 +259,7 @@ public final class EdgeGrpcSession implements Closeable { @@ -259,7 +259,7 @@ public final class EdgeGrpcSession implements Closeable {
259 log.error("[{}] Msg processing failed! Error msg: {}", edge.getRoutingKey(), msg.getErrorMsg()); 259 log.error("[{}] Msg processing failed! Error msg: {}", edge.getRoutingKey(), msg.getErrorMsg());
260 } 260 }
261 if (sessionState.getPendingMsgsMap().isEmpty()) { 261 if (sessionState.getPendingMsgsMap().isEmpty()) {
262 - log.debug("[{}] Pending msgs map is empty. Stopping current iteration {}", edge.getRoutingKey(), msg); 262 + log.debug("[{}] Pending msgs map is empty. Stopping current iteration", edge.getRoutingKey());
263 if (sessionState.getScheduledSendDownlinkTask() != null) { 263 if (sessionState.getScheduledSendDownlinkTask() != null) {
264 sessionState.getScheduledSendDownlinkTask().cancel(false); 264 sessionState.getScheduledSendDownlinkTask().cancel(false);
265 } 265 }
@@ -527,7 +527,7 @@ public final class EdgeGrpcSession implements Closeable { @@ -527,7 +527,7 @@ public final class EdgeGrpcSession implements Closeable {
527 case RULE_CHAIN_METADATA: 527 case RULE_CHAIN_METADATA:
528 return ctx.getRuleChainProcessor().processRuleChainMetadataToEdge(edgeEvent, msgType); 528 return ctx.getRuleChainProcessor().processRuleChainMetadataToEdge(edgeEvent, msgType);
529 case ALARM: 529 case ALARM:
530 - return ctx.getAlarmProcessor().processAlarmToEdge(edge, edgeEvent, msgType); 530 + return ctx.getAlarmProcessor().processAlarmToEdge(edge, edgeEvent, msgType, action);
531 case USER: 531 case USER:
532 return ctx.getUserProcessor().processUserToEdge(edge, edgeEvent, msgType, action); 532 return ctx.getUserProcessor().processUserToEdge(edge, edgeEvent, msgType, action);
533 case RELATION: 533 case RELATION:
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.edge.rpc;
  17 +
  18 +import com.google.protobuf.BoolValue;
  19 +import com.google.protobuf.ByteString;
  20 +import com.google.protobuf.BytesValue;
  21 +import com.google.protobuf.Int64Value;
  22 +import com.google.protobuf.StringValue;
  23 +
  24 +public class EdgeProtoUtils {
  25 +
  26 + private EdgeProtoUtils() {
  27 + }
  28 +
  29 + public static BoolValue getBoolValue(Boolean value) {
  30 + BoolValue.Builder builder = BoolValue.newBuilder();
  31 + builder.setValue(value);
  32 + return builder.build();
  33 + }
  34 +
  35 + public static StringValue getStringValue(String value) {
  36 + StringValue.Builder builder = StringValue.newBuilder();
  37 + builder.setValue(value);
  38 + return builder.build();
  39 + }
  40 +
  41 + public static Int64Value getInt64Value(Long value) {
  42 + Int64Value.Builder builder = Int64Value.newBuilder();
  43 + builder.setValue(value);
  44 + return builder.build();
  45 + }
  46 +
  47 + public static BytesValue getBytesValue(ByteString value) {
  48 + BytesValue.Builder builder = BytesValue.newBuilder();
  49 + builder.setValue(value);
  50 + return builder.build();
  51 + }
  52 +}
@@ -58,6 +58,8 @@ public class AlarmMsgConstructor { @@ -58,6 +58,8 @@ public class AlarmMsgConstructor {
58 } 58 }
59 AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder() 59 AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder()
60 .setMsgType(msgType) 60 .setMsgType(msgType)
  61 + .setIdMSB(alarm.getId().getId().getMostSignificantBits())
  62 + .setIdLSB(alarm.getId().getId().getLeastSignificantBits())
61 .setName(alarm.getName()) 63 .setName(alarm.getName())
62 .setType(alarm.getType()) 64 .setType(alarm.getType())
63 .setOriginatorName(entityName) 65 .setOriginatorName(entityName)
@@ -24,6 +24,9 @@ import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; @@ -24,6 +24,9 @@ import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg;
24 import org.thingsboard.server.gen.edge.v1.UpdateMsgType; 24 import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
25 import org.thingsboard.server.queue.util.TbCoreComponent; 25 import org.thingsboard.server.queue.util.TbCoreComponent;
26 26
  27 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getInt64Value;
  28 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  29 +
27 @Component 30 @Component
28 @TbCoreComponent 31 @TbCoreComponent
29 public class AssetMsgConstructor { 32 public class AssetMsgConstructor {
@@ -36,14 +39,14 @@ public class AssetMsgConstructor { @@ -36,14 +39,14 @@ public class AssetMsgConstructor {
36 .setName(asset.getName()) 39 .setName(asset.getName())
37 .setType(asset.getType()); 40 .setType(asset.getType());
38 if (asset.getLabel() != null) { 41 if (asset.getLabel() != null) {
39 - builder.setLabel(asset.getLabel()); 42 + builder.setLabel(getStringValue(asset.getLabel()));
40 } 43 }
41 if (customerId != null) { 44 if (customerId != null) {
42 - builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());  
43 - builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits()); 45 + builder.setCustomerIdMSB(getInt64Value(customerId.getId().getMostSignificantBits()));
  46 + builder.setCustomerIdLSB(getInt64Value(customerId.getId().getLeastSignificantBits()));
44 } 47 }
45 if (asset.getAdditionalInfo() != null) { 48 if (asset.getAdditionalInfo() != null) {
46 - builder.setAdditionalInfo(JacksonUtil.toString(asset.getAdditionalInfo())); 49 + builder.setAdditionalInfo(getStringValue(JacksonUtil.toString(asset.getAdditionalInfo())));
47 } 50 }
48 return builder.build(); 51 return builder.build();
49 } 52 }
@@ -23,6 +23,8 @@ import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg; @@ -23,6 +23,8 @@ import org.thingsboard.server.gen.edge.v1.CustomerUpdateMsg;
23 import org.thingsboard.server.gen.edge.v1.UpdateMsgType; 23 import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
24 import org.thingsboard.server.queue.util.TbCoreComponent; 24 import org.thingsboard.server.queue.util.TbCoreComponent;
25 25
  26 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  27 +
26 @Component 28 @Component
27 @TbCoreComponent 29 @TbCoreComponent
28 public class CustomerMsgConstructor { 30 public class CustomerMsgConstructor {
@@ -34,31 +36,31 @@ public class CustomerMsgConstructor { @@ -34,31 +36,31 @@ public class CustomerMsgConstructor {
34 .setIdLSB(customer.getId().getId().getLeastSignificantBits()) 36 .setIdLSB(customer.getId().getId().getLeastSignificantBits())
35 .setTitle(customer.getTitle()); 37 .setTitle(customer.getTitle());
36 if (customer.getCountry() != null) { 38 if (customer.getCountry() != null) {
37 - builder.setCountry(customer.getCountry()); 39 + builder.setCountry(getStringValue(customer.getCountry()));
38 } 40 }
39 if (customer.getState() != null) { 41 if (customer.getState() != null) {
40 - builder.setState(customer.getState()); 42 + builder.setState(getStringValue(customer.getState()));
41 } 43 }
42 if (customer.getCity() != null) { 44 if (customer.getCity() != null) {
43 - builder.setCity(customer.getCity()); 45 + builder.setCity(getStringValue(customer.getCity()));
44 } 46 }
45 if (customer.getAddress() != null) { 47 if (customer.getAddress() != null) {
46 - builder.setAddress(customer.getAddress()); 48 + builder.setAddress(getStringValue(customer.getAddress()));
47 } 49 }
48 if (customer.getAddress2() != null) { 50 if (customer.getAddress2() != null) {
49 - builder.setAddress2(customer.getAddress2()); 51 + builder.setAddress2(getStringValue(customer.getAddress2()));
50 } 52 }
51 if (customer.getZip() != null) { 53 if (customer.getZip() != null) {
52 - builder.setZip(customer.getZip()); 54 + builder.setZip(getStringValue(customer.getZip()));
53 } 55 }
54 if (customer.getPhone() != null) { 56 if (customer.getPhone() != null) {
55 - builder.setPhone(customer.getPhone()); 57 + builder.setPhone(getStringValue(customer.getPhone()));
56 } 58 }
57 if (customer.getEmail() != null) { 59 if (customer.getEmail() != null) {
58 - builder.setEmail(customer.getEmail()); 60 + builder.setEmail(getStringValue(customer.getEmail()));
59 } 61 }
60 if (customer.getAdditionalInfo() != null) { 62 if (customer.getAdditionalInfo() != null) {
61 - builder.setAdditionalInfo(JacksonUtil.toString(customer.getAdditionalInfo())); 63 + builder.setAdditionalInfo(getStringValue(JacksonUtil.toString(customer.getAdditionalInfo())));
62 } 64 }
63 return builder.build(); 65 return builder.build();
64 } 66 }
@@ -24,6 +24,8 @@ import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; @@ -24,6 +24,8 @@ import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg;
24 import org.thingsboard.server.gen.edge.v1.UpdateMsgType; 24 import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
25 import org.thingsboard.server.queue.util.TbCoreComponent; 25 import org.thingsboard.server.queue.util.TbCoreComponent;
26 26
  27 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getInt64Value;
  28 +
27 @Component 29 @Component
28 @TbCoreComponent 30 @TbCoreComponent
29 public class DashboardMsgConstructor { 31 public class DashboardMsgConstructor {
@@ -36,8 +38,8 @@ public class DashboardMsgConstructor { @@ -36,8 +38,8 @@ public class DashboardMsgConstructor {
36 .setTitle(dashboard.getTitle()) 38 .setTitle(dashboard.getTitle())
37 .setConfiguration(JacksonUtil.toString(dashboard.getConfiguration())); 39 .setConfiguration(JacksonUtil.toString(dashboard.getConfiguration()));
38 if (customerId != null) { 40 if (customerId != null) {
39 - builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());  
40 - builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits()); 41 + builder.setCustomerIdMSB(getInt64Value(customerId.getId().getMostSignificantBits()));
  42 + builder.setCustomerIdLSB(getInt64Value(customerId.getId().getLeastSignificantBits()));
41 } 43 }
42 return builder.build(); 44 return builder.build();
43 } 45 }
@@ -32,6 +32,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @@ -32,6 +32,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
32 32
33 import java.util.UUID; 33 import java.util.UUID;
34 34
  35 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getInt64Value;
  36 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  37 +
35 @Component 38 @Component
36 @TbCoreComponent 39 @TbCoreComponent
37 public class DeviceMsgConstructor { 40 public class DeviceMsgConstructor {
@@ -46,21 +49,21 @@ public class DeviceMsgConstructor { @@ -46,21 +49,21 @@ public class DeviceMsgConstructor {
46 .setName(device.getName()) 49 .setName(device.getName())
47 .setType(device.getType()); 50 .setType(device.getType());
48 if (device.getLabel() != null) { 51 if (device.getLabel() != null) {
49 - builder.setLabel(device.getLabel()); 52 + builder.setLabel(getStringValue(device.getLabel()));
50 } 53 }
51 if (customerId != null) { 54 if (customerId != null) {
52 - builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());  
53 - builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits()); 55 + builder.setCustomerIdMSB(getInt64Value(customerId.getId().getMostSignificantBits()));
  56 + builder.setCustomerIdLSB(getInt64Value(customerId.getId().getLeastSignificantBits()));
54 } 57 }
55 if (device.getDeviceProfileId() != null) { 58 if (device.getDeviceProfileId() != null) {
56 - builder.setDeviceProfileIdMSB(device.getDeviceProfileId().getId().getMostSignificantBits());  
57 - builder.setDeviceProfileIdLSB(device.getDeviceProfileId().getId().getLeastSignificantBits()); 59 + builder.setDeviceProfileIdMSB(getInt64Value(device.getDeviceProfileId().getId().getMostSignificantBits()));
  60 + builder.setDeviceProfileIdLSB(getInt64Value(device.getDeviceProfileId().getId().getLeastSignificantBits()));
58 } 61 }
59 if (device.getAdditionalInfo() != null) { 62 if (device.getAdditionalInfo() != null) {
60 - builder.setAdditionalInfo(JacksonUtil.toString(device.getAdditionalInfo())); 63 + builder.setAdditionalInfo(getStringValue(JacksonUtil.toString(device.getAdditionalInfo())));
61 } 64 }
62 if (conflictName != null) { 65 if (conflictName != null) {
63 - builder.setConflictName(conflictName); 66 + builder.setConflictName(getStringValue(conflictName));
64 } 67 }
65 return builder.build(); 68 return builder.build();
66 } 69 }
@@ -74,7 +77,7 @@ public class DeviceMsgConstructor { @@ -74,7 +77,7 @@ public class DeviceMsgConstructor {
74 .setCredentialsId(deviceCredentials.getCredentialsId()); 77 .setCredentialsId(deviceCredentials.getCredentialsId());
75 } 78 }
76 if (deviceCredentials.getCredentialsValue() != null) { 79 if (deviceCredentials.getCredentialsValue() != null) {
77 - builder.setCredentialsValue(deviceCredentials.getCredentialsValue()); 80 + builder.setCredentialsValue(getStringValue(deviceCredentials.getCredentialsValue()));
78 } 81 }
79 return builder.build(); 82 return builder.build();
80 } 83 }
@@ -27,6 +27,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @@ -27,6 +27,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
27 27
28 import java.nio.charset.StandardCharsets; 28 import java.nio.charset.StandardCharsets;
29 29
  30 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getBytesValue;
  31 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  32 +
30 @Component 33 @Component
31 @TbCoreComponent 34 @TbCoreComponent
32 public class DeviceProfileMsgConstructor { 35 public class DeviceProfileMsgConstructor {
@@ -52,19 +55,19 @@ public class DeviceProfileMsgConstructor { @@ -52,19 +55,19 @@ public class DeviceProfileMsgConstructor {
52 // builder.setDefaultQueueName(deviceProfile.getDefaultQueueName()); 55 // builder.setDefaultQueueName(deviceProfile.getDefaultQueueName());
53 // } 56 // }
54 if (deviceProfile.getDescription() != null) { 57 if (deviceProfile.getDescription() != null) {
55 - builder.setDescription(deviceProfile.getDescription()); 58 + builder.setDescription(getStringValue(deviceProfile.getDescription()));
56 } 59 }
57 if (deviceProfile.getTransportType() != null) { 60 if (deviceProfile.getTransportType() != null) {
58 - builder.setTransportType(deviceProfile.getTransportType().name()); 61 + builder.setTransportType(getStringValue(deviceProfile.getTransportType().name()));
59 } 62 }
60 if (deviceProfile.getProvisionType() != null) { 63 if (deviceProfile.getProvisionType() != null) {
61 - builder.setProvisionType(deviceProfile.getProvisionType().name()); 64 + builder.setProvisionType(getStringValue(deviceProfile.getProvisionType().name()));
62 } 65 }
63 if (deviceProfile.getProvisionDeviceKey() != null) { 66 if (deviceProfile.getProvisionDeviceKey() != null) {
64 - builder.setProvisionDeviceKey(deviceProfile.getProvisionDeviceKey()); 67 + builder.setProvisionDeviceKey(getStringValue(deviceProfile.getProvisionDeviceKey()));
65 } 68 }
66 if (deviceProfile.getImage() != null) { 69 if (deviceProfile.getImage() != null) {
67 - builder.setImage(ByteString.copyFrom(deviceProfile.getImage().getBytes(StandardCharsets.UTF_8))); 70 + builder.setImage(getBytesValue(ByteString.copyFrom(deviceProfile.getImage().getBytes(StandardCharsets.UTF_8))));
68 } 71 }
69 return builder.build(); 72 return builder.build();
70 } 73 }
@@ -25,6 +25,9 @@ import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg; @@ -25,6 +25,9 @@ import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg;
25 import org.thingsboard.server.gen.edge.v1.UpdateMsgType; 25 import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
26 import org.thingsboard.server.queue.util.TbCoreComponent; 26 import org.thingsboard.server.queue.util.TbCoreComponent;
27 27
  28 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getInt64Value;
  29 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  30 +
28 @Component 31 @Component
29 @TbCoreComponent 32 @TbCoreComponent
30 public class EntityViewMsgConstructor { 33 public class EntityViewMsgConstructor {
@@ -51,11 +54,11 @@ public class EntityViewMsgConstructor { @@ -51,11 +54,11 @@ public class EntityViewMsgConstructor {
51 .setEntityIdLSB(entityView.getEntityId().getId().getLeastSignificantBits()) 54 .setEntityIdLSB(entityView.getEntityId().getId().getLeastSignificantBits())
52 .setEntityType(entityType); 55 .setEntityType(entityType);
53 if (customerId != null) { 56 if (customerId != null) {
54 - builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());  
55 - builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits()); 57 + builder.setCustomerIdMSB(getInt64Value(customerId.getId().getMostSignificantBits()));
  58 + builder.setCustomerIdLSB(getInt64Value(customerId.getId().getLeastSignificantBits()));
56 } 59 }
57 if (entityView.getAdditionalInfo() != null) { 60 if (entityView.getAdditionalInfo() != null) {
58 - builder.setAdditionalInfo(JacksonUtil.toString(entityView.getAdditionalInfo())); 61 + builder.setAdditionalInfo(getStringValue(JacksonUtil.toString(entityView.getAdditionalInfo())));
59 } 62 }
60 return builder.build(); 63 return builder.build();
61 } 64 }
@@ -22,6 +22,8 @@ import org.thingsboard.server.gen.edge.v1.RelationUpdateMsg; @@ -22,6 +22,8 @@ import org.thingsboard.server.gen.edge.v1.RelationUpdateMsg;
22 import org.thingsboard.server.gen.edge.v1.UpdateMsgType; 22 import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
23 import org.thingsboard.server.queue.util.TbCoreComponent; 23 import org.thingsboard.server.queue.util.TbCoreComponent;
24 24
  25 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  26 +
25 @Component 27 @Component
26 @TbCoreComponent 28 @TbCoreComponent
27 public class RelationMsgConstructor { 29 public class RelationMsgConstructor {
@@ -35,10 +37,12 @@ public class RelationMsgConstructor { @@ -35,10 +37,12 @@ public class RelationMsgConstructor {
35 .setToIdMSB(entityRelation.getTo().getId().getMostSignificantBits()) 37 .setToIdMSB(entityRelation.getTo().getId().getMostSignificantBits())
36 .setToIdLSB(entityRelation.getTo().getId().getLeastSignificantBits()) 38 .setToIdLSB(entityRelation.getTo().getId().getLeastSignificantBits())
37 .setToEntityType(entityRelation.getTo().getEntityType().name()) 39 .setToEntityType(entityRelation.getTo().getEntityType().name())
38 - .setType(entityRelation.getType())  
39 - .setAdditionalInfo(JacksonUtil.toString(entityRelation.getAdditionalInfo())); 40 + .setType(entityRelation.getType());
  41 + if (entityRelation.getAdditionalInfo() != null) {
  42 + builder.setAdditionalInfo(JacksonUtil.toString(entityRelation.getAdditionalInfo()));
  43 + }
40 if (entityRelation.getTypeGroup() != null) { 44 if (entityRelation.getTypeGroup() != null) {
41 - builder.setTypeGroup(entityRelation.getTypeGroup().name()); 45 + builder.setTypeGroup(getStringValue(entityRelation.getTypeGroup().name()));
42 } 46 }
43 return builder.build(); 47 return builder.build();
44 } 48 }
@@ -37,6 +37,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @@ -37,6 +37,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
37 import java.util.ArrayList; 37 import java.util.ArrayList;
38 import java.util.List; 38 import java.util.List;
39 39
  40 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getInt64Value;
  41 +
40 @Component 42 @Component
41 @Slf4j 43 @Slf4j
42 @TbCoreComponent 44 @TbCoreComponent
@@ -54,8 +56,8 @@ public class RuleChainMsgConstructor { @@ -54,8 +56,8 @@ public class RuleChainMsgConstructor {
54 .setDebugMode(ruleChain.isDebugMode()) 56 .setDebugMode(ruleChain.isDebugMode())
55 .setConfiguration(JacksonUtil.toString(ruleChain.getConfiguration())); 57 .setConfiguration(JacksonUtil.toString(ruleChain.getConfiguration()));
56 if (ruleChain.getFirstRuleNodeId() != null) { 58 if (ruleChain.getFirstRuleNodeId() != null) {
57 - builder.setFirstRuleNodeIdMSB(ruleChain.getFirstRuleNodeId().getId().getMostSignificantBits())  
58 - .setFirstRuleNodeIdLSB(ruleChain.getFirstRuleNodeId().getId().getLeastSignificantBits()); 59 + builder.setFirstRuleNodeIdMSB(getInt64Value(ruleChain.getFirstRuleNodeId().getId().getMostSignificantBits()))
  60 + .setFirstRuleNodeIdLSB(getInt64Value(ruleChain.getFirstRuleNodeId().getId().getLeastSignificantBits()));
59 } 61 }
60 return builder.build(); 62 return builder.build();
61 } 63 }
@@ -16,16 +16,19 @@ @@ -16,16 +16,19 @@
16 package org.thingsboard.server.service.edge.rpc.constructor; 16 package org.thingsboard.server.service.edge.rpc.constructor;
17 17
18 import org.springframework.stereotype.Component; 18 import org.springframework.stereotype.Component;
  19 +import org.thingsboard.common.util.JacksonUtil;
19 import org.thingsboard.server.common.data.User; 20 import org.thingsboard.server.common.data.User;
20 import org.thingsboard.server.common.data.id.CustomerId; 21 import org.thingsboard.server.common.data.id.CustomerId;
21 import org.thingsboard.server.common.data.id.UserId; 22 import org.thingsboard.server.common.data.id.UserId;
22 import org.thingsboard.server.common.data.security.UserCredentials; 23 import org.thingsboard.server.common.data.security.UserCredentials;
23 -import org.thingsboard.common.util.JacksonUtil;  
24 import org.thingsboard.server.gen.edge.v1.UpdateMsgType; 24 import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
25 import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg; 25 import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg;
26 import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; 26 import org.thingsboard.server.gen.edge.v1.UserUpdateMsg;
27 import org.thingsboard.server.queue.util.TbCoreComponent; 27 import org.thingsboard.server.queue.util.TbCoreComponent;
28 28
  29 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getInt64Value;
  30 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  31 +
29 @Component 32 @Component
30 @TbCoreComponent 33 @TbCoreComponent
31 public class UserMsgConstructor { 34 public class UserMsgConstructor {
@@ -38,20 +41,17 @@ public class UserMsgConstructor { @@ -38,20 +41,17 @@ public class UserMsgConstructor {
38 .setEmail(user.getEmail()) 41 .setEmail(user.getEmail())
39 .setAuthority(user.getAuthority().name()); 42 .setAuthority(user.getAuthority().name());
40 if (customerId != null) { 43 if (customerId != null) {
41 - builder.setCustomerIdMSB(customerId.getId().getMostSignificantBits());  
42 - builder.setCustomerIdLSB(customerId.getId().getLeastSignificantBits()); 44 + builder.setCustomerIdMSB(getInt64Value(customerId.getId().getMostSignificantBits()));
  45 + builder.setCustomerIdLSB(getInt64Value(customerId.getId().getLeastSignificantBits()));
43 } 46 }
44 if (user.getFirstName() != null) { 47 if (user.getFirstName() != null) {
45 - builder.setFirstName(user.getFirstName()); 48 + builder.setFirstName(getStringValue(user.getFirstName()));
46 } 49 }
47 if (user.getLastName() != null) { 50 if (user.getLastName() != null) {
48 - builder.setLastName(user.getLastName());  
49 - }  
50 - if (user.getAdditionalInfo() != null) {  
51 - builder.setAdditionalInfo(JacksonUtil.toString(user.getAdditionalInfo())); 51 + builder.setLastName(getStringValue(user.getLastName()));
52 } 52 }
53 if (user.getAdditionalInfo() != null) { 53 if (user.getAdditionalInfo() != null) {
54 - builder.setAdditionalInfo(JacksonUtil.toString(user.getAdditionalInfo())); 54 + builder.setAdditionalInfo(getStringValue(JacksonUtil.toString(user.getAdditionalInfo())));
55 } 55 }
56 return builder.build(); 56 return builder.build();
57 } 57 }
@@ -16,14 +16,16 @@ @@ -16,14 +16,16 @@
16 package org.thingsboard.server.service.edge.rpc.constructor; 16 package org.thingsboard.server.service.edge.rpc.constructor;
17 17
18 import org.springframework.stereotype.Component; 18 import org.springframework.stereotype.Component;
  19 +import org.thingsboard.common.util.JacksonUtil;
19 import org.thingsboard.server.common.data.id.TenantId; 20 import org.thingsboard.server.common.data.id.TenantId;
20 import org.thingsboard.server.common.data.id.WidgetTypeId; 21 import org.thingsboard.server.common.data.id.WidgetTypeId;
21 import org.thingsboard.server.common.data.widget.WidgetType; 22 import org.thingsboard.server.common.data.widget.WidgetType;
22 -import org.thingsboard.common.util.JacksonUtil;  
23 import org.thingsboard.server.gen.edge.v1.UpdateMsgType; 23 import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
24 import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; 24 import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg;
25 import org.thingsboard.server.queue.util.TbCoreComponent; 25 import org.thingsboard.server.queue.util.TbCoreComponent;
26 26
  27 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  28 +
27 @Component 29 @Component
28 @TbCoreComponent 30 @TbCoreComponent
29 public class WidgetTypeMsgConstructor { 31 public class WidgetTypeMsgConstructor {
@@ -33,21 +35,21 @@ public class WidgetTypeMsgConstructor { @@ -33,21 +35,21 @@ public class WidgetTypeMsgConstructor {
33 .setMsgType(msgType) 35 .setMsgType(msgType)
34 .setIdMSB(widgetType.getId().getId().getMostSignificantBits()) 36 .setIdMSB(widgetType.getId().getId().getMostSignificantBits())
35 .setIdLSB(widgetType.getId().getId().getLeastSignificantBits()); 37 .setIdLSB(widgetType.getId().getId().getLeastSignificantBits());
36 - if (widgetType.getBundleAlias() != null) {  
37 - builder.setBundleAlias(widgetType.getBundleAlias());  
38 - }  
39 - if (widgetType.getAlias() != null) {  
40 - builder.setAlias(widgetType.getAlias());  
41 - }  
42 - if (widgetType.getName() != null) {  
43 - builder.setName(widgetType.getName());  
44 - }  
45 - if (widgetType.getDescriptor() != null) {  
46 - builder.setDescriptorJson(JacksonUtil.toString(widgetType.getDescriptor()));  
47 - }  
48 - if (widgetType.getTenantId().equals(TenantId.SYS_TENANT_ID)) {  
49 - builder.setIsSystem(true);  
50 - } 38 + if (widgetType.getBundleAlias() != null) {
  39 + builder.setBundleAlias(getStringValue(widgetType.getBundleAlias()));
  40 + }
  41 + if (widgetType.getAlias() != null) {
  42 + builder.setAlias(getStringValue(widgetType.getAlias()));
  43 + }
  44 + if (widgetType.getName() != null) {
  45 + builder.setName(getStringValue(widgetType.getName()));
  46 + }
  47 + if (widgetType.getDescriptor() != null) {
  48 + builder.setDescriptorJson(getStringValue(JacksonUtil.toString(widgetType.getDescriptor())));
  49 + }
  50 + if (widgetType.getTenantId().equals(TenantId.SYS_TENANT_ID)) {
  51 + builder.setIsSystem(true);
  52 + }
51 return builder.build(); 53 return builder.build();
52 } 54 }
53 55
@@ -26,6 +26,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @@ -26,6 +26,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
26 26
27 import java.nio.charset.StandardCharsets; 27 import java.nio.charset.StandardCharsets;
28 28
  29 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getBytesValue;
  30 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
  31 +
29 @Component 32 @Component
30 @TbCoreComponent 33 @TbCoreComponent
31 public class WidgetsBundleMsgConstructor { 34 public class WidgetsBundleMsgConstructor {
@@ -38,10 +41,10 @@ public class WidgetsBundleMsgConstructor { @@ -38,10 +41,10 @@ public class WidgetsBundleMsgConstructor {
38 .setTitle(widgetsBundle.getTitle()) 41 .setTitle(widgetsBundle.getTitle())
39 .setAlias(widgetsBundle.getAlias()); 42 .setAlias(widgetsBundle.getAlias());
40 if (widgetsBundle.getImage() != null) { 43 if (widgetsBundle.getImage() != null) {
41 - builder.setImage(ByteString.copyFrom(widgetsBundle.getImage().getBytes(StandardCharsets.UTF_8))); 44 + builder.setImage(getBytesValue(ByteString.copyFrom(widgetsBundle.getImage().getBytes(StandardCharsets.UTF_8))));
42 } 45 }
43 if (widgetsBundle.getDescription() != null) { 46 if (widgetsBundle.getDescription() != null) {
44 - builder.setDescription(widgetsBundle.getDescription()); 47 + builder.setDescription(getStringValue(widgetsBundle.getDescription()));
45 } 48 }
46 if (widgetsBundle.getTenantId().equals(TenantId.SYS_TENANT_ID)) { 49 if (widgetsBundle.getTenantId().equals(TenantId.SYS_TENANT_ID)) {
47 builder.setIsSystem(true); 50 builder.setIsSystem(true);
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.service.edge.rpc.processor; 16 package org.thingsboard.server.service.edge.rpc.processor;
17 17
  18 +import com.fasterxml.jackson.core.JsonProcessingException;
18 import com.google.common.util.concurrent.FutureCallback; 19 import com.google.common.util.concurrent.FutureCallback;
19 import com.google.common.util.concurrent.Futures; 20 import com.google.common.util.concurrent.Futures;
20 import com.google.common.util.concurrent.ListenableFuture; 21 import com.google.common.util.concurrent.ListenableFuture;
@@ -54,6 +55,7 @@ public class AlarmEdgeProcessor extends BaseEdgeProcessor { @@ -54,6 +55,7 @@ public class AlarmEdgeProcessor extends BaseEdgeProcessor {
54 EntityId originatorId = getAlarmOriginator(tenantId, alarmUpdateMsg.getOriginatorName(), 55 EntityId originatorId = getAlarmOriginator(tenantId, alarmUpdateMsg.getOriginatorName(),
55 EntityType.valueOf(alarmUpdateMsg.getOriginatorType())); 56 EntityType.valueOf(alarmUpdateMsg.getOriginatorType()));
56 if (originatorId == null) { 57 if (originatorId == null) {
  58 + log.warn("Originator not found for the alarm msg {}", alarmUpdateMsg);
57 return Futures.immediateFuture(null); 59 return Futures.immediateFuture(null);
58 } 60 }
59 try { 61 try {
@@ -113,59 +115,84 @@ public class AlarmEdgeProcessor extends BaseEdgeProcessor { @@ -113,59 +115,84 @@ public class AlarmEdgeProcessor extends BaseEdgeProcessor {
113 } 115 }
114 } 116 }
115 117
116 - public DownlinkMsg processAlarmToEdge(Edge edge, EdgeEvent edgeEvent, UpdateMsgType msgType) { 118 + public DownlinkMsg processAlarmToEdge(Edge edge, EdgeEvent edgeEvent, UpdateMsgType msgType, EdgeEventActionType action) {
  119 + AlarmId alarmId = new AlarmId(edgeEvent.getEntityId());
117 DownlinkMsg downlinkMsg = null; 120 DownlinkMsg downlinkMsg = null;
118 - try {  
119 - AlarmId alarmId = new AlarmId(edgeEvent.getEntityId());  
120 - Alarm alarm = alarmService.findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId).get();  
121 - if (alarm != null) { 121 + switch (action) {
  122 + case ADDED:
  123 + case UPDATED:
  124 + case ALARM_ACK:
  125 + case ALARM_CLEAR:
  126 + try {
  127 + Alarm alarm = alarmService.findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId).get();
  128 + if (alarm != null) {
  129 + downlinkMsg = DownlinkMsg.newBuilder()
  130 + .setDownlinkMsgId(EdgeUtils.nextPositiveInt())
  131 + .addAlarmUpdateMsg(alarmMsgConstructor.constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm))
  132 + .build();
  133 + }
  134 + } catch (Exception e) {
  135 + log.error("Can't process alarm msg [{}] [{}]", edgeEvent, msgType, e);
  136 + }
  137 + break;
  138 + case DELETED:
  139 + Alarm alarm = mapper.convertValue(edgeEvent.getBody(), Alarm.class);
  140 + AlarmUpdateMsg alarmUpdateMsg =
  141 + alarmMsgConstructor.constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm);
122 downlinkMsg = DownlinkMsg.newBuilder() 142 downlinkMsg = DownlinkMsg.newBuilder()
123 .setDownlinkMsgId(EdgeUtils.nextPositiveInt()) 143 .setDownlinkMsgId(EdgeUtils.nextPositiveInt())
124 - .addAlarmUpdateMsg(alarmMsgConstructor.constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm)) 144 + .addAlarmUpdateMsg(alarmUpdateMsg)
125 .build(); 145 .build();
126 - }  
127 - } catch (Exception e) {  
128 - log.error("Can't process alarm msg [{}] [{}]", edgeEvent, msgType, e); 146 + break;
129 } 147 }
130 return downlinkMsg; 148 return downlinkMsg;
131 } 149 }
132 150
133 - public void processAlarmNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { 151 + public void processAlarmNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException {
  152 + EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
134 AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); 153 AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
135 - ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);  
136 - Futures.addCallback(alarmFuture, new FutureCallback<Alarm>() {  
137 - @Override  
138 - public void onSuccess(@Nullable Alarm alarm) {  
139 - if (alarm != null) {  
140 - EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType());  
141 - if (type != null) {  
142 - PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);  
143 - PageData<EdgeId> pageData;  
144 - do {  
145 - pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink);  
146 - if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {  
147 - for (EdgeId edgeId : pageData.getData()) {  
148 - saveEdgeEvent(tenantId,  
149 - edgeId,  
150 - EdgeEventType.ALARM,  
151 - EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),  
152 - alarmId,  
153 - null);  
154 - }  
155 - if (pageData.hasNext()) {  
156 - pageLink = pageLink.nextPageLink();  
157 - } 154 + switch (actionType) {
  155 + case DELETED:
  156 + EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
  157 + Alarm alarm = mapper.readValue(edgeNotificationMsg.getBody(), Alarm.class);
  158 + saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, actionType, alarmId, mapper.valueToTree(alarm));
  159 + break;
  160 + default:
  161 + ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);
  162 + Futures.addCallback(alarmFuture, new FutureCallback<Alarm>() {
  163 + @Override
  164 + public void onSuccess(@Nullable Alarm alarm) {
  165 + if (alarm != null) {
  166 + EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType());
  167 + if (type != null) {
  168 + PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
  169 + PageData<EdgeId> pageData;
  170 + do {
  171 + pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink);
  172 + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
  173 + for (EdgeId edgeId : pageData.getData()) {
  174 + saveEdgeEvent(tenantId,
  175 + edgeId,
  176 + EdgeEventType.ALARM,
  177 + EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
  178 + alarmId,
  179 + null);
  180 + }
  181 + if (pageData.hasNext()) {
  182 + pageLink = pageLink.nextPageLink();
  183 + }
  184 + }
  185 + } while (pageData != null && pageData.hasNext());
158 } 186 }
159 - } while (pageData != null && pageData.hasNext()); 187 + }
160 } 188 }
161 - }  
162 - }  
163 189
164 - @Override  
165 - public void onFailure(Throwable t) {  
166 - log.warn("[{}] can't find alarm by id [{}] {}", tenantId.getId(), alarmId.getId(), t);  
167 - }  
168 - }, dbCallbackExecutorService); 190 + @Override
  191 + public void onFailure(Throwable t) {
  192 + log.warn("[{}] can't find alarm by id [{}] {}", tenantId.getId(), alarmId.getId(), t);
  193 + }
  194 + }, dbCallbackExecutorService);
  195 + }
169 } 196 }
170 197
171 } 198 }
@@ -17,11 +17,7 @@ package org.thingsboard.server.service.edge.rpc.processor; @@ -17,11 +17,7 @@ package org.thingsboard.server.service.edge.rpc.processor;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
20 -import com.google.common.util.concurrent.FutureCallback;  
21 -import com.google.common.util.concurrent.Futures;  
22 -import com.google.common.util.concurrent.ListenableFuture;  
23 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
24 -import org.checkerframework.checker.nullness.qual.Nullable;  
25 import org.springframework.beans.factory.annotation.Autowired; 21 import org.springframework.beans.factory.annotation.Autowired;
26 import org.thingsboard.server.common.data.HasCustomerId; 22 import org.thingsboard.server.common.data.HasCustomerId;
27 import org.thingsboard.server.common.data.edge.Edge; 23 import org.thingsboard.server.common.data.edge.Edge;
@@ -66,7 +62,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.WidgetTypeMsgConstruc @@ -66,7 +62,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.WidgetTypeMsgConstruc
66 import org.thingsboard.server.service.edge.rpc.constructor.WidgetsBundleMsgConstructor; 62 import org.thingsboard.server.service.edge.rpc.constructor.WidgetsBundleMsgConstructor;
67 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 63 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
68 import org.thingsboard.server.service.profile.TbDeviceProfileCache; 64 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
69 -import org.thingsboard.server.service.queue.TbClusterService; 65 +import org.thingsboard.server.cluster.TbClusterService;
70 import org.thingsboard.server.service.state.DeviceStateService; 66 import org.thingsboard.server.service.state.DeviceStateService;
71 67
72 @Slf4j 68 @Slf4j
@@ -178,12 +174,12 @@ public abstract class BaseEdgeProcessor { @@ -178,12 +174,12 @@ public abstract class BaseEdgeProcessor {
178 @Autowired 174 @Autowired
179 protected DbCallbackExecutorService dbCallbackExecutorService; 175 protected DbCallbackExecutorService dbCallbackExecutorService;
180 176
181 - protected ListenableFuture<EdgeEvent> saveEdgeEvent(TenantId tenantId,  
182 - EdgeId edgeId,  
183 - EdgeEventType type,  
184 - EdgeEventActionType action,  
185 - EntityId entityId,  
186 - JsonNode body) { 177 + protected void saveEdgeEvent(TenantId tenantId,
  178 + EdgeId edgeId,
  179 + EdgeEventType type,
  180 + EdgeEventActionType action,
  181 + EntityId entityId,
  182 + JsonNode body) {
187 log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " + 183 log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " +
188 "action [{}], entityId [{}], body [{}]", 184 "action [{}], entityId [{}], body [{}]",
189 tenantId, edgeId, type, action, entityId, body); 185 tenantId, edgeId, type, action, entityId, body);
@@ -197,19 +193,8 @@ public abstract class BaseEdgeProcessor { @@ -197,19 +193,8 @@ public abstract class BaseEdgeProcessor {
197 edgeEvent.setEntityId(entityId.getId()); 193 edgeEvent.setEntityId(entityId.getId());
198 } 194 }
199 edgeEvent.setBody(body); 195 edgeEvent.setBody(body);
200 - ListenableFuture<EdgeEvent> future = edgeEventService.saveAsync(edgeEvent);  
201 - Futures.addCallback(future, new FutureCallback<EdgeEvent>() {  
202 - @Override  
203 - public void onSuccess(@Nullable EdgeEvent result) {  
204 - tbClusterService.onEdgeEventUpdate(tenantId, edgeId);  
205 - }  
206 -  
207 - @Override  
208 - public void onFailure(Throwable t) {  
209 - log.warn("[{}] Can't save edge event [{}] for edge [{}]", tenantId.getId(), edgeEvent, edgeId.getId(), t);  
210 - }  
211 - }, dbCallbackExecutorService);  
212 - return future; 196 + edgeEventService.save(edgeEvent);
  197 + tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
213 } 198 }
214 199
215 protected CustomerId getCustomerIdIfEdgeAssignedToCustomer(HasCustomerId hasCustomerIdEntity, Edge edge) { 200 protected CustomerId getCustomerIdIfEdgeAssignedToCustomer(HasCustomerId hasCustomerIdEntity, Edge edge) {
@@ -18,7 +18,6 @@ package org.thingsboard.server.service.edge.rpc.processor; @@ -18,7 +18,6 @@ package org.thingsboard.server.service.edge.rpc.processor;
18 import com.datastax.oss.driver.api.core.uuid.Uuids; 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
19 import com.fasterxml.jackson.core.JsonProcessingException; 19 import com.fasterxml.jackson.core.JsonProcessingException;
20 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
21 -import com.google.common.util.concurrent.FutureCallback;  
22 import com.google.common.util.concurrent.Futures; 21 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.ListenableFuture; 22 import com.google.common.util.concurrent.ListenableFuture;
24 import com.google.common.util.concurrent.SettableFuture; 23 import com.google.common.util.concurrent.SettableFuture;
@@ -27,7 +26,7 @@ import org.apache.commons.lang3.RandomStringUtils; @@ -27,7 +26,7 @@ import org.apache.commons.lang3.RandomStringUtils;
27 import org.apache.commons.lang3.StringUtils; 26 import org.apache.commons.lang3.StringUtils;
28 import org.springframework.stereotype.Component; 27 import org.springframework.stereotype.Component;
29 import org.thingsboard.common.util.JacksonUtil; 28 import org.thingsboard.common.util.JacksonUtil;
30 -import org.thingsboard.rule.engine.api.RpcError; 29 +import org.thingsboard.server.common.data.rpc.RpcError;
31 import org.thingsboard.server.common.data.Customer; 30 import org.thingsboard.server.common.data.Customer;
32 import org.thingsboard.server.common.data.DataConstants; 31 import org.thingsboard.server.common.data.DataConstants;
33 import org.thingsboard.server.common.data.Device; 32 import org.thingsboard.server.common.data.Device;
@@ -60,7 +59,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType; @@ -60,7 +59,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
60 import org.thingsboard.server.queue.TbQueueCallback; 59 import org.thingsboard.server.queue.TbQueueCallback;
61 import org.thingsboard.server.queue.TbQueueMsgMetadata; 60 import org.thingsboard.server.queue.TbQueueMsgMetadata;
62 import org.thingsboard.server.queue.util.TbCoreComponent; 61 import org.thingsboard.server.queue.util.TbCoreComponent;
63 -import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 62 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
64 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; 63 import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg;
65 64
66 import java.util.UUID; 65 import java.util.UUID;
@@ -105,19 +104,8 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { @@ -105,19 +104,8 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
105 Device newDevice = createDevice(tenantId, edge, deviceUpdateMsg, newDeviceName); 104 Device newDevice = createDevice(tenantId, edge, deviceUpdateMsg, newDeviceName);
106 ObjectNode body = mapper.createObjectNode(); 105 ObjectNode body = mapper.createObjectNode();
107 body.put("conflictName", deviceName); 106 body.put("conflictName", deviceName);
108 - ListenableFuture<EdgeEvent> future =  
109 - saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, newDevice.getId(), body);  
110 - Futures.addCallback(future, new FutureCallback<>() {  
111 - @Override  
112 - public void onSuccess(EdgeEvent edgeEvent) {  
113 - saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, newDevice.getId(), null);  
114 - }  
115 -  
116 - @Override  
117 - public void onFailure(Throwable t) {  
118 - log.error("[{}] Failed to save ENTITY_MERGE_REQUEST edge event [{}][{}]", tenantId, deviceUpdateMsg, edge.getId(), t);  
119 - }  
120 - }, dbCallbackExecutorService); 107 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, newDevice.getId(), body);
  108 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, newDevice.getId(), null);
121 } 109 }
122 } while (pageData != null && pageData.hasNext()); 110 } while (pageData != null && pageData.hasNext());
123 } else { 111 } else {
@@ -155,7 +143,9 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { @@ -155,7 +143,9 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
155 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, device.getId()); 143 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, device.getId());
156 deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType())); 144 deviceCredentials.setCredentialsType(DeviceCredentialsType.valueOf(deviceCredentialsUpdateMsg.getCredentialsType()));
157 deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId()); 145 deviceCredentials.setCredentialsId(deviceCredentialsUpdateMsg.getCredentialsId());
158 - deviceCredentials.setCredentialsValue(deviceCredentialsUpdateMsg.getCredentialsValue()); 146 + if (deviceCredentialsUpdateMsg.hasCredentialsValue()) {
  147 + deviceCredentials.setCredentialsValue(deviceCredentialsUpdateMsg.getCredentialsValue().getValue());
  148 + }
159 deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentials); 149 deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentials);
160 } catch (Exception e) { 150 } catch (Exception e) {
161 log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", device.getName(), deviceCredentialsUpdateMsg, e); 151 log.error("Can't update device credentials for device [{}], deviceCredentialsUpdateMsg [{}]", device.getName(), deviceCredentialsUpdateMsg, e);
@@ -173,14 +163,20 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { @@ -173,14 +163,20 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
173 if (device != null) { 163 if (device != null) {
174 device.setName(deviceUpdateMsg.getName()); 164 device.setName(deviceUpdateMsg.getName());
175 device.setType(deviceUpdateMsg.getType()); 165 device.setType(deviceUpdateMsg.getType());
176 - device.setLabel(deviceUpdateMsg.getLabel());  
177 - device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));  
178 - if (deviceUpdateMsg.getDeviceProfileIdMSB() != 0 && deviceUpdateMsg.getDeviceProfileIdLSB() != 0) { 166 + if (deviceUpdateMsg.hasLabel()) {
  167 + device.setLabel(deviceUpdateMsg.getLabel().getValue());
  168 + }
  169 + if (deviceUpdateMsg.hasAdditionalInfo()) {
  170 + device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo().getValue()));
  171 + }
  172 + if (deviceUpdateMsg.hasDeviceProfileIdMSB() && deviceUpdateMsg.hasDeviceProfileIdLSB()) {
179 DeviceProfileId deviceProfileId = new DeviceProfileId( 173 DeviceProfileId deviceProfileId = new DeviceProfileId(
180 - new UUID(deviceUpdateMsg.getDeviceProfileIdMSB(), deviceUpdateMsg.getDeviceProfileIdLSB())); 174 + new UUID(deviceUpdateMsg.getDeviceProfileIdMSB().getValue(),
  175 + deviceUpdateMsg.getDeviceProfileIdLSB().getValue()));
181 device.setDeviceProfileId(deviceProfileId); 176 device.setDeviceProfileId(deviceProfileId);
182 } 177 }
183 - deviceService.saveDevice(device); 178 + Device savedDevice = deviceService.saveDevice(device);
  179 + tbClusterService.onDeviceUpdated(savedDevice, device);
184 saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null); 180 saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null);
185 } else { 181 } else {
186 log.warn("[{}] can't find device [{}], edge [{}]", tenantId, deviceUpdateMsg, edge.getId()); 182 log.warn("[{}] can't find device [{}], edge [{}]", tenantId, deviceUpdateMsg, edge.getId());
@@ -206,22 +202,26 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { @@ -206,22 +202,26 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
206 device.setCustomerId(getCustomerId(edge)); 202 device.setCustomerId(getCustomerId(edge));
207 device.setName(deviceName); 203 device.setName(deviceName);
208 device.setType(deviceUpdateMsg.getType()); 204 device.setType(deviceUpdateMsg.getType());
209 - device.setLabel(deviceUpdateMsg.getLabel());  
210 - device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo()));  
211 - if (deviceUpdateMsg.getDeviceProfileIdMSB() != 0 && deviceUpdateMsg.getDeviceProfileIdLSB() != 0) { 205 + if (deviceUpdateMsg.hasLabel()) {
  206 + device.setLabel(deviceUpdateMsg.getLabel().getValue());
  207 + }
  208 + if (deviceUpdateMsg.hasAdditionalInfo()) {
  209 + device.setAdditionalInfo(JacksonUtil.toJsonNode(deviceUpdateMsg.getAdditionalInfo().getValue()));
  210 + }
  211 + if (deviceUpdateMsg.hasDeviceProfileIdMSB() && deviceUpdateMsg.hasDeviceProfileIdLSB()) {
212 DeviceProfileId deviceProfileId = new DeviceProfileId( 212 DeviceProfileId deviceProfileId = new DeviceProfileId(
213 - new UUID(deviceUpdateMsg.getDeviceProfileIdMSB(), deviceUpdateMsg.getDeviceProfileIdLSB())); 213 + new UUID(deviceUpdateMsg.getDeviceProfileIdMSB().getValue(),
  214 + deviceUpdateMsg.getDeviceProfileIdLSB().getValue()));
214 device.setDeviceProfileId(deviceProfileId); 215 device.setDeviceProfileId(deviceProfileId);
215 } 216 }
216 Device savedDevice = deviceService.saveDevice(device, false); 217 Device savedDevice = deviceService.saveDevice(device, false);
  218 + tbClusterService.onDeviceUpdated(savedDevice, device);
217 if (created) { 219 if (created) {
218 DeviceCredentials deviceCredentials = new DeviceCredentials(); 220 DeviceCredentials deviceCredentials = new DeviceCredentials();
219 deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId())); 221 deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId()));
220 deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); 222 deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
221 deviceCredentials.setCredentialsId(org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(20)); 223 deviceCredentials.setCredentialsId(org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric(20));
222 deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials); 224 deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
223 -  
224 - deviceStateService.onDeviceAdded(savedDevice);  
225 } 225 }
226 createRelationFromEdge(tenantId, edge.getId(), device.getId()); 226 createRelationFromEdge(tenantId, edge.getId(), device.getId());
227 pushDeviceCreatedEventToRuleEngine(tenantId, edge, device); 227 pushDeviceCreatedEventToRuleEngine(tenantId, edge, device);
@@ -72,7 +72,9 @@ public class RelationEdgeProcessor extends BaseEdgeProcessor { @@ -72,7 +72,9 @@ public class RelationEdgeProcessor extends BaseEdgeProcessor {
72 entityRelation.setTo(toId); 72 entityRelation.setTo(toId);
73 73
74 entityRelation.setType(relationUpdateMsg.getType()); 74 entityRelation.setType(relationUpdateMsg.getType());
75 - entityRelation.setTypeGroup(RelationTypeGroup.valueOf(relationUpdateMsg.getTypeGroup())); 75 + if (relationUpdateMsg.hasTypeGroup()) {
  76 + entityRelation.setTypeGroup(RelationTypeGroup.valueOf(relationUpdateMsg.getTypeGroup().getValue()));
  77 + }
76 entityRelation.setAdditionalInfo(mapper.readTree(relationUpdateMsg.getAdditionalInfo())); 78 entityRelation.setAdditionalInfo(mapper.readTree(relationUpdateMsg.getAdditionalInfo()));
77 switch (relationUpdateMsg.getMsgType()) { 79 switch (relationUpdateMsg.getMsgType()) {
78 case ENTITY_CREATED_RPC_MESSAGE: 80 case ENTITY_CREATED_RPC_MESSAGE:
@@ -73,7 +73,7 @@ import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg; @@ -73,7 +73,7 @@ import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg;
73 import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg; 73 import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg;
74 import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; 74 import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
75 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 75 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
76 -import org.thingsboard.server.service.queue.TbClusterService; 76 +import org.thingsboard.server.cluster.TbClusterService;
77 77
78 import java.util.ArrayList; 78 import java.util.ArrayList;
79 import java.util.HashMap; 79 import java.util.HashMap;
@@ -122,26 +122,13 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -122,26 +122,13 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
122 @Override 122 @Override
123 public ListenableFuture<Void> processRuleChainMetadataRequestMsg(TenantId tenantId, Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) { 123 public ListenableFuture<Void> processRuleChainMetadataRequestMsg(TenantId tenantId, Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) {
124 log.trace("[{}] processRuleChainMetadataRequestMsg [{}][{}]", tenantId, edge.getName(), ruleChainMetadataRequestMsg); 124 log.trace("[{}] processRuleChainMetadataRequestMsg [{}][{}]", tenantId, edge.getName(), ruleChainMetadataRequestMsg);
125 - SettableFuture<Void> futureToSet = SettableFuture.create();  
126 if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) { 125 if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {
127 RuleChainId ruleChainId = 126 RuleChainId ruleChainId =
128 new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB())); 127 new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
129 - ListenableFuture<EdgeEvent> future = saveEdgeEvent(tenantId, edge.getId(), 128 + saveEdgeEvent(tenantId, edge.getId(),
130 EdgeEventType.RULE_CHAIN_METADATA, EdgeEventActionType.ADDED, ruleChainId, null); 129 EdgeEventType.RULE_CHAIN_METADATA, EdgeEventActionType.ADDED, ruleChainId, null);
131 - Futures.addCallback(future, new FutureCallback<EdgeEvent>() {  
132 - @Override  
133 - public void onSuccess(@Nullable EdgeEvent result) {  
134 - futureToSet.set(null);  
135 - }  
136 -  
137 - @Override  
138 - public void onFailure(Throwable t) {  
139 - log.error("Can't save edge event [{}]", ruleChainMetadataRequestMsg, t);  
140 - futureToSet.setException(t);  
141 - }  
142 - }, dbCallbackExecutorService);  
143 } 130 }
144 - return futureToSet; 131 + return Futures.immediateFuture(null);
145 } 132 }
146 133
147 @Override 134 @Override
@@ -154,8 +141,8 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -154,8 +141,8 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
154 if (type != null) { 141 if (type != null) {
155 SettableFuture<Void> futureToSet = SettableFuture.create(); 142 SettableFuture<Void> futureToSet = SettableFuture.create();
156 String scope = attributesRequestMsg.getScope(); 143 String scope = attributesRequestMsg.getScope();
157 - ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = attributesService.findAll(tenantId, entityId, scope);  
158 - Futures.addCallback(ssAttrFuture, new FutureCallback<List<AttributeKvEntry>>() { 144 + ListenableFuture<List<AttributeKvEntry>> findAttrFuture = attributesService.findAll(tenantId, entityId, scope);
  145 + Futures.addCallback(findAttrFuture, new FutureCallback<List<AttributeKvEntry>>() {
159 @Override 146 @Override
160 public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) { 147 public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) {
161 if (ssAttributes != null && !ssAttributes.isEmpty()) { 148 if (ssAttributes != null && !ssAttributes.isEmpty()) {
@@ -184,8 +171,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -184,8 +171,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
184 entityId, 171 entityId,
185 body); 172 body);
186 } catch (Exception e) { 173 } catch (Exception e) {
187 - log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e);  
188 - throw new RuntimeException("[" + edge.getName() + "] Failed to send attribute updates to the edge", e); 174 + log.error("[{}] Failed to save attribute updates to the edge", edge.getName(), e);
  175 + futureToSet.setException(new RuntimeException("[" + edge.getName() + "] Failed to send attribute updates to the edge", e));
  176 + return;
189 } 177 }
190 } else { 178 } else {
191 log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId, 179 log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId,
@@ -198,7 +186,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -198,7 +186,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
198 186
199 @Override 187 @Override
200 public void onFailure(Throwable t) { 188 public void onFailure(Throwable t) {
201 - log.error("Can't save attributes [{}]", attributesRequestMsg, t); 189 + log.error("Can't find attributes [{}]", attributesRequestMsg, t);
202 futureToSet.setException(t); 190 futureToSet.setException(t);
203 } 191 }
204 }, dbCallbackExecutorService); 192 }, dbCallbackExecutorService);
@@ -273,82 +261,39 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -273,82 +261,39 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
273 @Override 261 @Override
274 public ListenableFuture<Void> processDeviceCredentialsRequestMsg(TenantId tenantId, Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) { 262 public ListenableFuture<Void> processDeviceCredentialsRequestMsg(TenantId tenantId, Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) {
275 log.trace("[{}] processDeviceCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), deviceCredentialsRequestMsg); 263 log.trace("[{}] processDeviceCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), deviceCredentialsRequestMsg);
276 - SettableFuture<Void> futureToSet = SettableFuture.create();  
277 if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) { 264 if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) {
278 DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB())); 265 DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
279 - ListenableFuture<EdgeEvent> future = saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, 266 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE,
280 EdgeEventActionType.CREDENTIALS_UPDATED, deviceId, null); 267 EdgeEventActionType.CREDENTIALS_UPDATED, deviceId, null);
281 - Futures.addCallback(future, new FutureCallback<EdgeEvent>() {  
282 - @Override  
283 - public void onSuccess(@Nullable EdgeEvent result) {  
284 - futureToSet.set(null);  
285 - }  
286 -  
287 - @Override  
288 - public void onFailure(Throwable t) {  
289 - log.error("Can't save edge event [{}]", deviceCredentialsRequestMsg, t);  
290 - futureToSet.setException(t);  
291 - }  
292 - }, dbCallbackExecutorService);  
293 } 268 }
294 - return futureToSet; 269 + return Futures.immediateFuture(null);
295 } 270 }
296 271
297 @Override 272 @Override
298 public ListenableFuture<Void> processUserCredentialsRequestMsg(TenantId tenantId, Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) { 273 public ListenableFuture<Void> processUserCredentialsRequestMsg(TenantId tenantId, Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) {
299 log.trace("[{}] processUserCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), userCredentialsRequestMsg); 274 log.trace("[{}] processUserCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), userCredentialsRequestMsg);
300 - SettableFuture<Void> futureToSet = SettableFuture.create();  
301 if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) { 275 if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) {
302 UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB())); 276 UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
303 - ListenableFuture<EdgeEvent> future = saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER, 277 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
304 EdgeEventActionType.CREDENTIALS_UPDATED, userId, null); 278 EdgeEventActionType.CREDENTIALS_UPDATED, userId, null);
305 - Futures.addCallback(future, new FutureCallback<>() {  
306 - @Override  
307 - public void onSuccess(@Nullable EdgeEvent result) {  
308 - futureToSet.set(null);  
309 - }  
310 -  
311 - @Override  
312 - public void onFailure(Throwable t) {  
313 - log.error("Can't save edge event [{}]", userCredentialsRequestMsg, t);  
314 - futureToSet.setException(t);  
315 - }  
316 - }, dbCallbackExecutorService);  
317 } 279 }
318 - return futureToSet; 280 + return Futures.immediateFuture(null);
319 } 281 }
320 282
321 @Override 283 @Override
322 public ListenableFuture<Void> processDeviceProfileDevicesRequestMsg(TenantId tenantId, Edge edge, DeviceProfileDevicesRequestMsg deviceProfileDevicesRequestMsg) { 284 public ListenableFuture<Void> processDeviceProfileDevicesRequestMsg(TenantId tenantId, Edge edge, DeviceProfileDevicesRequestMsg deviceProfileDevicesRequestMsg) {
323 log.trace("[{}] processDeviceProfileDevicesRequestMsg [{}][{}]", tenantId, edge.getName(), deviceProfileDevicesRequestMsg); 285 log.trace("[{}] processDeviceProfileDevicesRequestMsg [{}][{}]", tenantId, edge.getName(), deviceProfileDevicesRequestMsg);
324 - SettableFuture<Void> futureToSet = SettableFuture.create();  
325 if (deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB() != 0 && deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB() != 0) { 286 if (deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB() != 0 && deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB() != 0) {
326 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB(), deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB())); 287 DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB(), deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB()));
327 DeviceProfile deviceProfileById = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); 288 DeviceProfile deviceProfileById = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
328 - List<ListenableFuture<EdgeEvent>> futures;  
329 if (deviceProfileById != null) { 289 if (deviceProfileById != null) {
330 - futures = syncDevices(tenantId, edge, deviceProfileById.getName());  
331 - } else {  
332 - futures = new ArrayList<>(); 290 + syncDevices(tenantId, edge, deviceProfileById.getName());
333 } 291 }
334 - Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {  
335 - @Override  
336 - public void onSuccess(@Nullable List<EdgeEvent> result) {  
337 - futureToSet.set(null);  
338 - }  
339 -  
340 - @Override  
341 - public void onFailure(Throwable t) {  
342 - log.error("Can't sync devices by device profile [{}]", deviceProfileDevicesRequestMsg, t);  
343 - futureToSet.setException(t);  
344 - }  
345 - }, dbCallbackExecutorService);  
346 } 292 }
347 - return futureToSet; 293 + return Futures.immediateFuture(null);
348 } 294 }
349 295
350 - private List<ListenableFuture<EdgeEvent>> syncDevices(TenantId tenantId, Edge edge, String deviceType) {  
351 - List<ListenableFuture<EdgeEvent>> futures = new ArrayList<>(); 296 + private void syncDevices(TenantId tenantId, Edge edge, String deviceType) {
352 log.trace("[{}] syncDevices [{}][{}]", tenantId, edge.getName(), deviceType); 297 log.trace("[{}] syncDevices [{}][{}]", tenantId, edge.getName(), deviceType);
353 try { 298 try {
354 PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); 299 PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
@@ -358,7 +303,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -358,7 +303,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
358 if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { 303 if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
359 log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); 304 log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
360 for (Device device : pageData.getData()) { 305 for (Device device : pageData.getData()) {
361 - futures.add(saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ADDED, device.getId(), null)); 306 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ADDED, device.getId(), null);
362 } 307 }
363 if (pageData.hasNext()) { 308 if (pageData.hasNext()) {
364 pageLink = pageLink.nextPageLink(); 309 pageLink = pageLink.nextPageLink();
@@ -368,40 +313,25 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -368,40 +313,25 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
368 } catch (Exception e) { 313 } catch (Exception e) {
369 log.error("Exception during loading edge device(s) on sync!", e); 314 log.error("Exception during loading edge device(s) on sync!", e);
370 } 315 }
371 - return futures;  
372 } 316 }
373 317
374 @Override 318 @Override
375 public ListenableFuture<Void> processWidgetBundleTypesRequestMsg(TenantId tenantId, Edge edge, 319 public ListenableFuture<Void> processWidgetBundleTypesRequestMsg(TenantId tenantId, Edge edge,
376 WidgetBundleTypesRequestMsg widgetBundleTypesRequestMsg) { 320 WidgetBundleTypesRequestMsg widgetBundleTypesRequestMsg) {
377 log.trace("[{}] processWidgetBundleTypesRequestMsg [{}][{}]", tenantId, edge.getName(), widgetBundleTypesRequestMsg); 321 log.trace("[{}] processWidgetBundleTypesRequestMsg [{}][{}]", tenantId, edge.getName(), widgetBundleTypesRequestMsg);
378 - SettableFuture<Void> futureToSet = SettableFuture.create();  
379 if (widgetBundleTypesRequestMsg.getWidgetBundleIdMSB() != 0 && widgetBundleTypesRequestMsg.getWidgetBundleIdLSB() != 0) { 322 if (widgetBundleTypesRequestMsg.getWidgetBundleIdMSB() != 0 && widgetBundleTypesRequestMsg.getWidgetBundleIdLSB() != 0) {
380 WidgetsBundleId widgetsBundleId = new WidgetsBundleId(new UUID(widgetBundleTypesRequestMsg.getWidgetBundleIdMSB(), widgetBundleTypesRequestMsg.getWidgetBundleIdLSB())); 323 WidgetsBundleId widgetsBundleId = new WidgetsBundleId(new UUID(widgetBundleTypesRequestMsg.getWidgetBundleIdMSB(), widgetBundleTypesRequestMsg.getWidgetBundleIdLSB()));
381 WidgetsBundle widgetsBundleById = widgetsBundleService.findWidgetsBundleById(tenantId, widgetsBundleId); 324 WidgetsBundle widgetsBundleById = widgetsBundleService.findWidgetsBundleById(tenantId, widgetsBundleId);
382 - List<ListenableFuture<EdgeEvent>> futures = new ArrayList<>();  
383 if (widgetsBundleById != null) { 325 if (widgetsBundleById != null) {
384 List<WidgetType> widgetTypesToPush = 326 List<WidgetType> widgetTypesToPush =
385 widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundleById.getTenantId(), widgetsBundleById.getAlias()); 327 widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundleById.getTenantId(), widgetsBundleById.getAlias());
386 328
387 for (WidgetType widgetType : widgetTypesToPush) { 329 for (WidgetType widgetType : widgetTypesToPush) {
388 - futures.add(saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null)); 330 + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null);
389 } 331 }
390 } 332 }
391 - Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {  
392 - @Override  
393 - public void onSuccess(@Nullable List<EdgeEvent> result) {  
394 - futureToSet.set(null);  
395 - }  
396 -  
397 - @Override  
398 - public void onFailure(Throwable t) {  
399 - log.error("Can't sync widget types by widget bundle [{}]", widgetBundleTypesRequestMsg, t);  
400 - futureToSet.setException(t);  
401 - }  
402 - }, dbCallbackExecutorService);  
403 } 333 }
404 - return futureToSet; 334 + return Futures.immediateFuture(null);
405 } 335 }
406 336
407 @Override 337 @Override
@@ -416,9 +346,12 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -416,9 +346,12 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
416 public void onSuccess(@Nullable List<EntityView> entityViews) { 346 public void onSuccess(@Nullable List<EntityView> entityViews) {
417 try { 347 try {
418 if (entityViews != null && !entityViews.isEmpty()) { 348 if (entityViews != null && !entityViews.isEmpty()) {
  349 + List<ListenableFuture<Boolean>> futures = new ArrayList<>();
419 for (EntityView entityView : entityViews) { 350 for (EntityView entityView : entityViews) {
420 - Futures.addCallback(relationService.checkRelation(tenantId, edge.getId(), entityView.getId(),  
421 - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE), new FutureCallback<>() { 351 + ListenableFuture<Boolean> future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(),
  352 + EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
  353 + futures.add(future);
  354 + Futures.addCallback(future, new FutureCallback<>() {
422 @Override 355 @Override
423 public void onSuccess(@Nullable Boolean result) { 356 public void onSuccess(@Nullable Boolean result) {
424 if (Boolean.TRUE.equals(result)) { 357 if (Boolean.TRUE.equals(result)) {
@@ -426,16 +359,27 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -426,16 +359,27 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
426 EdgeEventActionType.ADDED, entityView.getId(), null); 359 EdgeEventActionType.ADDED, entityView.getId(), null);
427 } 360 }
428 } 361 }
429 -  
430 @Override 362 @Override
431 public void onFailure(Throwable t) { 363 public void onFailure(Throwable t) {
432 - log.error("Exception during loading relation [{}] to edge on sync!", t, t);  
433 - futureToSet.setException(t); 364 + // Do nothing - error handles in allAsList
434 } 365 }
435 }, dbCallbackExecutorService); 366 }, dbCallbackExecutorService);
436 } 367 }
  368 + Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {
  369 + @Override
  370 + public void onSuccess(@Nullable List<Boolean> result) {
  371 + futureToSet.set(null);
  372 + }
  373 +
  374 + @Override
  375 + public void onFailure(Throwable t) {
  376 + log.error("Exception during loading relation [{}] to edge on sync!", t, t);
  377 + futureToSet.setException(t);
  378 + }
  379 + }, dbCallbackExecutorService);
  380 + } else {
  381 + futureToSet.set(null);
437 } 382 }
438 - futureToSet.set(null);  
439 } catch (Exception e) { 383 } catch (Exception e) {
440 log.error("Exception during loading relation(s) to edge on sync!", e); 384 log.error("Exception during loading relation(s) to edge on sync!", e);
441 futureToSet.setException(e); 385 futureToSet.setException(e);
@@ -451,30 +395,19 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { @@ -451,30 +395,19 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
451 return futureToSet; 395 return futureToSet;
452 } 396 }
453 397
454 - private ListenableFuture<EdgeEvent> saveEdgeEvent(TenantId tenantId,  
455 - EdgeId edgeId,  
456 - EdgeEventType type,  
457 - EdgeEventActionType action,  
458 - EntityId entityId,  
459 - JsonNode body) { 398 + private void saveEdgeEvent(TenantId tenantId,
  399 + EdgeId edgeId,
  400 + EdgeEventType type,
  401 + EdgeEventActionType action,
  402 + EntityId entityId,
  403 + JsonNode body) {
460 log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]", 404 log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
461 tenantId, edgeId, type, action, entityId, body); 405 tenantId, edgeId, type, action, entityId, body);
462 406
463 EdgeEvent edgeEvent = EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body); 407 EdgeEvent edgeEvent = EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
464 408
465 - ListenableFuture<EdgeEvent> future = edgeEventService.saveAsync(edgeEvent);  
466 - Futures.addCallback(future, new FutureCallback<>() {  
467 - @Override  
468 - public void onSuccess(@Nullable EdgeEvent result) {  
469 - tbClusterService.onEdgeEventUpdate(tenantId, edgeId);  
470 - }  
471 -  
472 - @Override  
473 - public void onFailure(Throwable t) {  
474 - log.warn("[{}] Can't save edge event [{}] for edge [{}]", tenantId.getId(), edgeEvent, edgeId.getId(), t);  
475 - }  
476 - }, dbCallbackExecutorService);  
477 - return future; 409 + edgeEventService.save(edgeEvent);
  410 + tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
478 } 411 }
479 412
480 } 413 }
@@ -215,6 +215,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @@ -215,6 +215,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
215 node.put("password", ""); 215 node.put("password", "");
216 node.put("tlsVersion", "TLSv1.2");//NOSONAR, key used to identify password field (not password value itself) 216 node.put("tlsVersion", "TLSv1.2");//NOSONAR, key used to identify password field (not password value itself)
217 node.put("enableProxy", false); 217 node.put("enableProxy", false);
  218 + node.put("showChangePassword", false);
218 mailSettings.setJsonValue(node); 219 mailSettings.setJsonValue(node);
219 adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings); 220 adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings);
220 } 221 }
@@ -480,6 +481,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @@ -480,6 +481,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
480 device.setAdditionalInfo(additionalInfo); 481 device.setAdditionalInfo(additionalInfo);
481 } 482 }
482 device = deviceService.saveDevice(device); 483 device = deviceService.saveDevice(device);
  484 + //TODO: No access to cluster service, so we should manually update the status of device.
483 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(TenantId.SYS_TENANT_ID, device.getId()); 485 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(TenantId.SYS_TENANT_ID, device.getId());
484 deviceCredentials.setCredentialsId(accessToken); 486 deviceCredentials.setCredentialsId(accessToken);
485 deviceCredentialsService.updateDeviceCredentials(TenantId.SYS_TENANT_ID, deviceCredentials); 487 deviceCredentialsService.updateDeviceCredentials(TenantId.SYS_TENANT_ID, deviceCredentials);
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.ota; @@ -17,6 +17,7 @@ package org.thingsboard.server.service.ota;
17 17
18 import com.google.common.util.concurrent.FutureCallback; 18 import com.google.common.util.concurrent.FutureCallback;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.context.annotation.Lazy;
20 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
21 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; 22 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
22 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; 23 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
@@ -49,7 +50,7 @@ import org.thingsboard.server.queue.TbQueueProducer; @@ -49,7 +50,7 @@ import org.thingsboard.server.queue.TbQueueProducer;
49 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 50 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
50 import org.thingsboard.server.queue.provider.TbCoreQueueFactory; 51 import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
51 import org.thingsboard.server.queue.util.TbCoreComponent; 52 import org.thingsboard.server.queue.util.TbCoreComponent;
52 -import org.thingsboard.server.service.queue.TbClusterService; 53 +import org.thingsboard.server.cluster.TbClusterService;
53 54
54 import javax.annotation.Nullable; 55 import javax.annotation.Nullable;
55 import java.util.ArrayList; 56 import java.util.ArrayList;
@@ -87,10 +88,11 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService { @@ -87,10 +88,11 @@ public class DefaultOtaPackageStateService implements OtaPackageStateService {
87 private final RuleEngineTelemetryService telemetryService; 88 private final RuleEngineTelemetryService telemetryService;
88 private final TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> otaPackageStateMsgProducer; 89 private final TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> otaPackageStateMsgProducer;
89 90
90 - public DefaultOtaPackageStateService(TbClusterService tbClusterService, OtaPackageService otaPackageService, 91 + public DefaultOtaPackageStateService(@Lazy TbClusterService tbClusterService,
  92 + OtaPackageService otaPackageService,
91 DeviceService deviceService, 93 DeviceService deviceService,
92 DeviceProfileService deviceProfileService, 94 DeviceProfileService deviceProfileService,
93 - RuleEngineTelemetryService telemetryService, 95 + @Lazy RuleEngineTelemetryService telemetryService,
94 TbCoreQueueFactory coreQueueFactory) { 96 TbCoreQueueFactory coreQueueFactory) {
95 this.tbClusterService = tbClusterService; 97 this.tbClusterService = tbClusterService;
96 this.otaPackageService = otaPackageService; 98 this.otaPackageService = otaPackageService;
@@ -16,11 +16,17 @@ @@ -16,11 +16,17 @@
16 package org.thingsboard.server.service.queue; 16 package org.thingsboard.server.service.queue;
17 17
18 import com.google.protobuf.ByteString; 18 import com.google.protobuf.ByteString;
  19 +import lombok.RequiredArgsConstructor;
19 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.beans.factory.annotation.Value; 21 import org.springframework.beans.factory.annotation.Value;
21 import org.springframework.scheduling.annotation.Scheduled; 22 import org.springframework.scheduling.annotation.Scheduled;
22 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
23 -import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 24 +import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
  25 +import org.thingsboard.server.cluster.TbClusterService;
  26 +import org.thingsboard.server.common.data.EdgeUtils;
  27 +import org.thingsboard.server.common.data.edge.EdgeEventActionType;
  28 +import org.thingsboard.server.common.data.edge.EdgeEventType;
  29 +import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
24 import org.thingsboard.server.common.data.ApiUsageState; 30 import org.thingsboard.server.common.data.ApiUsageState;
25 import org.thingsboard.server.common.data.Device; 31 import org.thingsboard.server.common.data.Device;
26 import org.thingsboard.server.common.data.DeviceProfile; 32 import org.thingsboard.server.common.data.DeviceProfile;
@@ -29,7 +35,6 @@ import org.thingsboard.server.common.data.HasName; @@ -29,7 +35,6 @@ import org.thingsboard.server.common.data.HasName;
29 import org.thingsboard.server.common.data.TbResource; 35 import org.thingsboard.server.common.data.TbResource;
30 import org.thingsboard.server.common.data.Tenant; 36 import org.thingsboard.server.common.data.Tenant;
31 import org.thingsboard.server.common.data.TenantProfile; 37 import org.thingsboard.server.common.data.TenantProfile;
32 -import org.thingsboard.server.common.data.id.CustomerId;  
33 import org.thingsboard.server.common.data.id.DeviceId; 38 import org.thingsboard.server.common.data.id.DeviceId;
34 import org.thingsboard.server.common.data.id.DeviceProfileId; 39 import org.thingsboard.server.common.data.id.DeviceProfileId;
35 import org.thingsboard.server.common.data.id.EdgeId; 40 import org.thingsboard.server.common.data.id.EdgeId;
@@ -56,8 +61,9 @@ import org.thingsboard.server.queue.common.MultipleTbQueueCallbackWrapper; @@ -56,8 +61,9 @@ import org.thingsboard.server.queue.common.MultipleTbQueueCallbackWrapper;
56 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 61 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
57 import org.thingsboard.server.queue.discovery.PartitionService; 62 import org.thingsboard.server.queue.discovery.PartitionService;
58 import org.thingsboard.server.queue.provider.TbQueueProducerProvider; 63 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
  64 +import org.thingsboard.server.service.ota.OtaPackageStateService;
59 import org.thingsboard.server.service.profile.TbDeviceProfileCache; 65 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
60 -import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 66 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
61 67
62 import java.util.HashSet; 68 import java.util.HashSet;
63 import java.util.Set; 69 import java.util.Set;
@@ -66,10 +72,13 @@ import java.util.concurrent.atomic.AtomicInteger; @@ -66,10 +72,13 @@ import java.util.concurrent.atomic.AtomicInteger;
66 72
67 @Service 73 @Service
68 @Slf4j 74 @Slf4j
  75 +@RequiredArgsConstructor
69 public class DefaultTbClusterService implements TbClusterService { 76 public class DefaultTbClusterService implements TbClusterService {
70 77
71 @Value("${cluster.stats.enabled:false}") 78 @Value("${cluster.stats.enabled:false}")
72 private boolean statsEnabled; 79 private boolean statsEnabled;
  80 + @Value("${edges.enabled}")
  81 + protected boolean edgesEnabled;
73 82
74 private final AtomicInteger toCoreMsgs = new AtomicInteger(0); 83 private final AtomicInteger toCoreMsgs = new AtomicInteger(0);
75 private final AtomicInteger toCoreNfs = new AtomicInteger(0); 84 private final AtomicInteger toCoreNfs = new AtomicInteger(0);
@@ -81,13 +90,7 @@ public class DefaultTbClusterService implements TbClusterService { @@ -81,13 +90,7 @@ public class DefaultTbClusterService implements TbClusterService {
81 private final PartitionService partitionService; 90 private final PartitionService partitionService;
82 private final DataDecodingEncodingService encodingService; 91 private final DataDecodingEncodingService encodingService;
83 private final TbDeviceProfileCache deviceProfileCache; 92 private final TbDeviceProfileCache deviceProfileCache;
84 -  
85 - public DefaultTbClusterService(TbQueueProducerProvider producerProvider, PartitionService partitionService, DataDecodingEncodingService encodingService, TbDeviceProfileCache deviceProfileCache) {  
86 - this.producerProvider = producerProvider;  
87 - this.partitionService = partitionService;  
88 - this.encodingService = encodingService;  
89 - this.deviceProfileCache = deviceProfileCache;  
90 - } 93 + private final OtaPackageStateService otaPackageStateService;
91 94
92 @Override 95 @Override
93 public void pushMsgToCore(TenantId tenantId, EntityId entityId, ToCoreMsg msg, TbQueueCallback callback) { 96 public void pushMsgToCore(TenantId tenantId, EntityId entityId, ToCoreMsg msg, TbQueueCallback callback) {
@@ -200,55 +203,52 @@ public class DefaultTbClusterService implements TbClusterService { @@ -200,55 +203,52 @@ public class DefaultTbClusterService implements TbClusterService {
200 } 203 }
201 204
202 @Override 205 @Override
203 - public void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state) { 206 + public void broadcastEntityStateChangeEvent(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state) {
204 log.trace("[{}] Processing {} state change event: {}", tenantId, entityId.getEntityType(), state); 207 log.trace("[{}] Processing {} state change event: {}", tenantId, entityId.getEntityType(), state);
205 broadcast(new ComponentLifecycleMsg(tenantId, entityId, state)); 208 broadcast(new ComponentLifecycleMsg(tenantId, entityId, state));
206 } 209 }
207 210
208 @Override 211 @Override
209 public void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback) { 212 public void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback) {
210 - onEntityChange(deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile, callback); 213 + broadcastEntityChangeToTransport(deviceProfile.getTenantId(), deviceProfile.getId(), deviceProfile, callback);
211 } 214 }
212 215
213 @Override 216 @Override
214 public void onTenantProfileChange(TenantProfile tenantProfile, TbQueueCallback callback) { 217 public void onTenantProfileChange(TenantProfile tenantProfile, TbQueueCallback callback) {
215 - onEntityChange(TenantId.SYS_TENANT_ID, tenantProfile.getId(), tenantProfile, callback); 218 + broadcastEntityChangeToTransport(TenantId.SYS_TENANT_ID, tenantProfile.getId(), tenantProfile, callback);
216 } 219 }
217 220
218 @Override 221 @Override
219 public void onTenantChange(Tenant tenant, TbQueueCallback callback) { 222 public void onTenantChange(Tenant tenant, TbQueueCallback callback) {
220 - onEntityChange(TenantId.SYS_TENANT_ID, tenant.getId(), tenant, callback); 223 + broadcastEntityChangeToTransport(TenantId.SYS_TENANT_ID, tenant.getId(), tenant, callback);
221 } 224 }
222 225
223 @Override 226 @Override
224 public void onApiStateChange(ApiUsageState apiUsageState, TbQueueCallback callback) { 227 public void onApiStateChange(ApiUsageState apiUsageState, TbQueueCallback callback) {
225 - onEntityChange(apiUsageState.getTenantId(), apiUsageState.getId(), apiUsageState, callback); 228 + broadcastEntityChangeToTransport(apiUsageState.getTenantId(), apiUsageState.getId(), apiUsageState, callback);
226 broadcast(new ComponentLifecycleMsg(apiUsageState.getTenantId(), apiUsageState.getId(), ComponentLifecycleEvent.UPDATED)); 229 broadcast(new ComponentLifecycleMsg(apiUsageState.getTenantId(), apiUsageState.getId(), ComponentLifecycleEvent.UPDATED));
227 } 230 }
228 231
229 @Override 232 @Override
230 public void onDeviceProfileDelete(DeviceProfile entity, TbQueueCallback callback) { 233 public void onDeviceProfileDelete(DeviceProfile entity, TbQueueCallback callback) {
231 - onEntityDelete(entity.getTenantId(), entity.getId(), entity.getName(), callback); 234 + broadcastEntityDeleteToTransport(entity.getTenantId(), entity.getId(), entity.getName(), callback);
232 } 235 }
233 236
234 @Override 237 @Override
235 public void onTenantProfileDelete(TenantProfile entity, TbQueueCallback callback) { 238 public void onTenantProfileDelete(TenantProfile entity, TbQueueCallback callback) {
236 - onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback); 239 + broadcastEntityDeleteToTransport(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback);
237 } 240 }
238 241
239 @Override 242 @Override
240 public void onTenantDelete(Tenant entity, TbQueueCallback callback) { 243 public void onTenantDelete(Tenant entity, TbQueueCallback callback) {
241 - onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback); 244 + broadcastEntityDeleteToTransport(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback);
242 } 245 }
243 246
244 @Override 247 @Override
245 - public void onDeviceChange(Device entity, TbQueueCallback callback) {  
246 - onEntityChange(entity.getTenantId(), entity.getId(), entity, callback);  
247 - }  
248 -  
249 - @Override  
250 - public void onDeviceDeleted(Device entity, TbQueueCallback callback) {  
251 - onEntityDelete(entity.getTenantId(), entity.getId(), entity.getName(), callback); 248 + public void onDeviceDeleted(Device device, TbQueueCallback callback) {
  249 + broadcastEntityDeleteToTransport(device.getTenantId(), device.getId(), device.getName(), callback);
  250 + sendDeviceStateServiceEvent(device.getTenantId(), device.getId(), false, false, true);
  251 + broadcastEntityStateChangeEvent(device.getTenantId(), device.getId(), ComponentLifecycleEvent.DELETED);
252 } 252 }
253 253
254 @Override 254 @Override
@@ -278,7 +278,7 @@ public class DefaultTbClusterService implements TbClusterService { @@ -278,7 +278,7 @@ public class DefaultTbClusterService implements TbClusterService {
278 broadcast(transportMsg, callback); 278 broadcast(transportMsg, callback);
279 } 279 }
280 280
281 - public <T> void onEntityChange(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) { 281 + public <T> void broadcastEntityChangeToTransport(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) {
282 String entityName = (entity instanceof HasName) ? ((HasName) entity).getName() : entity.getClass().getName(); 282 String entityName = (entity instanceof HasName) ? ((HasName) entity).getName() : entity.getClass().getName();
283 log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entityName); 283 log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entityName);
284 TransportProtos.EntityUpdateMsg entityUpdateMsg = TransportProtos.EntityUpdateMsg.newBuilder() 284 TransportProtos.EntityUpdateMsg entityUpdateMsg = TransportProtos.EntityUpdateMsg.newBuilder()
@@ -288,7 +288,7 @@ public class DefaultTbClusterService implements TbClusterService { @@ -288,7 +288,7 @@ public class DefaultTbClusterService implements TbClusterService {
288 broadcast(transportMsg, callback); 288 broadcast(transportMsg, callback);
289 } 289 }
290 290
291 - private void onEntityDelete(TenantId tenantId, EntityId entityId, String name, TbQueueCallback callback) { 291 + private void broadcastEntityDeleteToTransport(TenantId tenantId, EntityId entityId, String name, TbQueueCallback callback) {
292 log.trace("[{}][{}][{}] Processing [{}] delete event", tenantId, entityId.getEntityType(), entityId.getId(), name); 292 log.trace("[{}][{}][{}] Processing [{}] delete event", tenantId, entityId.getEntityType(), entityId.getId(), name);
293 TransportProtos.EntityDeleteMsg entityDeleteMsg = TransportProtos.EntityDeleteMsg.newBuilder() 293 TransportProtos.EntityDeleteMsg entityDeleteMsg = TransportProtos.EntityDeleteMsg.newBuilder()
294 .setEntityType(entityId.getEntityType().name()) 294 .setEntityType(entityId.getEntityType().name())
@@ -369,4 +369,72 @@ public class DefaultTbClusterService implements TbClusterService { @@ -369,4 +369,72 @@ public class DefaultTbClusterService implements TbClusterService {
369 } 369 }
370 } 370 }
371 } 371 }
  372 +
  373 + private void sendDeviceStateServiceEvent(TenantId tenantId, DeviceId deviceId, boolean added, boolean updated, boolean deleted) {
  374 + TransportProtos.DeviceStateServiceMsgProto.Builder builder = TransportProtos.DeviceStateServiceMsgProto.newBuilder();
  375 + builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
  376 + builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
  377 + builder.setDeviceIdMSB(deviceId.getId().getMostSignificantBits());
  378 + builder.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits());
  379 + builder.setAdded(added);
  380 + builder.setUpdated(updated);
  381 + builder.setDeleted(deleted);
  382 + TransportProtos.DeviceStateServiceMsgProto msg = builder.build();
  383 + pushMsgToCore(tenantId, deviceId, TransportProtos.ToCoreMsg.newBuilder().setDeviceStateServiceMsg(msg).build(), null);
  384 + }
  385 +
  386 + @Override
  387 + public void onDeviceUpdated(Device device, Device old) {
  388 + var created = old == null;
  389 + broadcastEntityChangeToTransport(device.getTenantId(), device.getId(), device, null);
  390 + if (old != null && (!device.getName().equals(old.getName()) || !device.getType().equals(old.getType()))) {
  391 + pushMsgToCore(new DeviceNameOrTypeUpdateMsg(device.getTenantId(), device.getId(), device.getName(), device.getType()), null);
  392 + }
  393 + broadcastEntityStateChangeEvent(device.getTenantId(), device.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
  394 + sendDeviceStateServiceEvent(device.getTenantId(), device.getId(), created, !created, false);
  395 + otaPackageStateService.update(device, old);
  396 + if (!created) {
  397 + sendNotificationMsgToEdgeService(device.getTenantId(), null, device.getId(), null, null, EdgeEventActionType.UPDATED);
  398 + }
  399 + }
  400 +
  401 + @Override
  402 + public void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) {
  403 + if (!edgesEnabled) {
  404 + return;
  405 + }
  406 + if (type == null) {
  407 + if (entityId != null) {
  408 + type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
  409 + } else {
  410 + log.trace("[{}] entity id and type are null. Ignoring this notification", tenantId);
  411 + return;
  412 + }
  413 + if (type == null) {
  414 + log.trace("[{}] edge event type is null. Ignoring this notification [{}]", tenantId, entityId);
  415 + return;
  416 + }
  417 + }
  418 + TransportProtos.EdgeNotificationMsgProto.Builder builder = TransportProtos.EdgeNotificationMsgProto.newBuilder();
  419 + builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
  420 + builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
  421 + builder.setType(type.name());
  422 + builder.setAction(action.name());
  423 + if (entityId != null) {
  424 + builder.setEntityIdMSB(entityId.getId().getMostSignificantBits());
  425 + builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits());
  426 + builder.setEntityType(entityId.getEntityType().name());
  427 + }
  428 + if (edgeId != null) {
  429 + builder.setEdgeIdMSB(edgeId.getId().getMostSignificantBits());
  430 + builder.setEdgeIdLSB(edgeId.getId().getLeastSignificantBits());
  431 + }
  432 + if (body != null) {
  433 + builder.setBody(body);
  434 + }
  435 + TransportProtos.EdgeNotificationMsgProto msg = builder.build();
  436 + log.trace("[{}] sending notification to edge service {}", tenantId.getId(), msg);
  437 + pushMsgToCore(tenantId, entityId != null ? entityId : tenantId, TransportProtos.ToCoreMsg.newBuilder().setEdgeNotificationMsg(msg).build(), null);
  438 + }
  439 +
372 } 440 }
@@ -26,7 +26,7 @@ import org.springframework.scheduling.annotation.Scheduled; @@ -26,7 +26,7 @@ import org.springframework.scheduling.annotation.Scheduled;
26 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
27 import org.thingsboard.common.util.JacksonUtil; 27 import org.thingsboard.common.util.JacksonUtil;
28 import org.thingsboard.common.util.ThingsBoardThreadFactory; 28 import org.thingsboard.common.util.ThingsBoardThreadFactory;
29 -import org.thingsboard.rule.engine.api.RpcError; 29 +import org.thingsboard.server.common.data.rpc.RpcError;
30 import org.thingsboard.server.actors.ActorSystemContext; 30 import org.thingsboard.server.actors.ActorSystemContext;
31 import org.thingsboard.server.common.data.alarm.Alarm; 31 import org.thingsboard.server.common.data.alarm.Alarm;
32 import org.thingsboard.server.common.data.id.TenantId; 32 import org.thingsboard.server.common.data.id.TenantId;
@@ -64,7 +64,7 @@ import org.thingsboard.server.service.ota.OtaPackageStateService; @@ -64,7 +64,7 @@ import org.thingsboard.server.service.ota.OtaPackageStateService;
64 import org.thingsboard.server.service.profile.TbDeviceProfileCache; 64 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
65 import org.thingsboard.server.service.queue.processing.AbstractConsumerService; 65 import org.thingsboard.server.service.queue.processing.AbstractConsumerService;
66 import org.thingsboard.server.service.queue.processing.IdMsgPair; 66 import org.thingsboard.server.service.queue.processing.IdMsgPair;
67 -import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 67 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
68 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; 68 import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;
69 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 69 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
70 import org.thingsboard.server.service.state.DeviceStateService; 70 import org.thingsboard.server.service.state.DeviceStateService;
@@ -21,7 +21,7 @@ import org.springframework.beans.factory.annotation.Value; @@ -21,7 +21,7 @@ import org.springframework.beans.factory.annotation.Value;
21 import org.springframework.scheduling.annotation.Scheduled; 21 import org.springframework.scheduling.annotation.Scheduled;
22 import org.springframework.stereotype.Service; 22 import org.springframework.stereotype.Service;
23 import org.thingsboard.common.util.ThingsBoardThreadFactory; 23 import org.thingsboard.common.util.ThingsBoardThreadFactory;
24 -import org.thingsboard.rule.engine.api.RpcError; 24 +import org.thingsboard.server.common.data.rpc.RpcError;
25 import org.thingsboard.server.actors.ActorSystemContext; 25 import org.thingsboard.server.actors.ActorSystemContext;
26 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.common.msg.TbMsg; 27 import org.thingsboard.server.common.msg.TbMsg;
@@ -55,7 +55,7 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStr @@ -55,7 +55,7 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStr
55 import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategyFactory; 55 import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategyFactory;
56 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; 56 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy;
57 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; 57 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory;
58 -import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 58 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
59 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; 59 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
60 import org.thingsboard.server.service.stats.RuleEngineStatisticsService; 60 import org.thingsboard.server.service.stats.RuleEngineStatisticsService;
61 61
@@ -22,18 +22,19 @@ import lombok.extern.slf4j.Slf4j; @@ -22,18 +22,19 @@ import lombok.extern.slf4j.Slf4j;
22 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
23 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
24 import org.thingsboard.common.util.ThingsBoardThreadFactory; 24 import org.thingsboard.common.util.ThingsBoardThreadFactory;
25 -import org.thingsboard.rule.engine.api.RpcError; 25 +import org.thingsboard.server.common.data.rpc.RpcError;
26 import org.thingsboard.server.actors.ActorSystemContext; 26 import org.thingsboard.server.actors.ActorSystemContext;
27 import org.thingsboard.server.common.data.DataConstants; 27 import org.thingsboard.server.common.data.DataConstants;
28 import org.thingsboard.server.common.data.Device; 28 import org.thingsboard.server.common.data.Device;
29 import org.thingsboard.server.common.msg.TbMsg; 29 import org.thingsboard.server.common.msg.TbMsg;
30 import org.thingsboard.server.common.msg.TbMsgDataType; 30 import org.thingsboard.server.common.msg.TbMsgDataType;
31 import org.thingsboard.server.common.msg.TbMsgMetaData; 31 import org.thingsboard.server.common.msg.TbMsgMetaData;
  32 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
32 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 33 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
33 import org.thingsboard.server.dao.device.DeviceService; 34 import org.thingsboard.server.dao.device.DeviceService;
34 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; 35 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
35 import org.thingsboard.server.queue.util.TbCoreComponent; 36 import org.thingsboard.server.queue.util.TbCoreComponent;
36 -import org.thingsboard.server.service.queue.TbClusterService; 37 +import org.thingsboard.server.cluster.TbClusterService;
37 import org.thingsboard.server.service.security.model.SecurityUser; 38 import org.thingsboard.server.service.security.model.SecurityUser;
38 39
39 import javax.annotation.PostConstruct; 40 import javax.annotation.PostConstruct;
@@ -138,6 +139,12 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -138,6 +139,12 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
138 } 139 }
139 } 140 }
140 141
  142 + @Override
  143 + public void processRemoveRpc(RemoveRpcActorMsg removeRpcMsg) {
  144 + log.trace("[{}][{}] Processing remove RPC [{}]", removeRpcMsg.getTenantId(), removeRpcMsg.getRequestId(), removeRpcMsg.getDeviceId());
  145 + actorContext.tellWithHighPriority(removeRpcMsg);
  146 + }
  147 +
141 private void sendRpcResponseToTbRuleEngine(String originServiceId, FromDeviceRpcResponse response) { 148 private void sendRpcResponseToTbRuleEngine(String originServiceId, FromDeviceRpcResponse response) {
142 if (serviceId.equals(originServiceId)) { 149 if (serviceId.equals(originServiceId)) {
143 if (tbRuleEngineRpcService.isPresent()) { 150 if (tbRuleEngineRpcService.isPresent()) {
@@ -168,6 +175,8 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -168,6 +175,8 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
168 entityNode.put("method", msg.getBody().getMethod()); 175 entityNode.put("method", msg.getBody().getMethod());
169 entityNode.put("params", msg.getBody().getParams()); 176 entityNode.put("params", msg.getBody().getParams());
170 177
  178 + entityNode.put(DataConstants.ADDITIONAL_INFO, msg.getAdditionalInfo());
  179 +
171 try { 180 try {
172 TbMsg tbMsg = TbMsg.newMsg(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), currentUser.getCustomerId(), metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode)); 181 TbMsg tbMsg = TbMsg.newMsg(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE, msg.getDeviceId(), currentUser.getCustomerId(), metaData, TbMsgDataType.JSON, json.writeValueAsString(entityNode));
173 clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null); 182 clusterService.pushMsgToRuleEngine(msg.getTenantId(), msg.getDeviceId(), tbMsg, null);
@@ -19,18 +19,19 @@ import lombok.extern.slf4j.Slf4j; @@ -19,18 +19,19 @@ import lombok.extern.slf4j.Slf4j;
19 import org.springframework.beans.factory.annotation.Autowired; 19 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
21 import org.thingsboard.common.util.ThingsBoardThreadFactory; 21 import org.thingsboard.common.util.ThingsBoardThreadFactory;
22 -import org.thingsboard.rule.engine.api.RpcError; 22 +import org.thingsboard.server.common.data.rpc.RpcError;
23 import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest; 23 import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest;
24 import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse; 24 import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse;
25 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; 25 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
26 import org.thingsboard.server.common.msg.queue.ServiceType; 26 import org.thingsboard.server.common.msg.queue.ServiceType;
27 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 27 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
  28 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
28 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 29 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
29 import org.thingsboard.server.gen.transport.TransportProtos; 30 import org.thingsboard.server.gen.transport.TransportProtos;
30 import org.thingsboard.server.queue.discovery.PartitionService; 31 import org.thingsboard.server.queue.discovery.PartitionService;
31 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; 32 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
32 import org.thingsboard.server.queue.util.TbRuleEngineComponent; 33 import org.thingsboard.server.queue.util.TbRuleEngineComponent;
33 -import org.thingsboard.server.service.queue.TbClusterService; 34 +import org.thingsboard.server.cluster.TbClusterService;
34 35
35 import javax.annotation.PostConstruct; 36 import javax.annotation.PostConstruct;
36 import javax.annotation.PreDestroy; 37 import javax.annotation.PreDestroy;
@@ -100,7 +101,7 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi @@ -100,7 +101,7 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi
100 @Override 101 @Override
101 public void sendRpcRequestToDevice(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) { 102 public void sendRpcRequestToDevice(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) {
102 ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), src.getTenantId(), src.getDeviceId(), 103 ToDeviceRpcRequest request = new ToDeviceRpcRequest(src.getRequestUUID(), src.getTenantId(), src.getDeviceId(),
103 - src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody()), src.isPersisted()); 104 + src.isOneway(), src.getExpirationTime(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody()), src.isPersisted(), src.getAdditionalInfo());
104 forwardRpcRequestToDeviceActor(request, response -> { 105 forwardRpcRequestToDeviceActor(request, response -> {
105 if (src.isRestApiCall()) { 106 if (src.isRestApiCall()) {
106 sendRpcResponseToTbCore(src.getOriginServiceId(), response); 107 sendRpcResponseToTbCore(src.getOriginServiceId(), response);
@@ -18,10 +18,11 @@ package org.thingsboard.server.service.rpc; @@ -18,10 +18,11 @@ package org.thingsboard.server.service.rpc;
18 import lombok.Getter; 18 import lombok.Getter;
19 import lombok.RequiredArgsConstructor; 19 import lombok.RequiredArgsConstructor;
20 import lombok.ToString; 20 import lombok.ToString;
21 -import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 21 +import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
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.MsgType; 24 import org.thingsboard.server.common.msg.MsgType;
  25 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
25 26
26 @ToString 27 @ToString
27 @RequiredArgsConstructor 28 @RequiredArgsConstructor
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.rpc;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.RequiredArgsConstructor;
  20 +import lombok.ToString;
  21 +import org.thingsboard.server.common.data.id.DeviceId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.common.msg.MsgType;
  24 +import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
  25 +
  26 +import java.util.UUID;
  27 +
  28 +@ToString
  29 +@RequiredArgsConstructor
  30 +public class RemoveRpcActorMsg implements ToDeviceActorNotificationMsg {
  31 +
  32 + @Getter
  33 + private final TenantId tenantId;
  34 + @Getter
  35 + private final DeviceId deviceId;
  36 +
  37 + @Getter
  38 + private final UUID requestId;
  39 +
  40 + @Override
  41 + public MsgType getMsgType() {
  42 + return MsgType.REMOVE_RPC_TO_DEVICE_ACTOR_MSG;
  43 + }
  44 +}
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.service.rpc; 16 package org.thingsboard.server.service.rpc;
17 17
  18 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
18 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 19 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
19 import org.thingsboard.server.service.security.model.SecurityUser; 20 import org.thingsboard.server.service.security.model.SecurityUser;
20 21
@@ -55,4 +56,6 @@ public interface TbCoreDeviceRpcService { @@ -55,4 +56,6 @@ public interface TbCoreDeviceRpcService {
55 */ 56 */
56 void processRpcResponseFromDeviceActor(FromDeviceRpcResponse response); 57 void processRpcResponseFromDeviceActor(FromDeviceRpcResponse response);
57 58
  59 + void processRemoveRpc(RemoveRpcActorMsg removeRpcMsg);
  60 +
58 } 61 }
@@ -31,7 +31,7 @@ import org.thingsboard.server.common.msg.TbMsg; @@ -31,7 +31,7 @@ import org.thingsboard.server.common.msg.TbMsg;
31 import org.thingsboard.server.common.msg.TbMsgMetaData; 31 import org.thingsboard.server.common.msg.TbMsgMetaData;
32 import org.thingsboard.server.dao.rpc.RpcService; 32 import org.thingsboard.server.dao.rpc.RpcService;
33 import org.thingsboard.server.queue.util.TbCoreComponent; 33 import org.thingsboard.server.queue.util.TbCoreComponent;
34 -import org.thingsboard.server.service.queue.TbClusterService; 34 +import org.thingsboard.server.cluster.TbClusterService;
35 35
36 @TbCoreComponent 36 @TbCoreComponent
37 @Service 37 @Service
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.service.rpc; 16 package org.thingsboard.server.service.rpc;
17 17
18 import org.thingsboard.rule.engine.api.RuleEngineRpcService; 18 import org.thingsboard.rule.engine.api.RuleEngineRpcService;
  19 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
19 20
20 /** 21 /**
21 * Created by ashvayka on 16.04.18. 22 * Created by ashvayka on 16.04.18.
@@ -18,7 +18,7 @@ package org.thingsboard.server.service.rpc; @@ -18,7 +18,7 @@ package org.thingsboard.server.service.rpc;
18 import lombok.Getter; 18 import lombok.Getter;
19 import lombok.RequiredArgsConstructor; 19 import lombok.RequiredArgsConstructor;
20 import lombok.ToString; 20 import lombok.ToString;
21 -import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 21 +import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
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.MsgType; 24 import org.thingsboard.server.common.msg.MsgType;
@@ -47,7 +47,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @@ -47,7 +47,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
47 import org.thingsboard.server.dao.tenant.TenantService; 47 import org.thingsboard.server.dao.tenant.TenantService;
48 import org.thingsboard.server.dao.user.UserService; 48 import org.thingsboard.server.dao.user.UserService;
49 import org.thingsboard.server.service.install.InstallScripts; 49 import org.thingsboard.server.service.install.InstallScripts;
50 -import org.thingsboard.server.service.queue.TbClusterService; 50 +import org.thingsboard.server.cluster.TbClusterService;
51 import org.thingsboard.server.service.security.model.SecurityUser; 51 import org.thingsboard.server.service.security.model.SecurityUser;
52 import org.thingsboard.server.service.security.model.UserPrincipal; 52 import org.thingsboard.server.service.security.model.UserPrincipal;
53 53
@@ -180,7 +180,7 @@ public abstract class AbstractOAuth2ClientMapper { @@ -180,7 +180,7 @@ public abstract class AbstractOAuth2ClientMapper {
180 installScripts.createDefaultEdgeRuleChains(tenant.getId()); 180 installScripts.createDefaultEdgeRuleChains(tenant.getId());
181 tenantProfileCache.evict(tenant.getId()); 181 tenantProfileCache.evict(tenant.getId());
182 tbClusterService.onTenantChange(tenant, null); 182 tbClusterService.onTenantChange(tenant, null);
183 - tbClusterService.onEntityStateChange(tenant.getId(), tenant.getId(), 183 + tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(),
184 ComponentLifecycleEvent.CREATED); 184 ComponentLifecycleEvent.CREATED);
185 } else { 185 } else {
186 tenant = tenants.get(0); 186 tenant = tenants.get(0);
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.security.auth.oauth2; @@ -17,6 +17,7 @@ package org.thingsboard.server.service.security.auth.oauth2;
17 17
18 import com.fasterxml.jackson.core.JsonProcessingException; 18 import com.fasterxml.jackson.core.JsonProcessingException;
19 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
  20 +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
20 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.boot.web.client.RestTemplateBuilder; 22 import org.springframework.boot.web.client.RestTemplateBuilder;
22 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; 23 import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
@@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.oauth2.OAuth2Registration; @@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.oauth2.OAuth2Registration;
29 import org.thingsboard.server.dao.oauth2.OAuth2User; 30 import org.thingsboard.server.dao.oauth2.OAuth2User;
30 import org.thingsboard.server.service.security.model.SecurityUser; 31 import org.thingsboard.server.service.security.model.SecurityUser;
31 32
  33 +import javax.annotation.PostConstruct;
32 import javax.servlet.http.HttpServletRequest; 34 import javax.servlet.http.HttpServletRequest;
33 35
34 @Service(value = "customOAuth2ClientMapper") 36 @Service(value = "customOAuth2ClientMapper")
@@ -40,6 +42,15 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme @@ -40,6 +42,15 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme
40 42
41 private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder(); 43 private RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
42 44
  45 + @PostConstruct
  46 + public void init() {
  47 + // Register time module to parse Instant objects.
  48 + // com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
  49 + // Java 8 date/time type `java.time.Instant` not supported by default:
  50 + // add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling
  51 + json.registerModule(new JavaTimeModule());
  52 + }
  53 +
43 @Override 54 @Override
44 public SecurityUser getOrCreateUserByClientPrincipal(HttpServletRequest request, OAuth2AuthenticationToken token, String providerAccessToken, OAuth2Registration registration) { 55 public SecurityUser getOrCreateUserByClientPrincipal(HttpServletRequest request, OAuth2AuthenticationToken token, String providerAccessToken, OAuth2Registration registration) {
45 OAuth2MapperConfig config = registration.getMapperConfig(); 56 OAuth2MapperConfig config = registration.getMapperConfig();
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.service.security.auth.oauth2; 16 package org.thingsboard.server.service.security.auth.oauth2;
17 17
  18 +import lombok.extern.slf4j.Slf4j;
18 import org.springframework.beans.factory.annotation.Autowired; 19 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.security.core.Authentication; 20 import org.springframework.security.core.Authentication;
20 import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; 21 import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
@@ -42,6 +43,7 @@ import java.net.URLEncoder; @@ -42,6 +43,7 @@ import java.net.URLEncoder;
42 import java.nio.charset.StandardCharsets; 43 import java.nio.charset.StandardCharsets;
43 import java.util.UUID; 44 import java.util.UUID;
44 45
  46 +@Slf4j
45 @Component(value = "oauth2AuthenticationSuccessHandler") 47 @Component(value = "oauth2AuthenticationSuccessHandler")
46 public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { 48 public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
47 49
@@ -99,6 +101,8 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS @@ -99,6 +101,8 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
99 clearAuthenticationAttributes(request, response); 101 clearAuthenticationAttributes(request, response);
100 getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken()); 102 getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken());
101 } catch (Exception e) { 103 } catch (Exception e) {
  104 + log.debug("Error occurred during processing authentication success result. " +
  105 + "request [{}], response [{}], authentication [{}]", request, response, authentication, e);
102 clearAuthenticationAttributes(request, response); 106 clearAuthenticationAttributes(request, response);
103 String errorPrefix; 107 String errorPrefix;
104 if (!StringUtils.isEmpty(callbackUrlScheme)) { 108 if (!StringUtils.isEmpty(callbackUrlScheme)) {
@@ -22,7 +22,6 @@ import com.google.common.util.concurrent.Futures; @@ -22,7 +22,6 @@ import com.google.common.util.concurrent.Futures;
22 import com.google.common.util.concurrent.ListenableFuture; 22 import com.google.common.util.concurrent.ListenableFuture;
23 import com.google.common.util.concurrent.ListeningScheduledExecutorService; 23 import com.google.common.util.concurrent.ListeningScheduledExecutorService;
24 import com.google.common.util.concurrent.MoreExecutors; 24 import com.google.common.util.concurrent.MoreExecutors;
25 -import com.google.common.util.concurrent.SettableFuture;  
26 import lombok.Getter; 25 import lombok.Getter;
27 import lombok.extern.slf4j.Slf4j; 26 import lombok.extern.slf4j.Slf4j;
28 import org.springframework.beans.factory.annotation.Autowired; 27 import org.springframework.beans.factory.annotation.Autowired;
@@ -59,7 +58,7 @@ import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; @@ -59,7 +58,7 @@ import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
59 import org.thingsboard.server.queue.discovery.PartitionService; 58 import org.thingsboard.server.queue.discovery.PartitionService;
60 import org.thingsboard.server.queue.discovery.TbApplicationEventListener; 59 import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
61 import org.thingsboard.server.queue.util.TbCoreComponent; 60 import org.thingsboard.server.queue.util.TbCoreComponent;
62 -import org.thingsboard.server.service.queue.TbClusterService; 61 +import org.thingsboard.server.cluster.TbClusterService;
63 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; 62 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
64 63
65 import javax.annotation.Nonnull; 64 import javax.annotation.Nonnull;
@@ -71,7 +70,6 @@ import java.util.Arrays; @@ -71,7 +70,6 @@ import java.util.Arrays;
71 import java.util.Collections; 70 import java.util.Collections;
72 import java.util.HashSet; 71 import java.util.HashSet;
73 import java.util.List; 72 import java.util.List;
74 -import java.util.Optional;  
75 import java.util.Queue; 73 import java.util.Queue;
76 import java.util.Random; 74 import java.util.Random;
77 import java.util.Set; 75 import java.util.Set;
@@ -137,7 +135,6 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -137,7 +135,6 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
137 private ExecutorService deviceStateExecutor; 135 private ExecutorService deviceStateExecutor;
138 private final ConcurrentMap<TopicPartitionInfo, Set<DeviceId>> partitionedDevices = new ConcurrentHashMap<>(); 136 private final ConcurrentMap<TopicPartitionInfo, Set<DeviceId>> partitionedDevices = new ConcurrentHashMap<>();
139 final ConcurrentMap<DeviceId, DeviceStateData> deviceStates = new ConcurrentHashMap<>(); 137 final ConcurrentMap<DeviceId, DeviceStateData> deviceStates = new ConcurrentHashMap<>();
140 - private final ConcurrentMap<DeviceId, Long> deviceLastSavedActivity = new ConcurrentHashMap<>();  
141 138
142 final Queue<Set<TopicPartitionInfo>> subscribeQueue = new ConcurrentLinkedQueue<>(); 139 final Queue<Set<TopicPartitionInfo>> subscribeQueue = new ConcurrentLinkedQueue<>();
143 140
@@ -177,22 +174,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -177,22 +174,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
177 } 174 }
178 175
179 @Override 176 @Override
180 - public void onDeviceAdded(Device device) {  
181 - sendDeviceEvent(device.getTenantId(), device.getId(), true, false, false);  
182 - }  
183 -  
184 - @Override  
185 - public void onDeviceUpdated(Device device) {  
186 - sendDeviceEvent(device.getTenantId(), device.getId(), false, true, false);  
187 - }  
188 -  
189 - @Override  
190 - public void onDeviceDeleted(Device device) {  
191 - sendDeviceEvent(device.getTenantId(), device.getId(), false, false, true);  
192 - }  
193 -  
194 - @Override  
195 - public void onDeviceConnect(DeviceId deviceId) { 177 + public void onDeviceConnect(TenantId tenantId, DeviceId deviceId) {
196 log.trace("on Device Connect [{}]", deviceId.getId()); 178 log.trace("on Device Connect [{}]", deviceId.getId());
197 DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); 179 DeviceStateData stateData = getOrFetchDeviceStateData(deviceId);
198 long ts = System.currentTimeMillis(); 180 long ts = System.currentTimeMillis();
@@ -200,23 +182,23 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -200,23 +182,23 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
200 save(deviceId, LAST_CONNECT_TIME, ts); 182 save(deviceId, LAST_CONNECT_TIME, ts);
201 pushRuleEngineMessage(stateData, CONNECT_EVENT); 183 pushRuleEngineMessage(stateData, CONNECT_EVENT);
202 checkAndUpdateState(deviceId, stateData); 184 checkAndUpdateState(deviceId, stateData);
  185 + cleanDeviceStateIfBelongsExternalPartition(tenantId, deviceId);
203 } 186 }
204 187
205 @Override 188 @Override
206 - public void onDeviceActivity(DeviceId deviceId, long lastReportedActivity) { 189 + public void onDeviceActivity(TenantId tenantId, DeviceId deviceId, long lastReportedActivity) {
207 log.trace("on Device Activity [{}], lastReportedActivity [{}]", deviceId.getId(), lastReportedActivity); 190 log.trace("on Device Activity [{}], lastReportedActivity [{}]", deviceId.getId(), lastReportedActivity);
208 - long lastSavedActivity = deviceLastSavedActivity.getOrDefault(deviceId, 0L);  
209 - if (lastReportedActivity > 0 && lastReportedActivity > lastSavedActivity) {  
210 - final DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); 191 + final DeviceStateData stateData = getOrFetchDeviceStateData(deviceId);
  192 + if (lastReportedActivity > 0 && lastReportedActivity > stateData.getState().getLastActivityTime()) {
211 updateActivityState(deviceId, stateData, lastReportedActivity); 193 updateActivityState(deviceId, stateData, lastReportedActivity);
212 } 194 }
  195 + cleanDeviceStateIfBelongsExternalPartition(tenantId, deviceId);
213 } 196 }
214 197
215 void updateActivityState(DeviceId deviceId, DeviceStateData stateData, long lastReportedActivity) { 198 void updateActivityState(DeviceId deviceId, DeviceStateData stateData, long lastReportedActivity) {
216 log.trace("updateActivityState - fetched state {} for device {}, lastReportedActivity {}", stateData, deviceId, lastReportedActivity); 199 log.trace("updateActivityState - fetched state {} for device {}, lastReportedActivity {}", stateData, deviceId, lastReportedActivity);
217 if (stateData != null) { 200 if (stateData != null) {
218 save(deviceId, LAST_ACTIVITY_TIME, lastReportedActivity); 201 save(deviceId, LAST_ACTIVITY_TIME, lastReportedActivity);
219 - deviceLastSavedActivity.put(deviceId, lastReportedActivity);  
220 DeviceState state = stateData.getState(); 202 DeviceState state = stateData.getState();
221 state.setLastActivityTime(lastReportedActivity); 203 state.setLastActivityTime(lastReportedActivity);
222 if (!state.isActive()) { 204 if (!state.isActive()) {
@@ -225,21 +207,23 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -225,21 +207,23 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
225 pushRuleEngineMessage(stateData, ACTIVITY_EVENT); 207 pushRuleEngineMessage(stateData, ACTIVITY_EVENT);
226 } 208 }
227 } else { 209 } else {
228 - log.warn("updateActivityState - fetched state IN NULL for device {}, lastReportedActivity {}", deviceId, lastReportedActivity); 210 + log.debug("updateActivityState - fetched state IN NULL for device {}, lastReportedActivity {}", deviceId, lastReportedActivity);
  211 + cleanUpDeviceStateMap(deviceId);
229 } 212 }
230 } 213 }
231 214
232 @Override 215 @Override
233 - public void onDeviceDisconnect(DeviceId deviceId) { 216 + public void onDeviceDisconnect(TenantId tenantId, DeviceId deviceId) {
234 DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); 217 DeviceStateData stateData = getOrFetchDeviceStateData(deviceId);
235 long ts = System.currentTimeMillis(); 218 long ts = System.currentTimeMillis();
236 stateData.getState().setLastDisconnectTime(ts); 219 stateData.getState().setLastDisconnectTime(ts);
237 save(deviceId, LAST_DISCONNECT_TIME, ts); 220 save(deviceId, LAST_DISCONNECT_TIME, ts);
238 pushRuleEngineMessage(stateData, DISCONNECT_EVENT); 221 pushRuleEngineMessage(stateData, DISCONNECT_EVENT);
  222 + cleanDeviceStateIfBelongsExternalPartition(tenantId, deviceId);
239 } 223 }
240 224
241 @Override 225 @Override
242 - public void onDeviceInactivityTimeoutUpdate(DeviceId deviceId, long inactivityTimeout) { 226 + public void onDeviceInactivityTimeoutUpdate(TenantId tenantId, DeviceId deviceId, long inactivityTimeout) {
243 if (inactivityTimeout <= 0L) { 227 if (inactivityTimeout <= 0L) {
244 return; 228 return;
245 } 229 }
@@ -247,6 +231,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -247,6 +231,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
247 DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); 231 DeviceStateData stateData = getOrFetchDeviceStateData(deviceId);
248 stateData.getState().setInactivityTimeout(inactivityTimeout); 232 stateData.getState().setInactivityTimeout(inactivityTimeout);
249 checkAndUpdateState(deviceId, stateData); 233 checkAndUpdateState(deviceId, stateData);
  234 + cleanDeviceStateIfBelongsExternalPartition(tenantId, deviceId);
250 } 235 }
251 236
252 @Override 237 @Override
@@ -267,6 +252,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -267,6 +252,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
267 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, device.getId()); 252 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, device.getId());
268 if (partitionedDevices.containsKey(tpi)) { 253 if (partitionedDevices.containsKey(tpi)) {
269 addDeviceUsingState(tpi, state); 254 addDeviceUsingState(tpi, state);
  255 + save(deviceId, ACTIVITY_STATE, false);
270 callback.onSuccess(); 256 callback.onSuccess();
271 } else { 257 } else {
272 log.warn("[{}][{}] Device belongs to external partition. Probably rebalancing is in progress. Topic: {}" 258 log.warn("[{}][{}] Device belongs to external partition. Probably rebalancing is in progress. Topic: {}"
@@ -283,12 +269,11 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -283,12 +269,11 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
283 }, deviceStateExecutor); 269 }, deviceStateExecutor);
284 } else if (proto.getUpdated()) { 270 } else if (proto.getUpdated()) {
285 DeviceStateData stateData = getOrFetchDeviceStateData(device.getId()); 271 DeviceStateData stateData = getOrFetchDeviceStateData(device.getId());
286 - if (stateData != null) {  
287 - TbMsgMetaData md = new TbMsgMetaData();  
288 - md.putValue("deviceName", device.getName());  
289 - md.putValue("deviceType", device.getType());  
290 - stateData.setMetaData(md);  
291 - } 272 + TbMsgMetaData md = new TbMsgMetaData();
  273 + md.putValue("deviceName", device.getName());
  274 + md.putValue("deviceType", device.getType());
  275 + stateData.setMetaData(md);
  276 + callback.onSuccess();
292 } 277 }
293 } else { 278 } else {
294 //Device was probably deleted while message was in queue; 279 //Device was probably deleted while message was in queue;
@@ -356,10 +341,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -356,10 +341,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
356 // We no longer manage current partition of devices; 341 // We no longer manage current partition of devices;
357 removedPartitions.forEach(partition -> { 342 removedPartitions.forEach(partition -> {
358 Set<DeviceId> devices = partitionedDevices.remove(partition); 343 Set<DeviceId> devices = partitionedDevices.remove(partition);
359 - devices.forEach(deviceId -> {  
360 - deviceStates.remove(deviceId);  
361 - deviceLastSavedActivity.remove(deviceId);  
362 - }); 344 + devices.forEach(this::cleanUpDeviceStateMap);
363 }); 345 });
364 346
365 addedPartitions.forEach(tpi -> partitionedDevices.computeIfAbsent(tpi, key -> ConcurrentHashMap.newKeySet())); 347 addedPartitions.forEach(tpi -> partitionedDevices.computeIfAbsent(tpi, key -> ConcurrentHashMap.newKeySet()));
@@ -457,17 +439,18 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -457,17 +439,18 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
457 deviceStates.put(state.getDeviceId(), state); 439 deviceStates.put(state.getDeviceId(), state);
458 } else { 440 } else {
459 log.warn("Device belongs to external partition {}" + tpi.getFullTopicName()); 441 log.warn("Device belongs to external partition {}" + tpi.getFullTopicName());
460 - new RuntimeException("Device belongs to external partition " + tpi.getFullTopicName() + "!"); 442 + throw new RuntimeException("Device belongs to external partition " + tpi.getFullTopicName() + "!");
461 } 443 }
462 } 444 }
463 445
464 void updateInactivityStateIfExpired() { 446 void updateInactivityStateIfExpired() {
465 final long ts = System.currentTimeMillis(); 447 final long ts = System.currentTimeMillis();
466 - log.debug("Calculating state updates for {} devices", deviceStates.size());  
467 - Set<DeviceId> deviceIds = new HashSet<>(deviceStates.keySet());  
468 - for (DeviceId deviceId : deviceIds) {  
469 - updateInactivityStateIfExpired(ts, deviceId);  
470 - } 448 + partitionedDevices.forEach((tpi, deviceIds) -> {
  449 + log.debug("Calculating state updates. tpi {} for {} devices", tpi.getFullTopicName(), deviceIds.size());
  450 + for (DeviceId deviceId : deviceIds) {
  451 + updateInactivityStateIfExpired(ts, deviceId);
  452 + }
  453 + });
471 } 454 }
472 455
473 void updateInactivityStateIfExpired(long ts, DeviceId deviceId) { 456 void updateInactivityStateIfExpired(long ts, DeviceId deviceId) {
@@ -488,8 +471,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -488,8 +471,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
488 } 471 }
489 } else { 472 } else {
490 log.debug("[{}] Device that belongs to other server is detected and removed.", deviceId); 473 log.debug("[{}] Device that belongs to other server is detected and removed.", deviceId);
491 - deviceStates.remove(deviceId);  
492 - deviceLastSavedActivity.remove(deviceId); 474 + cleanUpDeviceStateMap(deviceId);
493 } 475 }
494 } 476 }
495 477
@@ -522,27 +504,26 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -522,27 +504,26 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
522 } 504 }
523 } 505 }
524 506
525 - private void sendDeviceEvent(TenantId tenantId, DeviceId deviceId, boolean added, boolean updated, boolean deleted) {  
526 - TransportProtos.DeviceStateServiceMsgProto.Builder builder = TransportProtos.DeviceStateServiceMsgProto.newBuilder();  
527 - builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());  
528 - builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());  
529 - builder.setDeviceIdMSB(deviceId.getId().getMostSignificantBits());  
530 - builder.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits());  
531 - builder.setAdded(added);  
532 - builder.setUpdated(updated);  
533 - builder.setDeleted(deleted);  
534 - TransportProtos.DeviceStateServiceMsgProto msg = builder.build();  
535 - clusterService.pushMsgToCore(tenantId, deviceId, TransportProtos.ToCoreMsg.newBuilder().setDeviceStateServiceMsg(msg).build(), null); 507 + private void cleanDeviceStateIfBelongsExternalPartition(TenantId tenantId, final DeviceId deviceId) {
  508 + TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId);
  509 + if (!partitionedDevices.containsKey(tpi)) {
  510 + cleanUpDeviceStateMap(deviceId);
  511 + log.debug("[{}][{}] device belongs to external partition. Probably rebalancing is in progress. Topic: {}"
  512 + , tenantId, deviceId, tpi.getFullTopicName());
  513 + }
536 } 514 }
537 515
538 private void onDeviceDeleted(TenantId tenantId, DeviceId deviceId) { 516 private void onDeviceDeleted(TenantId tenantId, DeviceId deviceId) {
539 - deviceStates.remove(deviceId);  
540 - deviceLastSavedActivity.remove(deviceId); 517 + cleanUpDeviceStateMap(deviceId);
541 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId); 518 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId);
542 Set<DeviceId> deviceIdSet = partitionedDevices.get(tpi); 519 Set<DeviceId> deviceIdSet = partitionedDevices.get(tpi);
543 deviceIdSet.remove(deviceId); 520 deviceIdSet.remove(deviceId);
544 } 521 }
545 522
  523 + private void cleanUpDeviceStateMap(DeviceId deviceId) {
  524 + deviceStates.remove(deviceId);
  525 + }
  526 +
546 private ListenableFuture<DeviceStateData> fetchDeviceState(Device device) { 527 private ListenableFuture<DeviceStateData> fetchDeviceState(Device device) {
547 ListenableFuture<DeviceStateData> future; 528 ListenableFuture<DeviceStateData> future;
548 if (persistToTelemetry) { 529 if (persistToTelemetry) {
@@ -573,7 +554,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -573,7 +554,7 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
573 } 554 }
574 555
575 private <T extends KvEntry> Function<List<T>, DeviceStateData> extractDeviceStateData(Device device) { 556 private <T extends KvEntry> Function<List<T>, DeviceStateData> extractDeviceStateData(Device device) {
576 - return new Function<List<T>, DeviceStateData>() { 557 + return new Function<>() {
577 @Nonnull 558 @Nonnull
578 @Override 559 @Override
579 public DeviceStateData apply(@Nullable List<T> data) { 560 public DeviceStateData apply(@Nullable List<T> data) {
@@ -660,9 +641,9 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -660,9 +641,9 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
660 tsSubService.saveAndNotifyInternal( 641 tsSubService.saveAndNotifyInternal(
661 TenantId.SYS_TENANT_ID, deviceId, 642 TenantId.SYS_TENANT_ID, deviceId,
662 Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))), 643 Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))),
663 - new AttributeSaveCallback<>(deviceId, key, value)); 644 + new TelemetrySaveCallback<>(deviceId, key, value));
664 } else { 645 } else {
665 - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback<>(deviceId, key, value)); 646 + tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
666 } 647 }
667 } 648 }
668 649
@@ -671,18 +652,18 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit @@ -671,18 +652,18 @@ public class DefaultDeviceStateService extends TbApplicationEventListener<Partit
671 tsSubService.saveAndNotifyInternal( 652 tsSubService.saveAndNotifyInternal(
672 TenantId.SYS_TENANT_ID, deviceId, 653 TenantId.SYS_TENANT_ID, deviceId,
673 Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))), 654 Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))),
674 - new AttributeSaveCallback<>(deviceId, key, value)); 655 + new TelemetrySaveCallback<>(deviceId, key, value));
675 } else { 656 } else {
676 - tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback<>(deviceId, key, value)); 657 + tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, DataConstants.SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value));
677 } 658 }
678 } 659 }
679 660
680 - private static class AttributeSaveCallback<T> implements FutureCallback<T> { 661 + private static class TelemetrySaveCallback<T> implements FutureCallback<T> {
681 private final DeviceId deviceId; 662 private final DeviceId deviceId;
682 private final String key; 663 private final String key;
683 private final Object value; 664 private final Object value;
684 665
685 - AttributeSaveCallback(DeviceId deviceId, String key, Object value) { 666 + TelemetrySaveCallback(DeviceId deviceId, String key, Object value) {
686 this.deviceId = deviceId; 667 this.deviceId = deviceId;
687 this.key = key; 668 this.key = key;
688 this.value = value; 669 this.value = value;
@@ -18,6 +18,7 @@ package org.thingsboard.server.service.state; @@ -18,6 +18,7 @@ package org.thingsboard.server.service.state;
18 import org.springframework.context.ApplicationListener; 18 import org.springframework.context.ApplicationListener;
19 import org.thingsboard.server.common.data.Device; 19 import org.thingsboard.server.common.data.Device;
20 import org.thingsboard.server.common.data.id.DeviceId; 20 import org.thingsboard.server.common.data.id.DeviceId;
  21 +import org.thingsboard.server.common.data.id.TenantId;
21 import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; 22 import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
22 import org.thingsboard.server.gen.transport.TransportProtos; 23 import org.thingsboard.server.gen.transport.TransportProtos;
23 import org.thingsboard.server.common.msg.queue.TbCallback; 24 import org.thingsboard.server.common.msg.queue.TbCallback;
@@ -27,19 +28,13 @@ import org.thingsboard.server.common.msg.queue.TbCallback; @@ -27,19 +28,13 @@ import org.thingsboard.server.common.msg.queue.TbCallback;
27 */ 28 */
28 public interface DeviceStateService extends ApplicationListener<PartitionChangeEvent> { 29 public interface DeviceStateService extends ApplicationListener<PartitionChangeEvent> {
29 30
30 - void onDeviceAdded(Device device); 31 + void onDeviceConnect(TenantId tenantId, DeviceId deviceId);
31 32
32 - void onDeviceUpdated(Device device); 33 + void onDeviceActivity(TenantId tenantId, DeviceId deviceId, long lastReportedActivityTime);
33 34
34 - void onDeviceDeleted(Device device); 35 + void onDeviceDisconnect(TenantId tenantId, DeviceId deviceId);
35 36
36 - void onDeviceConnect(DeviceId deviceId);  
37 -  
38 - void onDeviceActivity(DeviceId deviceId, long lastReportedActivityTime);  
39 -  
40 - void onDeviceDisconnect(DeviceId deviceId);  
41 -  
42 - void onDeviceInactivityTimeoutUpdate(DeviceId deviceId, long inactivityTimeout); 37 + void onDeviceInactivityTimeoutUpdate(TenantId tenantId, DeviceId deviceId, long inactivityTimeout);
43 38
44 void onQueueMsg(TransportProtos.DeviceStateServiceMsgProto proto, TbCallback bytes); 39 void onQueueMsg(TransportProtos.DeviceStateServiceMsgProto proto, TbCallback bytes);
45 40
@@ -53,7 +53,7 @@ import org.thingsboard.server.queue.discovery.TbApplicationEventListener; @@ -53,7 +53,7 @@ import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
53 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; 53 import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
54 import org.thingsboard.server.queue.provider.TbQueueProducerProvider; 54 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
55 import org.thingsboard.server.queue.util.TbCoreComponent; 55 import org.thingsboard.server.queue.util.TbCoreComponent;
56 -import org.thingsboard.server.service.queue.TbClusterService; 56 +import org.thingsboard.server.cluster.TbClusterService;
57 import org.thingsboard.server.service.state.DefaultDeviceStateService; 57 import org.thingsboard.server.service.state.DefaultDeviceStateService;
58 import org.thingsboard.server.service.state.DeviceStateService; 58 import org.thingsboard.server.service.state.DeviceStateService;
59 import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; 59 import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate;
@@ -224,7 +224,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene @@ -224,7 +224,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
224 return subscriptionUpdate; 224 return subscriptionUpdate;
225 }); 225 });
226 if (entityId.getEntityType() == EntityType.DEVICE) { 226 if (entityId.getEntityType() == EntityType.DEVICE) {
227 - updateDeviceInactivityTimeout(entityId, ts); 227 + updateDeviceInactivityTimeout(tenantId, entityId, ts);
228 } 228 }
229 callback.onSuccess(); 229 callback.onSuccess();
230 } 230 }
@@ -259,7 +259,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene @@ -259,7 +259,7 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
259 }); 259 });
260 if (entityId.getEntityType() == EntityType.DEVICE) { 260 if (entityId.getEntityType() == EntityType.DEVICE) {
261 if (TbAttributeSubscriptionScope.SERVER_SCOPE.name().equalsIgnoreCase(scope)) { 261 if (TbAttributeSubscriptionScope.SERVER_SCOPE.name().equalsIgnoreCase(scope)) {
262 - updateDeviceInactivityTimeout(entityId, attributes); 262 + updateDeviceInactivityTimeout(tenantId, entityId, attributes);
263 } else if (TbAttributeSubscriptionScope.SHARED_SCOPE.name().equalsIgnoreCase(scope) && notifyDevice) { 263 } else if (TbAttributeSubscriptionScope.SHARED_SCOPE.name().equalsIgnoreCase(scope) && notifyDevice) {
264 clusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onUpdate(tenantId, 264 clusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onUpdate(tenantId,
265 new DeviceId(entityId.getId()), DataConstants.SHARED_SCOPE, new ArrayList<>(attributes)) 265 new DeviceId(entityId.getId()), DataConstants.SHARED_SCOPE, new ArrayList<>(attributes))
@@ -269,10 +269,10 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene @@ -269,10 +269,10 @@ public class DefaultSubscriptionManagerService extends TbApplicationEventListene
269 callback.onSuccess(); 269 callback.onSuccess();
270 } 270 }
271 271
272 - private void updateDeviceInactivityTimeout(EntityId entityId, List<? extends KvEntry> kvEntries) { 272 + private void updateDeviceInactivityTimeout(TenantId tenantId, EntityId entityId, List<? extends KvEntry> kvEntries) {
273 for (KvEntry kvEntry : kvEntries) { 273 for (KvEntry kvEntry : kvEntries) {
274 if (kvEntry.getKey().equals(DefaultDeviceStateService.INACTIVITY_TIMEOUT)) { 274 if (kvEntry.getKey().equals(DefaultDeviceStateService.INACTIVITY_TIMEOUT)) {
275 - deviceStateService.onDeviceInactivityTimeoutUpdate(new DeviceId(entityId.getId()), kvEntry.getLongValue().orElse(0L)); 275 + deviceStateService.onDeviceInactivityTimeoutUpdate(tenantId, new DeviceId(entityId.getId()), kvEntry.getLongValue().orElse(0L));
276 } 276 }
277 } 277 }
278 } 278 }
@@ -30,7 +30,7 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -30,7 +30,7 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
30 import org.thingsboard.server.common.msg.queue.TbCallback; 30 import org.thingsboard.server.common.msg.queue.TbCallback;
31 import org.thingsboard.server.queue.discovery.TbApplicationEventListener; 31 import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
32 import org.thingsboard.server.queue.util.TbCoreComponent; 32 import org.thingsboard.server.queue.util.TbCoreComponent;
33 -import org.thingsboard.server.service.queue.TbClusterService; 33 +import org.thingsboard.server.cluster.TbClusterService;
34 import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; 34 import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate;
35 import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate; 35 import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate;
36 36
@@ -42,7 +42,6 @@ import java.util.Map; @@ -42,7 +42,6 @@ import java.util.Map;
42 import java.util.Set; 42 import java.util.Set;
43 import java.util.concurrent.ConcurrentHashMap; 43 import java.util.concurrent.ConcurrentHashMap;
44 import java.util.concurrent.ExecutorService; 44 import java.util.concurrent.ExecutorService;
45 -import java.util.concurrent.Executors;  
46 45
47 @Slf4j 46 @Slf4j
48 @TbCoreComponent 47 @TbCoreComponent
@@ -20,15 +20,13 @@ import com.google.common.util.concurrent.Futures; @@ -20,15 +20,13 @@ import com.google.common.util.concurrent.Futures;
20 import com.google.common.util.concurrent.ListenableFuture; 20 import com.google.common.util.concurrent.ListenableFuture;
21 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
22 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
23 -import org.springframework.context.ApplicationListener;  
24 -import org.springframework.context.event.EventListener;  
25 import org.thingsboard.common.util.ThingsBoardThreadFactory; 23 import org.thingsboard.common.util.ThingsBoardThreadFactory;
26 import org.thingsboard.server.common.msg.queue.ServiceType; 24 import org.thingsboard.server.common.msg.queue.ServiceType;
27 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 25 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
28 import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; 26 import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
29 import org.thingsboard.server.queue.discovery.PartitionService; 27 import org.thingsboard.server.queue.discovery.PartitionService;
30 import org.thingsboard.server.queue.discovery.TbApplicationEventListener; 28 import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
31 -import org.thingsboard.server.service.queue.TbClusterService; 29 +import org.thingsboard.server.cluster.TbClusterService;
32 import org.thingsboard.server.service.subscription.SubscriptionManagerService; 30 import org.thingsboard.server.service.subscription.SubscriptionManagerService;
33 31
34 import javax.annotation.Nullable; 32 import javax.annotation.Nullable;
@@ -46,7 +46,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; @@ -46,7 +46,7 @@ import org.thingsboard.server.gen.transport.TransportProtos;
46 import org.thingsboard.server.queue.discovery.PartitionService; 46 import org.thingsboard.server.queue.discovery.PartitionService;
47 import org.thingsboard.server.queue.usagestats.TbApiUsageClient; 47 import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
48 import org.thingsboard.server.service.apiusage.TbApiUsageStateService; 48 import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
49 -import org.thingsboard.server.service.queue.TbClusterService; 49 +import org.thingsboard.server.cluster.TbClusterService;
50 import org.thingsboard.server.service.subscription.SubscriptionManagerService; 50 import org.thingsboard.server.service.subscription.SubscriptionManagerService;
51 import org.thingsboard.server.service.subscription.TbSubscriptionUtils; 51 import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
52 52
@@ -45,7 +45,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; @@ -45,7 +45,7 @@ import org.thingsboard.server.gen.transport.TransportProtos;
45 import org.thingsboard.server.queue.discovery.PartitionService; 45 import org.thingsboard.server.queue.discovery.PartitionService;
46 import org.thingsboard.server.queue.usagestats.TbApiUsageClient; 46 import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
47 import org.thingsboard.server.service.apiusage.TbApiUsageStateService; 47 import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
48 -import org.thingsboard.server.service.queue.TbClusterService; 48 +import org.thingsboard.server.cluster.TbClusterService;
49 import org.thingsboard.server.service.subscription.TbSubscriptionUtils; 49 import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
50 50
51 import javax.annotation.Nullable; 51 import javax.annotation.Nullable;
@@ -95,7 +95,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @@ -95,7 +95,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
95 import org.thingsboard.server.service.apiusage.TbApiUsageStateService; 95 import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
96 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 96 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
97 import org.thingsboard.server.service.profile.TbDeviceProfileCache; 97 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
98 -import org.thingsboard.server.service.queue.TbClusterService; 98 +import org.thingsboard.server.cluster.TbClusterService;
99 import org.thingsboard.server.service.resource.TbResourceService; 99 import org.thingsboard.server.service.resource.TbResourceService;
100 import org.thingsboard.server.service.state.DeviceStateService; 100 import org.thingsboard.server.service.state.DeviceStateService;
101 101
@@ -265,9 +265,11 @@ public class DefaultTransportApiService implements TransportApiService { @@ -265,9 +265,11 @@ public class DefaultTransportApiService implements TransportApiService {
265 device.setCustomerId(gateway.getCustomerId()); 265 device.setCustomerId(gateway.getCustomerId());
266 DeviceProfile deviceProfile = deviceProfileCache.findOrCreateDeviceProfile(gateway.getTenantId(), requestMsg.getDeviceType()); 266 DeviceProfile deviceProfile = deviceProfileCache.findOrCreateDeviceProfile(gateway.getTenantId(), requestMsg.getDeviceType());
267 device.setDeviceProfileId(deviceProfile.getId()); 267 device.setDeviceProfileId(deviceProfile.getId());
268 - device = deviceService.saveDevice(device); 268 + Device savedDevice = deviceService.saveDevice(device);
  269 + tbClusterService.onDeviceUpdated(savedDevice, device);
  270 + device = savedDevice;
  271 +
269 relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created")); 272 relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created"));
270 - deviceStateService.onDeviceAdded(device);  
271 273
272 TbMsgMetaData metaData = new TbMsgMetaData(); 274 TbMsgMetaData metaData = new TbMsgMetaData();
273 CustomerId customerId = gateway.getCustomerId(); 275 CustomerId customerId = gateway.getCustomerId();
@@ -581,7 +583,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -581,7 +583,7 @@ public class DefaultTransportApiService implements TransportApiService {
581 device.setName(deviceName); 583 device.setName(deviceName);
582 device.setType("LwM2M"); 584 device.setType("LwM2M");
583 device = deviceService.saveDevice(device); 585 device = deviceService.saveDevice(device);
584 - deviceStateService.onDeviceAdded(device); 586 + tbClusterService.onDeviceUpdated(device, null);
585 } 587 }
586 TransportProtos.LwM2MRegistrationResponseMsg registrationResponseMsg = 588 TransportProtos.LwM2MRegistrationResponseMsg registrationResponseMsg =
587 TransportProtos.LwM2MRegistrationResponseMsg.newBuilder() 589 TransportProtos.LwM2MRegistrationResponseMsg.newBuilder()
@@ -588,6 +588,7 @@ transport: @@ -588,6 +588,7 @@ transport:
588 bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" 588 bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}"
589 bind_port: "${MQTT_BIND_PORT:1883}" 589 bind_port: "${MQTT_BIND_PORT:1883}"
590 timeout: "${MQTT_TIMEOUT:10000}" 590 timeout: "${MQTT_TIMEOUT:10000}"
  591 + msg_queue_size_per_device_limit: "${MQTT_MSG_QUEUE_SIZE_PER_DEVICE_LIMIT:100}" # messages await in the queue before device connected state. This limit works on low level before TenantProfileLimits mechanism
591 netty: 592 netty:
592 leak_detector_level: "${NETTY_LEAK_DETECTOR_LVL:DISABLED}" 593 leak_detector_level: "${NETTY_LEAK_DETECTOR_LVL:DISABLED}"
593 boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}" 594 boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}"
@@ -747,6 +748,8 @@ queue: @@ -747,6 +748,8 @@ queue:
747 compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip 748 compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip
748 batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" 749 batch.size: "${TB_KAFKA_BATCH_SIZE:16384}"
749 linger.ms: "${TB_KAFKA_LINGER_MS:1}" 750 linger.ms: "${TB_KAFKA_LINGER_MS:1}"
  751 + max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}"
  752 + max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}"
750 buffer.memory: "${TB_BUFFER_MEMORY:33554432}" 753 buffer.memory: "${TB_BUFFER_MEMORY:33554432}"
751 replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" 754 replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}"
752 max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" 755 max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}"
@@ -763,7 +766,11 @@ queue: @@ -763,7 +766,11 @@ queue:
763 tb_ota_package: 766 tb_ota_package:
764 - key: max.poll.records 767 - key: max.poll.records
765 value: 10 768 value: 10
766 - other: 769 + other: # In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside
  770 + - key: "request.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms
  771 + value: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds)
  772 + - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms
  773 + value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds)
767 topic-properties: 774 topic-properties:
768 rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" 775 rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
769 core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" 776 core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
@@ -17,6 +17,7 @@ package org.thingsboard.server.controller; @@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
17 17
18 import com.fasterxml.jackson.core.type.TypeReference; 18 import com.fasterxml.jackson.core.type.TypeReference;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.awaitility.Awaitility;
20 import org.junit.After; 21 import org.junit.After;
21 import org.junit.Assert; 22 import org.junit.Assert;
22 import org.junit.Before; 23 import org.junit.Before;
@@ -28,13 +29,14 @@ import org.thingsboard.server.common.data.asset.Asset; @@ -28,13 +29,14 @@ import org.thingsboard.server.common.data.asset.Asset;
28 import org.thingsboard.server.common.data.edge.Edge; 29 import org.thingsboard.server.common.data.edge.Edge;
29 import org.thingsboard.server.common.data.edge.EdgeEvent; 30 import org.thingsboard.server.common.data.edge.EdgeEvent;
30 import org.thingsboard.server.common.data.edge.EdgeEventType; 31 import org.thingsboard.server.common.data.edge.EdgeEventType;
31 -import org.thingsboard.server.common.data.id.TenantId; 32 +import org.thingsboard.server.common.data.id.EdgeId;
32 import org.thingsboard.server.common.data.page.PageData; 33 import org.thingsboard.server.common.data.page.PageData;
33 import org.thingsboard.server.common.data.page.TimePageLink; 34 import org.thingsboard.server.common.data.page.TimePageLink;
34 import org.thingsboard.server.common.data.relation.EntityRelation; 35 import org.thingsboard.server.common.data.relation.EntityRelation;
35 import org.thingsboard.server.common.data.security.Authority; 36 import org.thingsboard.server.common.data.security.Authority;
36 37
37 import java.util.List; 38 import java.util.List;
  39 +import java.util.concurrent.TimeUnit;
38 40
39 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 41 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
40 42
@@ -83,34 +85,37 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest { @@ -83,34 +85,37 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest {
83 Device device = constructDevice("TestDevice", "default"); 85 Device device = constructDevice("TestDevice", "default");
84 Device savedDevice = doPost("/api/device", device, Device.class); 86 Device savedDevice = doPost("/api/device", device, Device.class);
85 87
86 - doPost("/api/edge/" + edge.getId().toString() + "/device/" + savedDevice.getId().toString(), Device.class); 88 + final EdgeId edgeId = edge.getId();
  89 + doPost("/api/edge/" + edgeId.toString() + "/device/" + savedDevice.getId().toString(), Device.class);
87 90
88 Asset asset = constructAsset("TestAsset", "default"); 91 Asset asset = constructAsset("TestAsset", "default");
89 Asset savedAsset = doPost("/api/asset", asset, Asset.class); 92 Asset savedAsset = doPost("/api/asset", asset, Asset.class);
90 93
91 - doPost("/api/edge/" + edge.getId().toString() + "/asset/" + savedAsset.getId().toString(), Asset.class); 94 + doPost("/api/edge/" + edgeId.toString() + "/asset/" + savedAsset.getId().toString(), Asset.class);
92 95
93 EntityRelation relation = new EntityRelation(savedAsset.getId(), savedDevice.getId(), EntityRelation.CONTAINS_TYPE); 96 EntityRelation relation = new EntityRelation(savedAsset.getId(), savedDevice.getId(), EntityRelation.CONTAINS_TYPE);
94 97
95 doPost("/api/relation", relation); 98 doPost("/api/relation", relation);
96 99
97 - // wait while edge event for the relation entity persisted to DB  
98 - Thread.sleep(100);  
99 - List<EdgeEvent> edgeEvents;  
100 - int attempt = 1;  
101 - do {  
102 - edgeEvents = doGetTypedWithTimePageLink("/api/edge/" + edge.getId().toString() + "/events?",  
103 - new TypeReference<PageData<EdgeEvent>>() {}, new TimePageLink(4)).getData();  
104 - attempt++;  
105 - Thread.sleep(100);  
106 - } while (edgeEvents.size() != 4 && attempt < 5);  
107 - Assert.assertEquals(4, edgeEvents.size()); 100 + Awaitility.await()
  101 + .atMost(30, TimeUnit.SECONDS)
  102 + .until(() -> {
  103 + List<EdgeEvent> edgeEvents = findEdgeEvents(edgeId);
  104 + return edgeEvents.size() == 4;
  105 + });
  106 + List<EdgeEvent> edgeEvents = findEdgeEvents(edgeId);
108 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RULE_CHAIN.equals(ee.getType()))); 107 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RULE_CHAIN.equals(ee.getType())));
109 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.DEVICE.equals(ee.getType()))); 108 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.DEVICE.equals(ee.getType())));
110 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.ASSET.equals(ee.getType()))); 109 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.ASSET.equals(ee.getType())));
111 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RELATION.equals(ee.getType()))); 110 Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RELATION.equals(ee.getType())));
112 } 111 }
113 112
  113 + private List<EdgeEvent> findEdgeEvents(EdgeId edgeId) throws Exception {
  114 + return doGetTypedWithTimePageLink("/api/edge/" + edgeId.toString() + "/events?",
  115 + new TypeReference<PageData<EdgeEvent>>() {
  116 + }, new TimePageLink(10)).getData();
  117 + }
  118 +
114 private Device constructDevice(String name, String type) { 119 private Device constructDevice(String name, String type) {
115 Device device = new Device(); 120 Device device = new Device();
116 device.setName(name); 121 device.setName(name);
@@ -27,6 +27,7 @@ import com.google.protobuf.InvalidProtocolBufferException; @@ -27,6 +27,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
27 import com.google.protobuf.MessageLite; 27 import com.google.protobuf.MessageLite;
28 import lombok.extern.slf4j.Slf4j; 28 import lombok.extern.slf4j.Slf4j;
29 import org.apache.commons.lang3.RandomStringUtils; 29 import org.apache.commons.lang3.RandomStringUtils;
  30 +import org.awaitility.Awaitility;
30 import org.junit.After; 31 import org.junit.After;
31 import org.junit.Assert; 32 import org.junit.Assert;
32 import org.junit.Before; 33 import org.junit.Before;
@@ -114,7 +115,7 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg; @@ -114,7 +115,7 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg;
114 import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; 115 import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg;
115 import org.thingsboard.server.gen.edge.v1.WidgetsBundleUpdateMsg; 116 import org.thingsboard.server.gen.edge.v1.WidgetsBundleUpdateMsg;
116 import org.thingsboard.server.gen.transport.TransportProtos; 117 import org.thingsboard.server.gen.transport.TransportProtos;
117 -import org.thingsboard.server.service.queue.TbClusterService; 118 +import org.thingsboard.server.cluster.TbClusterService;
118 119
119 import java.util.ArrayList; 120 import java.util.ArrayList;
120 import java.util.List; 121 import java.util.List;
@@ -126,6 +127,7 @@ import java.util.UUID; @@ -126,6 +127,7 @@ import java.util.UUID;
126 import java.util.concurrent.TimeUnit; 127 import java.util.concurrent.TimeUnit;
127 128
128 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 129 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  130 +import static org.thingsboard.server.service.edge.rpc.EdgeProtoUtils.getStringValue;
129 131
130 @Slf4j 132 @Slf4j
131 abstract public class BaseEdgeTest extends AbstractControllerTest { 133 abstract public class BaseEdgeTest extends AbstractControllerTest {
@@ -648,7 +650,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -648,7 +650,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
648 Assert.assertEquals(relationUpdateMsg.getFromIdMSB(), relation.getFrom().getId().getMostSignificantBits()); 650 Assert.assertEquals(relationUpdateMsg.getFromIdMSB(), relation.getFrom().getId().getMostSignificantBits());
649 Assert.assertEquals(relationUpdateMsg.getToIdLSB(), relation.getTo().getId().getLeastSignificantBits()); 651 Assert.assertEquals(relationUpdateMsg.getToIdLSB(), relation.getTo().getId().getLeastSignificantBits());
650 Assert.assertEquals(relationUpdateMsg.getToEntityType(), relation.getTo().getEntityType().name()); 652 Assert.assertEquals(relationUpdateMsg.getToEntityType(), relation.getTo().getEntityType().name());
651 - Assert.assertEquals(relationUpdateMsg.getTypeGroup(), relation.getTypeGroup().name()); 653 + Assert.assertEquals(relationUpdateMsg.getTypeGroup().getValue(), relation.getTypeGroup().name());
652 654
653 // 2 655 // 2
654 edgeImitator.expectMessageAmount(1); 656 edgeImitator.expectMessageAmount(1);
@@ -672,7 +674,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -672,7 +674,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
672 Assert.assertEquals(relationUpdateMsg.getFromIdMSB(), relation.getFrom().getId().getMostSignificantBits()); 674 Assert.assertEquals(relationUpdateMsg.getFromIdMSB(), relation.getFrom().getId().getMostSignificantBits());
673 Assert.assertEquals(relationUpdateMsg.getToIdLSB(), relation.getTo().getId().getLeastSignificantBits()); 675 Assert.assertEquals(relationUpdateMsg.getToIdLSB(), relation.getTo().getId().getLeastSignificantBits());
674 Assert.assertEquals(relationUpdateMsg.getToEntityType(), relation.getTo().getEntityType().name()); 676 Assert.assertEquals(relationUpdateMsg.getToEntityType(), relation.getTo().getEntityType().name());
675 - Assert.assertEquals(relationUpdateMsg.getTypeGroup(), relation.getTypeGroup().name()); 677 + Assert.assertEquals(relationUpdateMsg.getTypeGroup().getValue(), relation.getTypeGroup().name());
676 678
677 log.info("Relations tested successfully"); 679 log.info("Relations tested successfully");
678 } 680 }
@@ -730,7 +732,15 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -730,7 +732,15 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
730 edgeImitator.expectMessageAmount(1); 732 edgeImitator.expectMessageAmount(1);
731 doDelete("/api/alarm/" + savedAlarm.getId().getId().toString()) 733 doDelete("/api/alarm/" + savedAlarm.getId().getId().toString())
732 .andExpect(status().isOk()); 734 .andExpect(status().isOk());
733 - Assert.assertFalse(edgeImitator.waitForMessages(1)); 735 + Assert.assertTrue(edgeImitator.waitForMessages(1));
  736 + latestMessage = edgeImitator.getLatestMessage();
  737 + Assert.assertTrue(latestMessage instanceof AlarmUpdateMsg);
  738 + alarmUpdateMsg = (AlarmUpdateMsg) latestMessage;
  739 + Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, alarmUpdateMsg.getMsgType());
  740 + Assert.assertEquals(alarmUpdateMsg.getType(), savedAlarm.getType());
  741 + Assert.assertEquals(alarmUpdateMsg.getName(), savedAlarm.getName());
  742 + Assert.assertEquals(alarmUpdateMsg.getOriginatorName(), device.getName());
  743 + Assert.assertEquals(alarmUpdateMsg.getStatus(), AlarmStatus.CLEARED_ACK.name());
734 744
735 log.info("Alarms tested successfully"); 745 log.info("Alarms tested successfully");
736 } 746 }
@@ -900,9 +910,9 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -900,9 +910,9 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
900 Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, widgetTypeUpdateMsg.getMsgType()); 910 Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, widgetTypeUpdateMsg.getMsgType());
901 Assert.assertEquals(widgetTypeUpdateMsg.getIdMSB(), savedWidgetType.getUuidId().getMostSignificantBits()); 911 Assert.assertEquals(widgetTypeUpdateMsg.getIdMSB(), savedWidgetType.getUuidId().getMostSignificantBits());
902 Assert.assertEquals(widgetTypeUpdateMsg.getIdLSB(), savedWidgetType.getUuidId().getLeastSignificantBits()); 912 Assert.assertEquals(widgetTypeUpdateMsg.getIdLSB(), savedWidgetType.getUuidId().getLeastSignificantBits());
903 - Assert.assertEquals(widgetTypeUpdateMsg.getAlias(), savedWidgetType.getAlias());  
904 - Assert.assertEquals(widgetTypeUpdateMsg.getName(), savedWidgetType.getName());  
905 - Assert.assertEquals(JacksonUtil.toJsonNode(widgetTypeUpdateMsg.getDescriptorJson()), savedWidgetType.getDescriptor()); 913 + Assert.assertEquals(widgetTypeUpdateMsg.getAlias().getValue(), savedWidgetType.getAlias());
  914 + Assert.assertEquals(widgetTypeUpdateMsg.getName().getValue(), savedWidgetType.getName());
  915 + Assert.assertEquals(JacksonUtil.toJsonNode(widgetTypeUpdateMsg.getDescriptorJson().getValue()), savedWidgetType.getDescriptor());
906 916
907 // 3 917 // 3
908 edgeImitator.expectMessageAmount(1); 918 edgeImitator.expectMessageAmount(1);
@@ -939,7 +949,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -939,7 +949,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
939 String timeseriesData = "{\"data\":{\"temperature\":25},\"ts\":" + System.currentTimeMillis() + "}"; 949 String timeseriesData = "{\"data\":{\"temperature\":25},\"ts\":" + System.currentTimeMillis() + "}";
940 JsonNode timeseriesEntityData = mapper.readTree(timeseriesData); 950 JsonNode timeseriesEntityData = mapper.readTree(timeseriesData);
941 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData); 951 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData);
942 - edgeEventService.saveAsync(edgeEvent); 952 + edgeEventService.save(edgeEvent);
943 clusterService.onEdgeEventUpdate(tenantId, edge.getId()); 953 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
944 Assert.assertTrue(edgeImitator.waitForMessages()); 954 Assert.assertTrue(edgeImitator.waitForMessages());
945 955
@@ -978,7 +988,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -978,7 +988,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
978 JsonNode attributesEntityData = mapper.readTree(attributesData); 988 JsonNode attributesEntityData = mapper.readTree(attributesData);
979 EdgeEvent edgeEvent1 = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, attributesEntityData); 989 EdgeEvent edgeEvent1 = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, attributesEntityData);
980 edgeImitator.expectMessageAmount(1); 990 edgeImitator.expectMessageAmount(1);
981 - edgeEventService.saveAsync(edgeEvent1); 991 + edgeEventService.save(edgeEvent1);
982 clusterService.onEdgeEventUpdate(tenantId, edge.getId()); 992 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
983 Assert.assertTrue(edgeImitator.waitForMessages()); 993 Assert.assertTrue(edgeImitator.waitForMessages());
984 994
@@ -1003,7 +1013,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1003,7 +1013,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1003 JsonNode postAttributesEntityData = mapper.readTree(postAttributesData); 1013 JsonNode postAttributesEntityData = mapper.readTree(postAttributesData);
1004 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.POST_ATTRIBUTES, device.getId().getId(), EdgeEventType.DEVICE, postAttributesEntityData); 1014 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.POST_ATTRIBUTES, device.getId().getId(), EdgeEventType.DEVICE, postAttributesEntityData);
1005 edgeImitator.expectMessageAmount(1); 1015 edgeImitator.expectMessageAmount(1);
1006 - edgeEventService.saveAsync(edgeEvent); 1016 + edgeEventService.save(edgeEvent);
1007 clusterService.onEdgeEventUpdate(tenantId, edge.getId()); 1017 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
1008 Assert.assertTrue(edgeImitator.waitForMessages()); 1018 Assert.assertTrue(edgeImitator.waitForMessages());
1009 1019
@@ -1028,7 +1038,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1028,7 +1038,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1028 JsonNode deleteAttributesEntityData = mapper.readTree(deleteAttributesData); 1038 JsonNode deleteAttributesEntityData = mapper.readTree(deleteAttributesData);
1029 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_DELETED, device.getId().getId(), EdgeEventType.DEVICE, deleteAttributesEntityData); 1039 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_DELETED, device.getId().getId(), EdgeEventType.DEVICE, deleteAttributesEntityData);
1030 edgeImitator.expectMessageAmount(1); 1040 edgeImitator.expectMessageAmount(1);
1031 - edgeEventService.saveAsync(edgeEvent); 1041 + edgeEventService.save(edgeEvent);
1032 clusterService.onEdgeEventUpdate(tenantId, edge.getId()); 1042 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
1033 Assert.assertTrue(edgeImitator.waitForMessages()); 1043 Assert.assertTrue(edgeImitator.waitForMessages());
1034 1044
@@ -1062,7 +1072,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1062,7 +1072,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1062 1072
1063 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.RPC_CALL, device.getId().getId(), EdgeEventType.DEVICE, body); 1073 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.RPC_CALL, device.getId().getId(), EdgeEventType.DEVICE, body);
1064 edgeImitator.expectMessageAmount(1); 1074 edgeImitator.expectMessageAmount(1);
1065 - edgeEventService.saveAsync(edgeEvent); 1075 + edgeEventService.save(edgeEvent);
1066 clusterService.onEdgeEventUpdate(tenantId, edge.getId()); 1076 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
1067 Assert.assertTrue(edgeImitator.waitForMessages()); 1077 Assert.assertTrue(edgeImitator.waitForMessages());
1068 1078
@@ -1088,7 +1098,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1088,7 +1098,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1088 JsonNode timeseriesEntityData = mapper.readTree(timeseriesData); 1098 JsonNode timeseriesEntityData = mapper.readTree(timeseriesData);
1089 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, 1099 EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED,
1090 device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData); 1100 device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData);
1091 - edgeEventService.saveAsync(edgeEvent); 1101 + edgeEventService.save(edgeEvent);
1092 clusterService.onEdgeEventUpdate(tenantId, edge.getId()); 1102 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
1093 } 1103 }
1094 1104
@@ -1202,7 +1212,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1202,7 +1212,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1202 Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg); 1212 Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
1203 DeviceUpdateMsg latestDeviceUpdateMsg = (DeviceUpdateMsg) latestMessage; 1213 DeviceUpdateMsg latestDeviceUpdateMsg = (DeviceUpdateMsg) latestMessage;
1204 Assert.assertNotEquals(deviceOnCloudName, latestDeviceUpdateMsg.getName()); 1214 Assert.assertNotEquals(deviceOnCloudName, latestDeviceUpdateMsg.getName());
1205 - Assert.assertEquals(deviceOnCloudName, latestDeviceUpdateMsg.getConflictName()); 1215 + Assert.assertEquals(deviceOnCloudName, latestDeviceUpdateMsg.getConflictName().getValue());
1206 1216
1207 UUID newDeviceId = new UUID(latestDeviceUpdateMsg.getIdMSB(), latestDeviceUpdateMsg.getIdLSB()); 1217 UUID newDeviceId = new UUID(latestDeviceUpdateMsg.getIdMSB(), latestDeviceUpdateMsg.getIdLSB());
1208 1218
@@ -1269,7 +1279,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1269,7 +1279,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1269 EntityId toEntityId = EntityIdFactory.getByTypeAndUuid(relationUpdateMsg.getToEntityType(), toUUID); 1279 EntityId toEntityId = EntityIdFactory.getByTypeAndUuid(relationUpdateMsg.getToEntityType(), toUUID);
1270 Assert.assertEquals(relation.getTo(), toEntityId); 1280 Assert.assertEquals(relation.getTo(), toEntityId);
1271 1281
1272 - Assert.assertEquals(relation.getTypeGroup().name(), relationUpdateMsg.getTypeGroup()); 1282 + Assert.assertEquals(relation.getTypeGroup().name(), relationUpdateMsg.getTypeGroup().getValue());
1273 } 1283 }
1274 1284
1275 private void sendAlarm() throws Exception { 1285 private void sendAlarm() throws Exception {
@@ -1348,15 +1358,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1348,15 +1358,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1348 edgeImitator.sendUplinkMsg(uplinkMsgBuilder2.build()); 1358 edgeImitator.sendUplinkMsg(uplinkMsgBuilder2.build());
1349 Assert.assertTrue(edgeImitator.waitForResponses()); 1359 Assert.assertTrue(edgeImitator.waitForResponses());
1350 1360
1351 - int attempt = 0;  
1352 - Map<String, List<Map<String, String>>> timeseries;  
1353 - do {  
1354 - timeseries = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getUuidId() + "/values/timeseries?keys=" + timeseriesKey,  
1355 - new TypeReference<>() {});  
1356 - // Wait before device attributes saved to database before requesting them from controller  
1357 - Thread.sleep(100);  
1358 - attempt++;  
1359 - } while (!timeseries.containsKey(timeseriesKey) || attempt < 10); 1361 + Awaitility.await()
  1362 + .atMost(2, TimeUnit.SECONDS)
  1363 + .until(() -> loadDeviceTimeseries(device, timeseriesKey).containsKey(timeseriesKey));
  1364 +
  1365 + Map<String, List<Map<String, String>>> timeseries = loadDeviceTimeseries(device, timeseriesKey);
1360 Assert.assertTrue(timeseries.containsKey(timeseriesKey)); 1366 Assert.assertTrue(timeseries.containsKey(timeseriesKey));
1361 Assert.assertEquals(1, timeseries.get(timeseriesKey).size()); 1367 Assert.assertEquals(1, timeseries.get(timeseriesKey).size());
1362 Assert.assertEquals(timeseriesValue, timeseries.get(timeseriesKey).get(0).get("value")); 1368 Assert.assertEquals(timeseriesValue, timeseries.get(timeseriesKey).get(0).get("value"));
@@ -1365,7 +1371,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1365,7 +1371,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1365 Assert.assertEquals(1, attributes.size()); 1371 Assert.assertEquals(1, attributes.size());
1366 Assert.assertEquals(attributes.get(0).get("key"), attributesKey); 1372 Assert.assertEquals(attributes.get(0).get("key"), attributesKey);
1367 Assert.assertEquals(attributes.get(0).get("value"), attributesValue); 1373 Assert.assertEquals(attributes.get(0).get("value"), attributesValue);
  1374 + }
1368 1375
  1376 + private Map<String, List<Map<String, String>>> loadDeviceTimeseries(Device device, String timeseriesKey) throws Exception {
  1377 + return doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getUuidId() + "/values/timeseries?keys=" + timeseriesKey,
  1378 + new TypeReference<>() {});
1369 } 1379 }
1370 1380
1371 private void sendRelation() throws Exception { 1381 private void sendRelation() throws Exception {
@@ -1381,7 +1391,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1381,7 +1391,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1381 UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder(); 1391 UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder();
1382 RelationUpdateMsg.Builder relationUpdateMsgBuilder = RelationUpdateMsg.newBuilder(); 1392 RelationUpdateMsg.Builder relationUpdateMsgBuilder = RelationUpdateMsg.newBuilder();
1383 relationUpdateMsgBuilder.setType("test"); 1393 relationUpdateMsgBuilder.setType("test");
1384 - relationUpdateMsgBuilder.setTypeGroup(RelationTypeGroup.COMMON.name()); 1394 + relationUpdateMsgBuilder.setTypeGroup(getStringValue(RelationTypeGroup.COMMON.name()));
1385 relationUpdateMsgBuilder.setToIdMSB(device1.getId().getId().getMostSignificantBits()); 1395 relationUpdateMsgBuilder.setToIdMSB(device1.getId().getId().getMostSignificantBits());
1386 relationUpdateMsgBuilder.setToIdLSB(device1.getId().getId().getLeastSignificantBits()); 1396 relationUpdateMsgBuilder.setToIdLSB(device1.getId().getId().getLeastSignificantBits());
1387 relationUpdateMsgBuilder.setToEntityType(device1.getId().getEntityType().name()); 1397 relationUpdateMsgBuilder.setToEntityType(device1.getId().getEntityType().name());
@@ -1447,7 +1457,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { @@ -1447,7 +1457,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1447 edgeImitator.expectMessageAmount(1); 1457 edgeImitator.expectMessageAmount(1);
1448 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); 1458 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1449 Assert.assertTrue(edgeImitator.waitForResponses()); 1459 Assert.assertTrue(edgeImitator.waitForResponses());
1450 - Assert.assertTrue(edgeImitator.waitForMessages());; 1460 + Assert.assertTrue(edgeImitator.waitForMessages());
1451 1461
1452 AbstractMessage latestMessage = edgeImitator.getLatestMessage(); 1462 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1453 Assert.assertTrue(latestMessage instanceof RuleChainMetadataUpdateMsg); 1463 Assert.assertTrue(latestMessage instanceof RuleChainMetadataUpdateMsg);
@@ -27,7 +27,7 @@ import org.thingsboard.server.dao.device.DeviceService; @@ -27,7 +27,7 @@ import org.thingsboard.server.dao.device.DeviceService;
27 import org.thingsboard.server.dao.tenant.TenantService; 27 import org.thingsboard.server.dao.tenant.TenantService;
28 import org.thingsboard.server.dao.timeseries.TimeseriesService; 28 import org.thingsboard.server.dao.timeseries.TimeseriesService;
29 import org.thingsboard.server.queue.discovery.PartitionService; 29 import org.thingsboard.server.queue.discovery.PartitionService;
30 -import org.thingsboard.server.service.queue.TbClusterService; 30 +import org.thingsboard.server.cluster.TbClusterService;
31 31
32 import static org.hamcrest.CoreMatchers.is; 32 import static org.hamcrest.CoreMatchers.is;
33 import static org.hamcrest.MatcherAssert.assertThat; 33 import static org.hamcrest.MatcherAssert.assertThat;
@@ -43,7 +43,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab @@ -43,7 +43,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab
43 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}"; 43 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}";
44 String deviceId = savedDevice.getId().getId().toString(); 44 String deviceId = savedDevice.getId().getId().toString();
45 45
46 - doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(409), 46 + doPostAsync("/api/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(504),
47 asyncContextTimeoutToUseRpcPlugin); 47 asyncContextTimeoutToUseRpcPlugin);
48 } 48 }
49 49
@@ -52,7 +52,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab @@ -52,7 +52,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab
52 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"25\",\"value\": 1}}"; 52 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"25\",\"value\": 1}}";
53 String nonExistentDeviceId = Uuids.timeBased().toString(); 53 String nonExistentDeviceId = Uuids.timeBased().toString();
54 54
55 - String result = doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class, 55 + String result = doPostAsync("/api/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class,
56 status().isNotFound()); 56 status().isNotFound());
57 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result); 57 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
58 } 58 }
@@ -62,7 +62,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab @@ -62,7 +62,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab
62 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}"; 62 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}";
63 String deviceId = savedDevice.getId().getId().toString(); 63 String deviceId = savedDevice.getId().getId().toString();
64 64
65 - doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(409), 65 + doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(504),
66 asyncContextTimeoutToUseRpcPlugin); 66 asyncContextTimeoutToUseRpcPlugin);
67 } 67 }
68 68
@@ -71,7 +71,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab @@ -71,7 +71,7 @@ public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends Ab
71 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"28\",\"value\": 1}}"; 71 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"28\",\"value\": 1}}";
72 String nonExistentDeviceId = Uuids.timeBased().toString(); 72 String nonExistentDeviceId = Uuids.timeBased().toString();
73 73
74 - String result = doPostAsync("/api/plugins/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class, 74 + String result = doPostAsync("/api/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class,
75 status().isNotFound()); 75 status().isNotFound());
76 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result); 76 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
77 } 77 }
@@ -71,7 +71,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC @@ -71,7 +71,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
71 71
72 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; 72 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
73 String deviceId = savedDevice.getId().getId().toString(); 73 String deviceId = savedDevice.getId().getId().toString();
74 - String result = doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk()); 74 + String result = doPostAsync("/api/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk());
75 75
76 latch.await(3, TimeUnit.SECONDS); 76 latch.await(3, TimeUnit.SECONDS);
77 77
@@ -99,14 +99,14 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC @@ -99,14 +99,14 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
99 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; 99 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
100 String deviceId = savedDevice.getId().getId().toString(); 100 String deviceId = savedDevice.getId().getId().toString();
101 101
102 - String actualResult = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); 102 + String actualResult = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
103 latch.await(3, TimeUnit.SECONDS); 103 latch.await(3, TimeUnit.SECONDS);
104 104
105 validateTwoWayStateChangedNotification(callback, 1, expectedResponseResult, actualResult); 105 validateTwoWayStateChangedNotification(callback, 1, expectedResponseResult, actualResult);
106 106
107 latch = new CountDownLatch(1); 107 latch = new CountDownLatch(1);
108 108
109 - actualResult = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); 109 + actualResult = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
110 latch.await(3, TimeUnit.SECONDS); 110 latch.await(3, TimeUnit.SECONDS);
111 111
112 validateTwoWayStateChangedNotification(callback, 2, expectedResponseResult, actualResult); 112 validateTwoWayStateChangedNotification(callback, 2, expectedResponseResult, actualResult);
@@ -27,6 +27,7 @@ import org.springframework.mock.web.MockMultipartFile; @@ -27,6 +27,7 @@ import org.springframework.mock.web.MockMultipartFile;
27 import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; 27 import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
28 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 28 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
29 import org.thingsboard.common.util.JacksonUtil; 29 import org.thingsboard.common.util.JacksonUtil;
  30 +import org.thingsboard.common.util.ThingsBoardThreadFactory;
30 import org.thingsboard.server.common.data.Device; 31 import org.thingsboard.server.common.data.Device;
31 import org.thingsboard.server.common.data.DeviceProfile; 32 import org.thingsboard.server.common.data.DeviceProfile;
32 import org.thingsboard.server.common.data.DeviceProfileProvisionType; 33 import org.thingsboard.server.common.data.DeviceProfileProvisionType;
@@ -261,7 +262,7 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest { @@ -261,7 +262,7 @@ public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
261 262
262 @Before 263 @Before
263 public void beforeTest() throws Exception { 264 public void beforeTest() throws Exception {
264 - executor = Executors.newScheduledThreadPool(10); 265 + executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-lwm2m-scheduled"));
265 loginTenantAdmin(); 266 loginTenantAdmin();
266 267
267 String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; 268 String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"};
@@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
16 package org.thingsboard.server.transport.lwm2m; 16 package org.thingsboard.server.transport.lwm2m;
17 17
18 import com.fasterxml.jackson.core.type.TypeReference; 18 import com.fasterxml.jackson.core.type.TypeReference;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.junit.After;
19 import org.junit.Assert; 21 import org.junit.Assert;
20 import org.junit.Test; 22 import org.junit.Test;
21 import org.thingsboard.server.common.data.Device; 23 import org.thingsboard.server.common.data.Device;
@@ -23,16 +25,18 @@ import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCr @@ -23,16 +25,18 @@ import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCr
23 import org.thingsboard.server.common.data.kv.KvEntry; 25 import org.thingsboard.server.common.data.kv.KvEntry;
24 import org.thingsboard.server.common.data.kv.TsKvEntry; 26 import org.thingsboard.server.common.data.kv.TsKvEntry;
25 import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; 27 import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
26 -import org.thingsboard.server.common.data.query.EntityKey;  
27 -import org.thingsboard.server.common.data.query.EntityKeyType;  
28 import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; 28 import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient;
29 29
30 import java.util.Arrays; 30 import java.util.Arrays;
31 import java.util.Collections; 31 import java.util.Collections;
32 import java.util.Comparator; 32 import java.util.Comparator;
33 import java.util.List; 33 import java.util.List;
  34 +import java.util.UUID;
  35 +import java.util.concurrent.TimeUnit;
34 import java.util.stream.Collectors; 36 import java.util.stream.Collectors;
35 37
  38 +import static org.awaitility.Awaitility.await;
  39 +import static org.hamcrest.Matchers.is;
36 import static org.thingsboard.rest.client.utils.RestJsonConverter.toTimeseries; 40 import static org.thingsboard.rest.client.utils.RestJsonConverter.toTimeseries;
37 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; 41 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;
38 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING; 42 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING;
@@ -43,8 +47,10 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDA @@ -43,8 +47,10 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDA
43 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING; 47 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING;
44 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED; 48 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED;
45 49
  50 +@Slf4j
46 public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { 51 public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
47 52
  53 + public static final int TIMEOUT = 30;
48 private final String OTA_TRANSPORT_CONFIGURATION = "{\n" + 54 private final String OTA_TRANSPORT_CONFIGURATION = "{\n" +
49 " \"observeAttr\": {\n" + 55 " \"observeAttr\": {\n" +
50 " \"keyName\": {\n" + 56 " \"keyName\": {\n" +
@@ -122,6 +128,15 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -122,6 +128,15 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
122 " \"type\": \"LWM2M\"\n" + 128 " \"type\": \"LWM2M\"\n" +
123 "}"; 129 "}";
124 130
  131 + LwM2MTestClient client = null;
  132 +
  133 + @After
  134 + public void tearDown() {
  135 + if (client != null) {
  136 + client.destroy();
  137 + }
  138 + }
  139 +
125 @Test 140 @Test
126 public void testConnectAndObserveTelemetry() throws Exception { 141 public void testConnectAndObserveTelemetry() throws Exception {
127 NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); 142 NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
@@ -196,37 +211,68 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { @@ -196,37 +211,68 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
196 } 211 }
197 } 212 }
198 213
  214 + /**
  215 + * This is the example how to use the AWAITILITY instead Thread.sleep()
  216 + * Test will finish as fast as possible, but will await until TIMEOUT if a build machine is busy or slow
  217 + * Check the detailed log output to learn how Awaitility polling the API and when exactly expected result appears
  218 + * */
199 @Test 219 @Test
200 public void testSoftwareUpdateByObject9() throws Exception { 220 public void testSoftwareUpdateByObject9() throws Exception {
201 - LwM2MTestClient client = null;  
202 - try {  
203 - createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);  
204 - NoSecClientCredentials clientCredentials = new NoSecClientCredentials();  
205 - clientCredentials.setEndpoint("OTA_" + ENDPOINT);  
206 - Device device = createDevice(clientCredentials);  
207 -  
208 - device.setSoftwareId(createSoftware().getId());  
209 - device = doPost("/api/device", device, Device.class); 221 + //given
  222 + final List<OtaPackageUpdateStatus> expectedStatuses = Collections.unmodifiableList(Arrays.asList(
  223 + QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED));
210 224
211 - Thread.sleep(1000);  
212 -  
213 - client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);  
214 - client.init(SECURITY, COAP_CONFIG);  
215 -  
216 - Thread.sleep(3000);  
217 -  
218 - List<TsKvEntry> ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId().getId() + "/values/timeseries?orderBy=ASC&keys=sw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() {  
219 - }));  
220 -  
221 - List<OtaPackageUpdateStatus> statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList()); 225 + createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
  226 + NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
  227 + clientCredentials.setEndpoint("OTA_" + ENDPOINT);
  228 + final Device device = createDevice(clientCredentials);
  229 + device.setSoftwareId(createSoftware().getId());
  230 +
  231 + log.warn("Saving by API " + device);
  232 + final Device savedDevice = doPost("/api/device", device, Device.class);
  233 + Assert.assertNotNull(savedDevice);
  234 + log.warn("Device saved by API {}", savedDevice);
  235 +
  236 + log.warn("AWAIT atMost {} SECONDS on get device by API...", TIMEOUT);
  237 + await()
  238 + .atMost(TIMEOUT, TimeUnit.SECONDS)
  239 + .until(() -> getDeviceFromAPI(device.getId().getId()), is(savedDevice));
  240 + log.warn("Got device by API.");
  241 +
  242 + //when
  243 + log.warn("Init the client...");
  244 + client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);
  245 + client.init(SECURITY, COAP_CONFIG);
  246 + log.warn("Init done");
  247 +
  248 + log.warn("AWAIT atMost {} SECONDS on timeseries List<TsKvEntry> by API with list size {}...", TIMEOUT, expectedStatuses.size());
  249 + await()
  250 + .atMost(30, TimeUnit.SECONDS)
  251 + .until(() -> getSwStateTelemetryFromAPI(device.getId().getId())
  252 + .size(), is(expectedStatuses.size()));
  253 + log.warn("Got an expected await condition!");
  254 +
  255 + //then
  256 + log.warn("Fetching ts for the final asserts");
  257 + List<TsKvEntry> ts = getSwStateTelemetryFromAPI(device.getId().getId());
  258 + log.warn("Got an ts {}", ts);
  259 +
  260 + List<OtaPackageUpdateStatus> statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
  261 + log.warn("Converted ts to statuses {}", statuses);
  262 +
  263 + Assert.assertEquals(expectedStatuses, statuses);
  264 + }
222 265
223 - List<OtaPackageUpdateStatus> expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED); 266 + private Device getDeviceFromAPI(UUID deviceId) throws Exception {
  267 + final Device device = doGet("/api/device/" + deviceId, Device.class);
  268 + log.warn("Fetched device by API for deviceId {}, device is {}", deviceId, device);
  269 + return device;
  270 + }
224 271
225 - Assert.assertEquals(expectedStatuses, statuses);  
226 - } finally {  
227 - if (client != null) {  
228 - client.destroy();  
229 - }  
230 - } 272 + private List<TsKvEntry> getSwStateTelemetryFromAPI(UUID deviceId) throws Exception {
  273 + final List<TsKvEntry> tsKvEntries = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?orderBy=ASC&keys=sw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() {
  274 + }));
  275 + log.warn("Fetched telemetry by API for deviceId {}, list size {}, tsKvEntries {}", deviceId, tsKvEntries.size(), tsKvEntries);
  276 + return tsKvEntries;
231 } 277 }
232 } 278 }
@@ -46,7 +46,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab @@ -46,7 +46,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab
46 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}"; 46 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}";
47 String deviceId = savedDevice.getId().getId().toString(); 47 String deviceId = savedDevice.getId().getId().toString();
48 48
49 - doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(409), 49 + doPostAsync("/api/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(504),
50 asyncContextTimeoutToUseRpcPlugin); 50 asyncContextTimeoutToUseRpcPlugin);
51 } 51 }
52 52
@@ -55,7 +55,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab @@ -55,7 +55,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab
55 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"25\",\"value\": 1}}"; 55 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"25\",\"value\": 1}}";
56 String nonExistentDeviceId = Uuids.timeBased().toString(); 56 String nonExistentDeviceId = Uuids.timeBased().toString();
57 57
58 - String result = doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class, 58 + String result = doPostAsync("/api/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class,
59 status().isNotFound()); 59 status().isNotFound());
60 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result); 60 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
61 } 61 }
@@ -65,7 +65,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab @@ -65,7 +65,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab
65 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}"; 65 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}";
66 String deviceId = savedDevice.getId().getId().toString(); 66 String deviceId = savedDevice.getId().getId().toString();
67 67
68 - doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(409), 68 + doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(504),
69 asyncContextTimeoutToUseRpcPlugin); 69 asyncContextTimeoutToUseRpcPlugin);
70 } 70 }
71 71
@@ -74,7 +74,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab @@ -74,7 +74,7 @@ public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends Ab
74 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"28\",\"value\": 1}}"; 74 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"28\",\"value\": 1}}";
75 String nonExistentDeviceId = Uuids.timeBased().toString(); 75 String nonExistentDeviceId = Uuids.timeBased().toString();
76 76
77 - String result = doPostAsync("/api/plugins/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class, 77 + String result = doPostAsync("/api/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class,
78 status().isNotFound()); 78 status().isNotFound());
79 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result); 79 Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result);
80 } 80 }
@@ -69,7 +69,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM @@ -69,7 +69,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
69 69
70 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; 70 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
71 String deviceId = savedDevice.getId().getId().toString(); 71 String deviceId = savedDevice.getId().getId().toString();
72 - String result = doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk()); 72 + String result = doPostAsync("/api/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk());
73 Assert.assertTrue(StringUtils.isEmpty(result)); 73 Assert.assertTrue(StringUtils.isEmpty(result));
74 latch.await(3, TimeUnit.SECONDS); 74 latch.await(3, TimeUnit.SECONDS);
75 assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); 75 assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
@@ -95,7 +95,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM @@ -95,7 +95,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
95 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; 95 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
96 String deviceId = savedDevice.getId().getId().toString(); 96 String deviceId = savedDevice.getId().getId().toString();
97 97
98 - String result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); 98 + String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
99 String expected = "{\"value1\":\"A\",\"value2\":\"B\"}"; 99 String expected = "{\"value1\":\"A\",\"value2\":\"B\"}";
100 latch.await(3, TimeUnit.SECONDS); 100 latch.await(3, TimeUnit.SECONDS);
101 Assert.assertEquals(expected, result); 101 Assert.assertEquals(expected, result);
@@ -130,7 +130,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM @@ -130,7 +130,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
130 130
131 String setGpioRequest = "{\"method\": \"toggle_gpio\", \"params\": {\"pin\":1}}"; 131 String setGpioRequest = "{\"method\": \"toggle_gpio\", \"params\": {\"pin\":1}}";
132 String deviceId = savedDevice.getId().getId().toString(); 132 String deviceId = savedDevice.getId().getId().toString();
133 - String result = doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk()); 133 + String result = doPostAsync("/api/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isOk());
134 Assert.assertTrue(StringUtils.isEmpty(result)); 134 Assert.assertTrue(StringUtils.isEmpty(result));
135 latch.await(3, TimeUnit.SECONDS); 135 latch.await(3, TimeUnit.SECONDS);
136 assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); 136 assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
@@ -156,7 +156,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM @@ -156,7 +156,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
156 156
157 String setGpioRequest = "{\"method\": \"toggle_gpio\", \"params\": {\"pin\":1}}"; 157 String setGpioRequest = "{\"method\": \"toggle_gpio\", \"params\": {\"pin\":1}}";
158 String deviceId = savedDevice.getId().getId().toString(); 158 String deviceId = savedDevice.getId().getId().toString();
159 - String result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); 159 + String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
160 latch.await(3, TimeUnit.SECONDS); 160 latch.await(3, TimeUnit.SECONDS);
161 String expected = "{\"success\":true}"; 161 String expected = "{\"success\":true}";
162 assertEquals(expected, result); 162 assertEquals(expected, result);
@@ -131,7 +131,7 @@ public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends Abst @@ -131,7 +131,7 @@ public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends Abst
131 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; 131 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
132 String deviceId = savedDevice.getId().getId().toString(); 132 String deviceId = savedDevice.getId().getId().toString();
133 133
134 - String result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk()); 134 + String result = doPostAsync("/api/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
135 String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}"; 135 String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}";
136 latch.await(3, TimeUnit.SECONDS); 136 latch.await(3, TimeUnit.SECONDS);
137 Assert.assertEquals(expected, result); 137 Assert.assertEquals(expected, result);
  1 +<!--
  2 +
  3 + Copyright © 2016-2021 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  20 + <modelVersion>4.0.0</modelVersion>
  21 + <parent>
  22 + <groupId>org.thingsboard</groupId>
  23 + <version>3.3.0-SNAPSHOT</version>
  24 + <artifactId>common</artifactId>
  25 + </parent>
  26 + <groupId>org.thingsboard.common</groupId>
  27 + <artifactId>cluster-api</artifactId>
  28 + <packaging>jar</packaging>
  29 +
  30 + <name>Thingsboard Server Common Cluster API</name>
  31 + <url>https://thingsboard.io</url>
  32 +
  33 + <properties>
  34 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  35 + <main.dir>${basedir}/../..</main.dir>
  36 + </properties>
  37 +
  38 + <dependencies>
  39 + <dependency>
  40 + <groupId>org.thingsboard.common</groupId>
  41 + <artifactId>data</artifactId>
  42 + </dependency>
  43 + <dependency>
  44 + <groupId>org.thingsboard.common</groupId>
  45 + <artifactId>message</artifactId>
  46 + </dependency>
  47 + <dependency>
  48 + <groupId>org.thingsboard.common</groupId>
  49 + <artifactId>stats</artifactId>
  50 + </dependency>
  51 + <dependency>
  52 + <groupId>com.google.guava</groupId>
  53 + <artifactId>guava</artifactId>
  54 + </dependency>
  55 + <dependency>
  56 + <groupId>javax.annotation</groupId>
  57 + <artifactId>javax.annotation-api</artifactId>
  58 + </dependency>
  59 + <dependency>
  60 + <groupId>com.github.fge</groupId>
  61 + <artifactId>json-schema-validator</artifactId>
  62 + </dependency>
  63 + <dependency>
  64 + <groupId>org.slf4j</groupId>
  65 + <artifactId>slf4j-api</artifactId>
  66 + </dependency>
  67 + <dependency>
  68 + <groupId>org.slf4j</groupId>
  69 + <artifactId>log4j-over-slf4j</artifactId>
  70 + </dependency>
  71 + <dependency>
  72 + <groupId>ch.qos.logback</groupId>
  73 + <artifactId>logback-core</artifactId>
  74 + </dependency>
  75 + <dependency>
  76 + <groupId>ch.qos.logback</groupId>
  77 + <artifactId>logback-classic</artifactId>
  78 + </dependency>
  79 + <dependency>
  80 + <groupId>com.fasterxml.jackson.core</groupId>
  81 + <artifactId>jackson-databind</artifactId>
  82 + </dependency>
  83 + <dependency>
  84 + <groupId>org.springframework.boot</groupId>
  85 + <artifactId>spring-boot-autoconfigure</artifactId>
  86 + <scope>provided</scope>
  87 + </dependency>
  88 + <dependency>
  89 + <groupId>com.datastax.oss</groupId>
  90 + <artifactId>java-driver-core</artifactId>
  91 + <scope>provided</scope>
  92 + </dependency>
  93 + <dependency>
  94 + <groupId>io.dropwizard.metrics</groupId>
  95 + <artifactId>metrics-jmx</artifactId>
  96 + <scope>provided</scope>
  97 + </dependency>
  98 + <dependency>
  99 + <groupId>org.apache.commons</groupId>
  100 + <artifactId>commons-lang3</artifactId>
  101 + <scope>provided</scope>
  102 + </dependency>
  103 + <dependency>
  104 + <groupId>junit</groupId>
  105 + <artifactId>junit</artifactId>
  106 + <scope>test</scope>
  107 + </dependency>
  108 + <dependency>
  109 + <groupId>org.mockito</groupId>
  110 + <artifactId>mockito-core</artifactId>
  111 + <scope>test</scope>
  112 + </dependency>
  113 + </dependencies>
  114 +
  115 + <build>
  116 + <plugins>
  117 + <plugin>
  118 + <groupId>org.xolstice.maven.plugins</groupId>
  119 + <artifactId>protobuf-maven-plugin</artifactId>
  120 + </plugin>
  121 + <plugin>
  122 + <groupId>org.apache.maven.plugins</groupId>
  123 + <artifactId>maven-source-plugin</artifactId>
  124 + <executions>
  125 + <execution>
  126 + <id>attach-sources</id>
  127 + <goals>
  128 + <goal>jar</goal>
  129 + </goals>
  130 + </execution>
  131 + </executions>
  132 + </plugin>
  133 + <plugin>
  134 + <groupId>org.apache.maven.plugins</groupId>
  135 + <artifactId>maven-deploy-plugin</artifactId>
  136 + <configuration>
  137 + <skip>false</skip>
  138 + </configuration>
  139 + </plugin>
  140 + </plugins>
  141 + </build>
  142 +
  143 +
  144 +</project>
common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java renamed from application/src/main/java/org/thingsboard/server/service/queue/TbClusterService.java
@@ -13,26 +13,29 @@ @@ -13,26 +13,29 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.thingsboard.server.service.queue; 16 +package org.thingsboard.server.cluster;
17 17
18 -import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 18 +import org.thingsboard.server.common.data.edge.EdgeEventActionType;
  19 +import org.thingsboard.server.common.data.edge.EdgeEventType;
  20 +import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
19 import org.thingsboard.server.common.data.ApiUsageState; 21 import org.thingsboard.server.common.data.ApiUsageState;
20 import org.thingsboard.server.common.data.Device; 22 import org.thingsboard.server.common.data.Device;
21 import org.thingsboard.server.common.data.DeviceProfile; 23 import org.thingsboard.server.common.data.DeviceProfile;
22 import org.thingsboard.server.common.data.TbResource; 24 import org.thingsboard.server.common.data.TbResource;
23 import org.thingsboard.server.common.data.Tenant; 25 import org.thingsboard.server.common.data.Tenant;
24 import org.thingsboard.server.common.data.TenantProfile; 26 import org.thingsboard.server.common.data.TenantProfile;
  27 +import org.thingsboard.server.common.data.id.DeviceId;
25 import org.thingsboard.server.common.data.id.EdgeId; 28 import org.thingsboard.server.common.data.id.EdgeId;
26 import org.thingsboard.server.common.data.id.EntityId; 29 import org.thingsboard.server.common.data.id.EntityId;
27 import org.thingsboard.server.common.data.id.TenantId; 30 import org.thingsboard.server.common.data.id.TenantId;
28 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 31 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
29 import org.thingsboard.server.common.msg.TbMsg; 32 import org.thingsboard.server.common.msg.TbMsg;
30 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 33 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
  34 +import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse;
31 import org.thingsboard.server.gen.transport.TransportProtos; 35 import org.thingsboard.server.gen.transport.TransportProtos;
32 import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; 36 import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
33 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; 37 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
34 import org.thingsboard.server.queue.TbQueueCallback; 38 import org.thingsboard.server.queue.TbQueueCallback;
35 -import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;  
36 39
37 import java.util.UUID; 40 import java.util.UUID;
38 41
@@ -54,7 +57,7 @@ public interface TbClusterService { @@ -54,7 +57,7 @@ public interface TbClusterService {
54 57
55 void pushNotificationToTransport(String targetServiceId, ToTransportMsg response, TbQueueCallback callback); 58 void pushNotificationToTransport(String targetServiceId, ToTransportMsg response, TbQueueCallback callback);
56 59
57 - void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state); 60 + void broadcastEntityStateChangeEvent(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state);
58 61
59 void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback); 62 void onDeviceProfileChange(DeviceProfile deviceProfile, TbQueueCallback callback);
60 63
@@ -70,7 +73,7 @@ public interface TbClusterService { @@ -70,7 +73,7 @@ public interface TbClusterService {
70 73
71 void onApiStateChange(ApiUsageState apiUsageState, TbQueueCallback callback); 74 void onApiStateChange(ApiUsageState apiUsageState, TbQueueCallback callback);
72 75
73 - void onDeviceChange(Device device, TbQueueCallback callback); 76 + void onDeviceUpdated(Device device, Device old);
74 77
75 void onDeviceDeleted(Device device, TbQueueCallback callback); 78 void onDeviceDeleted(Device device, TbQueueCallback callback);
76 79
@@ -79,4 +82,6 @@ public interface TbClusterService { @@ -79,4 +82,6 @@ public interface TbClusterService {
79 void onResourceDeleted(TbResource resource, TbQueueCallback callback); 82 void onResourceDeleted(TbResource resource, TbQueueCallback callback);
80 83
81 void onEdgeEventUpdate(TenantId tenantId, EdgeId edgeId); 84 void onEdgeEventUpdate(TenantId tenantId, EdgeId edgeId);
  85 +
  86 + void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action);
82 } 87 }
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueAdmin.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueCallback.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueCallback.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueConsumer.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueConsumer.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueHandler.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueHandler.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueMsg.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueMsg.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueMsgDecoder.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueMsgDecoder.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueMsgHeaders.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueMsgHeaders.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueMsgMetadata.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueMsgMetadata.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueProducer.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueProducer.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueRequestTemplate.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueRequestTemplate.java
common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueResponseTemplate.java renamed from common/queue/src/main/java/org/thingsboard/server/queue/TbQueueResponseTemplate.java
common/cluster-api/src/main/proto/jsinvoke.proto renamed from common/queue/src/main/proto/jsinvoke.proto
common/cluster-api/src/main/proto/queue.proto renamed from common/queue/src/main/proto/queue.proto
@@ -54,6 +54,8 @@ public interface DeviceService { @@ -54,6 +54,8 @@ public interface DeviceService {
54 54
55 Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials); 55 Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials);
56 56
  57 + Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile);
  58 +
57 void createAccessTokenCredentials(Device device, String accessToken); 59 void createAccessTokenCredentials(Device device, String accessToken);
58 60
59 Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId); 61 Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId);
@@ -100,8 +102,6 @@ public interface DeviceService { @@ -100,8 +102,6 @@ public interface DeviceService {
100 102
101 Device assignDeviceToTenant(TenantId tenantId, Device device); 103 Device assignDeviceToTenant(TenantId tenantId, Device device);
102 104
103 - Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile);  
104 -  
105 PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink); 105 PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink);
106 106
107 Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); 107 Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId);