Commit 6b3448d10fc07f95591eec94041f81d5214d9d23

Authored by ShvaykaD
2 parents 22c91039 08de78a8

Merge branch 'master' of github.com:thingsboard/thingsboard

Showing 79 changed files with 2655 additions and 514 deletions

Too many changes to show.

To preserve performance only 79 of 165 files are displayed.

@@ -33,3 +33,5 @@ pom.xml.versionsBackup @@ -33,3 +33,5 @@ pom.xml.versionsBackup
33 **/.env 33 **/.env
34 .instance_id 34 .instance_id
35 rebuild-docker.sh 35 rebuild-docker.sh
  36 +.run/**
  37 +.run
@@ -194,6 +194,14 @@ @@ -194,6 +194,14 @@
194 <artifactId>javax.mail</artifactId> 194 <artifactId>javax.mail</artifactId>
195 </dependency> 195 </dependency>
196 <dependency> 196 <dependency>
  197 + <groupId>com.twilio.sdk</groupId>
  198 + <artifactId>twilio</artifactId>
  199 + </dependency>
  200 + <dependency>
  201 + <groupId>com.amazonaws</groupId>
  202 + <artifactId>aws-java-sdk-sns</artifactId>
  203 + </dependency>
  204 + <dependency>
197 <groupId>org.apache.curator</groupId> 205 <groupId>org.apache.curator</groupId>
198 <artifactId>curator-recipes</artifactId> 206 <artifactId>curator-recipes</artifactId>
199 </dependency> 207 </dependency>
@@ -219,8 +219,8 @@ @@ -219,8 +219,8 @@
219 "defaultPageSize": 10, 219 "defaultPageSize": 10,
220 "defaultSortOrder": "-createdTime", 220 "defaultSortOrder": "-createdTime",
221 "enableSelectColumnDisplay": false, 221 "enableSelectColumnDisplay": false,
222 - "enableStatusFilter": true,  
223 - "alarmsTitle": "Alarms" 222 + "alarmsTitle": "Alarms",
  223 + "enableFilter": true
224 }, 224 },
225 "title": "New Alarms table", 225 "title": "New Alarms table",
226 "dropShadow": true, 226 "dropShadow": true,
@@ -234,6 +234,9 @@ @@ -234,6 +234,9 @@
234 "showLegend": false, 234 "showLegend": false,
235 "alarmSource": { 235 "alarmSource": {
236 "type": "entity", 236 "type": "entity",
  237 + "name": "alarms",
  238 + "entityAliasId": "68a058e1-fdda-8482-715b-3ae4a488568e",
  239 + "filterId": null,
237 "dataKeys": [ 240 "dataKeys": [
238 { 241 {
239 "name": "createdTime", 242 "name": "createdTime",
@@ -275,9 +278,7 @@ @@ -275,9 +278,7 @@
275 "settings": {}, 278 "settings": {},
276 "_hash": 0.7977920750136249 279 "_hash": 0.7977920750136249
277 } 280 }
278 - ],  
279 - "entityAliasId": "ce27a9d0-93bf-b7a4-054d-d0369a8cf813",  
280 - "name": "alarms" 281 + ]
281 }, 282 },
282 "alarmSearchStatus": "ANY", 283 "alarmSearchStatus": "ANY",
283 "alarmsPollingInterval": 5, 284 "alarmsPollingInterval": 5,
@@ -1031,7 +1032,8 @@ @@ -1031,7 +1032,8 @@
1031 "markerImageFunction": "var res;\nif(dsData[dsIndex].active !== \"true\"){\n\tvar res = {\n\t url: images[0],\n\t size: 48\n\t}\n} else {\n var res = {\n\t url: images[1],\n\t size: 48\n\t}\n}\nreturn res;", 1032 "markerImageFunction": "var res;\nif(dsData[dsIndex].active !== \"true\"){\n\tvar res = {\n\t url: images[0],\n\t size: 48\n\t}\n} else {\n var res = {\n\t url: images[1],\n\t size: 48\n\t}\n}\nreturn res;",
1032 "useLabelFunction": true, 1033 "useLabelFunction": true,
1033 "provider": "openstreet-map", 1034 "provider": "openstreet-map",
1034 - "draggableMarker": true 1035 + "draggableMarker": true,
  1036 + "editablePolygon": true
1035 }, 1037 },
1036 "title": "New Markers Placement - OpenStreetMap", 1038 "title": "New Markers Placement - OpenStreetMap",
1037 "dropShadow": true, 1039 "dropShadow": true,
@@ -1062,61 +1064,6 @@ @@ -1062,61 +1064,6 @@
1062 "displayTimewindow": true 1064 "displayTimewindow": true
1063 }, 1065 },
1064 "id": "0a430429-9078-9ae6-2b67-e4a15a2bf8bf" 1066 "id": "0a430429-9078-9ae6-2b67-e4a15a2bf8bf"
1065 - },  
1066 - "f4bb2f2d-0164-60bc-f3e8-9b1e7b5a59b3": {  
1067 - "isSystemType": true,  
1068 - "bundleAlias": "input_widgets",  
1069 - "typeAlias": "update_double_timeseries",  
1070 - "type": "latest",  
1071 - "title": "New widget",  
1072 - "sizeX": 7.5,  
1073 - "sizeY": 3,  
1074 - "config": {  
1075 - "datasources": [  
1076 - {  
1077 - "type": "entity",  
1078 - "name": null,  
1079 - "entityAliasId": "12ae98c7-1ea2-52cf-64d5-763e9d993547",  
1080 - "dataKeys": [  
1081 - {  
1082 - "name": "temperature",  
1083 - "type": "timeseries",  
1084 - "label": "temperature",  
1085 - "color": "#2196f3",  
1086 - "settings": {},  
1087 - "_hash": 0.4164505192982848  
1088 - }  
1089 - ]  
1090 - }  
1091 - ],  
1092 - "timewindow": {  
1093 - "realtime": {  
1094 - "timewindowMs": 60000  
1095 - }  
1096 - },  
1097 - "showTitle": true,  
1098 - "backgroundColor": "#fff",  
1099 - "color": "rgba(0, 0, 0, 0.87)",  
1100 - "padding": "8px",  
1101 - "settings": {  
1102 - "showResultMessage": true,  
1103 - "showLabel": true  
1104 - },  
1105 - "title": "New Update double timeseries",  
1106 - "dropShadow": true,  
1107 - "enableFullscreen": false,  
1108 - "widgetStyle": {},  
1109 - "titleStyle": {  
1110 - "fontSize": "16px",  
1111 - "fontWeight": 400  
1112 - },  
1113 - "useDashboardTimewindow": true,  
1114 - "showLegend": false,  
1115 - "actions": {}  
1116 - },  
1117 - "row": 0,  
1118 - "col": 0,  
1119 - "id": "f4bb2f2d-0164-60bc-f3e8-9b1e7b5a59b3"  
1120 } 1067 }
1121 }, 1068 },
1122 "states": { 1069 "states": {
@@ -1215,12 +1162,6 @@ @@ -1215,12 +1162,6 @@
1215 "sizeY": 6, 1162 "sizeY": 6,
1216 "row": 6, 1163 "row": 6,
1217 "col": 0 1164 "col": 0
1218 - },  
1219 - "f4bb2f2d-0164-60bc-f3e8-9b1e7b5a59b3": {  
1220 - "sizeX": 7.5,  
1221 - "sizeY": 3,  
1222 - "row": 12,  
1223 - "col": 0  
1224 } 1165 }
1225 }, 1166 },
1226 "gridSettings": { 1167 "gridSettings": {
@@ -1257,16 +1198,6 @@ @@ -1257,16 +1198,6 @@
1257 "stateEntityParamName": null, 1198 "stateEntityParamName": null,
1258 "defaultStateEntity": null 1199 "defaultStateEntity": null
1259 } 1200 }
1260 - },  
1261 - "ce27a9d0-93bf-b7a4-054d-d0369a8cf813": {  
1262 - "id": "ce27a9d0-93bf-b7a4-054d-d0369a8cf813",  
1263 - "alias": "Thermostat-alarm",  
1264 - "filter": {  
1265 - "type": "entityName",  
1266 - "resolveMultiple": false,  
1267 - "entityType": "ASSET",  
1268 - "entityNameFilter": "Thermostat Alarms"  
1269 - }  
1270 } 1201 }
1271 }, 1202 },
1272 "timewindow": { 1203 "timewindow": {
@@ -1301,7 +1232,8 @@ @@ -1301,7 +1232,8 @@
1301 "showDashboardTimewindow": true, 1232 "showDashboardTimewindow": true,
1302 "showDashboardExport": true, 1233 "showDashboardExport": true,
1303 "toolbarAlwaysOpen": true 1234 "toolbarAlwaysOpen": true
1304 - } 1235 + },
  1236 + "filters": {}
1305 }, 1237 },
1306 "name": "Thermostats" 1238 "name": "Thermostats"
1307 } 1239 }
1 { 1 {
2 "ruleChain": { 2 "ruleChain": {
3 - "additionalInfo": null, 3 + "additionalInfo": {
  4 + "description": ""
  5 + },
4 "name": "Thermostat Alarms", 6 "name": "Thermostat Alarms",
5 "firstRuleNodeId": null, 7 "firstRuleNodeId": null,
6 "root": false, 8 "root": false,
@@ -8,131 +10,126 @@ @@ -8,131 +10,126 @@
8 "configuration": null 10 "configuration": null
9 }, 11 },
10 "metadata": { 12 "metadata": {
11 - "firstNodeIndex": 5, 13 + "firstNodeIndex": 6,
12 "nodes": [ 14 "nodes": [
13 { 15 {
14 "additionalInfo": { 16 "additionalInfo": {
15 - "layoutX": 929,  
16 - "layoutY": 67 17 + "layoutX": 822,
  18 + "layoutY": 294
17 }, 19 },
18 - "type": "org.thingsboard.rule.engine.action.TbCreateAlarmNode",  
19 - "name": "Create Temp Alarm", 20 + "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
  21 + "name": "Save Timeseries",
20 "debugMode": false, 22 "debugMode": false,
21 "configuration": { 23 "configuration": {
22 - "alarmType": "High Temperature",  
23 - "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\ndetails.triggerValue = msg.temperature;\nreturn details;",  
24 - "severity": "MAJOR",  
25 - "propagate": true,  
26 - "useMessageAlarmData": false,  
27 - "relationTypes": [  
28 - "ToAlarmPropagationAsset"  
29 - ] 24 + "defaultTTL": 0
30 } 25 }
31 }, 26 },
32 { 27 {
33 "additionalInfo": { 28 "additionalInfo": {
34 - "layoutX": 930,  
35 - "layoutY": 201 29 + "description": null,
  30 + "layoutX": 824,
  31 + "layoutY": 221
36 }, 32 },
37 - "type": "org.thingsboard.rule.engine.action.TbClearAlarmNode",  
38 - "name": "Clear Temp Alarm", 33 + "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode",
  34 + "name": "Save Client Attributes",
39 "debugMode": false, 35 "debugMode": false,
40 "configuration": { 36 "configuration": {
41 - "alarmType": "High Temperature",  
42 - "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\nreturn details;" 37 + "scope": "SERVER_SCOPE",
  38 + "notifyDevice": null
43 } 39 }
44 }, 40 },
45 { 41 {
46 "additionalInfo": { 42 "additionalInfo": {
47 - "layoutX": 930,  
48 - "layoutY": 131 43 + "layoutX": 494,
  44 + "layoutY": 309
49 }, 45 },
50 - "type": "org.thingsboard.rule.engine.action.TbCreateAlarmNode",  
51 - "name": "Create Humidity Alarm", 46 + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode",
  47 + "name": "Message Type Switch",
52 "debugMode": false, 48 "debugMode": false,
53 "configuration": { 49 "configuration": {
54 - "alarmType": "Low Humidity",  
55 - "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\ndetails.triggerValue = msg.humidity;\nreturn details;",  
56 - "severity": "MINOR",  
57 - "propagate": true,  
58 - "useMessageAlarmData": false,  
59 - "relationTypes": [  
60 - "ToAlarmPropagationAsset"  
61 - ] 50 + "version": 0
62 } 51 }
63 }, 52 },
64 { 53 {
65 "additionalInfo": { 54 "additionalInfo": {
66 - "layoutX": 929,  
67 - "layoutY": 275 55 + "layoutX": 824,
  56 + "layoutY": 383
68 }, 57 },
69 - "type": "org.thingsboard.rule.engine.action.TbClearAlarmNode",  
70 - "name": "Clear Humidity Alarm", 58 + "type": "org.thingsboard.rule.engine.action.TbLogNode",
  59 + "name": "Log RPC from Device",
71 "debugMode": false, 60 "debugMode": false,
72 "configuration": { 61 "configuration": {
73 - "alarmType": "Low Humidity",  
74 - "alarmDetailsBuildJs": "var details = {};\nif (metadata.prevAlarmDetails) {\n details = JSON.parse(metadata.prevAlarmDetails);\n}\nreturn details;" 62 + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
75 } 63 }
76 }, 64 },
77 { 65 {
78 "additionalInfo": { 66 "additionalInfo": {
79 - "layoutX": 586,  
80 - "layoutY": 148 67 + "layoutX": 823,
  68 + "layoutY": 444
81 }, 69 },
82 - "type": "org.thingsboard.rule.engine.filter.TbJsSwitchNode",  
83 - "name": "Check Alarms", 70 + "type": "org.thingsboard.rule.engine.action.TbLogNode",
  71 + "name": "Log Other",
84 "debugMode": false, 72 "debugMode": false,
85 "configuration": { 73 "configuration": {
86 - "jsScript": "var relations = [];\nif(metadata[\"ss_alarmTemperature\"] === \"true\"){\n if(msg.temperature > metadata[\"ss_thresholdTemperature\"]){\n relations.push(\"NewTempAlarm\");\n } else {\n relations.push(\"ClearTempAlarm\");\n }\n}\nif(metadata[\"ss_alarmHumidity\"] === \"true\"){\n if(msg.humidity < metadata[\"ss_thresholdHumidity\"]){\n relations.push(\"NewHumidityAlarm\");\n } else {\n relations.push(\"ClearHumidityAlarm\");\n }\n}\n\nreturn relations;" 74 + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
87 } 75 }
88 }, 76 },
89 { 77 {
90 "additionalInfo": { 78 "additionalInfo": {
91 - "layoutX": 321,  
92 - "layoutY": 149 79 + "layoutX": 822,
  80 + "layoutY": 507
93 }, 81 },
94 - "type": "org.thingsboard.rule.engine.metadata.TbGetAttributesNode",  
95 - "name": "Fetch Configuration", 82 + "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode",
  83 + "name": "RPC Call Request",
96 "debugMode": false, 84 "debugMode": false,
97 "configuration": { 85 "configuration": {
98 - "clientAttributeNames": [],  
99 - "sharedAttributeNames": [],  
100 - "serverAttributeNames": [  
101 - "alarmTemperature",  
102 - "thresholdTemperature",  
103 - "alarmHumidity",  
104 - "thresholdHumidity"  
105 - ],  
106 - "latestTsKeyNames": [],  
107 - "tellFailureIfAbsent": false,  
108 - "getLatestValueWithTs": false 86 + "timeoutInSeconds": 60
  87 + }
  88 + },
  89 + {
  90 + "additionalInfo": {
  91 + "description": "",
  92 + "layoutX": 209,
  93 + "layoutY": 307
  94 + },
  95 + "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode",
  96 + "name": "Device Profile Node",
  97 + "debugMode": false,
  98 + "configuration": {
  99 + "persistAlarmRulesState": false,
  100 + "fetchAlarmRulesStateOnStart": false
109 } 101 }
110 } 102 }
111 ], 103 ],
112 "connections": [ 104 "connections": [
113 { 105 {
114 - "fromIndex": 4,  
115 - "toIndex": 0,  
116 - "type": "NewTempAlarm" 106 + "fromIndex": 2,
  107 + "toIndex": 4,
  108 + "type": "Other"
117 }, 109 },
118 { 110 {
119 - "fromIndex": 4, 111 + "fromIndex": 2,
120 "toIndex": 1, 112 "toIndex": 1,
121 - "type": "ClearTempAlarm" 113 + "type": "Post attributes"
122 }, 114 },
123 { 115 {
124 - "fromIndex": 4,  
125 - "toIndex": 2,  
126 - "type": "NewHumidityAlarm" 116 + "fromIndex": 2,
  117 + "toIndex": 0,
  118 + "type": "Post telemetry"
127 }, 119 },
128 { 120 {
129 - "fromIndex": 4, 121 + "fromIndex": 2,
130 "toIndex": 3, 122 "toIndex": 3,
131 - "type": "ClearHumidityAlarm" 123 + "type": "RPC Request from Device"
132 }, 124 },
133 { 125 {
134 - "fromIndex": 5,  
135 - "toIndex": 4, 126 + "fromIndex": 2,
  127 + "toIndex": 5,
  128 + "type": "RPC Request to Device"
  129 + },
  130 + {
  131 + "fromIndex": 6,
  132 + "toIndex": 2,
136 "type": "Success" 133 "type": "Success"
137 } 134 }
138 ], 135 ],
@@ -32,6 +32,8 @@ import org.springframework.data.redis.core.RedisTemplate; @@ -32,6 +32,8 @@ import org.springframework.data.redis.core.RedisTemplate;
32 import org.springframework.scheduling.annotation.Scheduled; 32 import org.springframework.scheduling.annotation.Scheduled;
33 import org.springframework.stereotype.Component; 33 import org.springframework.stereotype.Component;
34 import org.thingsboard.rule.engine.api.MailService; 34 import org.thingsboard.rule.engine.api.MailService;
  35 +import org.thingsboard.rule.engine.api.SmsService;
  36 +import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
35 import org.thingsboard.server.actors.service.ActorService; 37 import org.thingsboard.server.actors.service.ActorService;
36 import org.thingsboard.server.actors.tenant.DebugTbRateLimits; 38 import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
37 import org.thingsboard.server.common.data.DataConstants; 39 import org.thingsboard.server.common.data.DataConstants;
@@ -80,6 +82,7 @@ import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; @@ -80,6 +82,7 @@ import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
80 import org.thingsboard.server.service.script.JsExecutorService; 82 import org.thingsboard.server.service.script.JsExecutorService;
81 import org.thingsboard.server.service.script.JsInvokeService; 83 import org.thingsboard.server.service.script.JsInvokeService;
82 import org.thingsboard.server.service.session.DeviceSessionCacheService; 84 import org.thingsboard.server.service.session.DeviceSessionCacheService;
  85 +import org.thingsboard.server.service.sms.SmsExecutorService;
83 import org.thingsboard.server.service.state.DeviceStateService; 86 import org.thingsboard.server.service.state.DeviceStateService;
84 import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; 87 import org.thingsboard.server.service.telemetry.AlarmSubscriptionService;
85 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; 88 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
@@ -230,6 +233,10 @@ public class ActorSystemContext { @@ -230,6 +233,10 @@ public class ActorSystemContext {
230 233
231 @Autowired 234 @Autowired
232 @Getter 235 @Getter
  236 + private SmsExecutorService smsExecutor;
  237 +
  238 + @Autowired
  239 + @Getter
233 private DbCallbackExecutorService dbCallbackExecutor; 240 private DbCallbackExecutorService dbCallbackExecutor;
234 241
235 @Autowired 242 @Autowired
@@ -246,6 +253,14 @@ public class ActorSystemContext { @@ -246,6 +253,14 @@ public class ActorSystemContext {
246 253
247 @Autowired 254 @Autowired
248 @Getter 255 @Getter
  256 + private SmsService smsService;
  257 +
  258 + @Autowired
  259 + @Getter
  260 + private SmsSenderFactory smsSenderFactory;
  261 +
  262 + @Autowired
  263 + @Getter
249 private ClaimDevicesService claimDevicesService; 264 private ClaimDevicesService claimDevicesService;
250 265
251 @Autowired 266 @Autowired
@@ -325,6 +340,10 @@ public class ActorSystemContext { @@ -325,6 +340,10 @@ public class ActorSystemContext {
325 @Getter 340 @Getter
326 private boolean allowSystemMailService; 341 private boolean allowSystemMailService;
327 342
  343 + @Value("${actors.rule.allow_system_sms_service}")
  344 + @Getter
  345 + private boolean allowSystemSmsService;
  346 +
328 @Value("${transport.sessions.inactivity_timeout}") 347 @Value("${transport.sessions.inactivity_timeout}")
329 @Getter 348 @Getter
330 private long sessionInactivityTimeout; 349 private long sessionInactivityTimeout;
@@ -28,10 +28,13 @@ import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache; @@ -28,10 +28,13 @@ import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache;
28 import org.thingsboard.rule.engine.api.RuleEngineRpcService; 28 import org.thingsboard.rule.engine.api.RuleEngineRpcService;
29 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; 29 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
30 import org.thingsboard.rule.engine.api.ScriptEngine; 30 import org.thingsboard.rule.engine.api.ScriptEngine;
  31 +import org.thingsboard.rule.engine.api.SmsService;
31 import org.thingsboard.rule.engine.api.TbContext; 32 import org.thingsboard.rule.engine.api.TbContext;
32 import org.thingsboard.rule.engine.api.TbRelationTypes; 33 import org.thingsboard.rule.engine.api.TbRelationTypes;
  34 +import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
33 import org.thingsboard.server.actors.ActorSystemContext; 35 import org.thingsboard.server.actors.ActorSystemContext;
34 import org.thingsboard.server.actors.TbActorRef; 36 import org.thingsboard.server.actors.TbActorRef;
  37 +import org.thingsboard.server.common.data.ApiUsageRecordKey;
35 import org.thingsboard.server.common.data.Customer; 38 import org.thingsboard.server.common.data.Customer;
36 import org.thingsboard.server.common.data.DataConstants; 39 import org.thingsboard.server.common.data.DataConstants;
37 import org.thingsboard.server.common.data.Device; 40 import org.thingsboard.server.common.data.Device;
@@ -303,6 +306,11 @@ class DefaultTbContext implements TbContext { @@ -303,6 +306,11 @@ class DefaultTbContext implements TbContext {
303 } 306 }
304 307
305 @Override 308 @Override
  309 + public ListeningExecutor getSmsExecutor() {
  310 + return mainCtx.getSmsExecutor();
  311 + }
  312 +
  313 + @Override
306 public ListeningExecutor getDbCallbackExecutor() { 314 public ListeningExecutor getDbCallbackExecutor() {
307 return mainCtx.getDbCallbackExecutor(); 315 return mainCtx.getDbCallbackExecutor();
308 } 316 }
@@ -428,6 +436,20 @@ class DefaultTbContext implements TbContext { @@ -428,6 +436,20 @@ class DefaultTbContext implements TbContext {
428 } 436 }
429 437
430 @Override 438 @Override
  439 + public SmsService getSmsService() {
  440 + if (mainCtx.isAllowSystemSmsService()) {
  441 + return mainCtx.getSmsService();
  442 + } else {
  443 + throw new RuntimeException("Access to System SMS Service is forbidden!");
  444 + }
  445 + }
  446 +
  447 + @Override
  448 + public SmsSenderFactory getSmsSenderFactory() {
  449 + return mainCtx.getSmsSenderFactory();
  450 + }
  451 +
  452 + @Override
431 public RuleEngineRpcService getRpcService() { 453 public RuleEngineRpcService getRpcService() {
432 return mainCtx.getTbRuleEngineDeviceRpcService(); 454 return mainCtx.getTbRuleEngineDeviceRpcService();
433 } 455 }
@@ -25,6 +25,8 @@ import org.springframework.web.bind.annotation.RequestMethod; @@ -25,6 +25,8 @@ 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.MailService; 27 import org.thingsboard.rule.engine.api.MailService;
  28 +import org.thingsboard.rule.engine.api.SmsService;
  29 +import org.thingsboard.rule.engine.api.sms.config.TestSmsRequest;
28 import org.thingsboard.server.common.data.AdminSettings; 30 import org.thingsboard.server.common.data.AdminSettings;
29 import org.thingsboard.server.common.data.UpdateMessage; 31 import org.thingsboard.server.common.data.UpdateMessage;
30 import org.thingsboard.server.common.data.exception.ThingsboardException; 32 import org.thingsboard.server.common.data.exception.ThingsboardException;
@@ -46,6 +48,9 @@ public class AdminController extends BaseController { @@ -46,6 +48,9 @@ public class AdminController extends BaseController {
46 private MailService mailService; 48 private MailService mailService;
47 49
48 @Autowired 50 @Autowired
  51 + private SmsService smsService;
  52 +
  53 + @Autowired
49 private AdminSettingsService adminSettingsService; 54 private AdminSettingsService adminSettingsService;
50 55
51 @Autowired 56 @Autowired
@@ -80,6 +85,8 @@ public class AdminController extends BaseController { @@ -80,6 +85,8 @@ public class AdminController extends BaseController {
80 if (adminSettings.getKey().equals("mail")) { 85 if (adminSettings.getKey().equals("mail")) {
81 mailService.updateMailConfiguration(); 86 mailService.updateMailConfiguration();
82 ((ObjectNode) adminSettings.getJsonValue()).put("password", ""); 87 ((ObjectNode) adminSettings.getJsonValue()).put("password", "");
  88 + } else if (adminSettings.getKey().equals("sms")) {
  89 + smsService.updateSmsConfiguration();
83 } 90 }
84 return adminSettings; 91 return adminSettings;
85 } catch (Exception e) { 92 } catch (Exception e) {
@@ -128,6 +135,17 @@ public class AdminController extends BaseController { @@ -128,6 +135,17 @@ public class AdminController extends BaseController {
128 } 135 }
129 136
130 @PreAuthorize("hasAuthority('SYS_ADMIN')") 137 @PreAuthorize("hasAuthority('SYS_ADMIN')")
  138 + @RequestMapping(value = "/settings/testSms", method = RequestMethod.POST)
  139 + public void sendTestSms(@RequestBody TestSmsRequest testSmsRequest) throws ThingsboardException {
  140 + try {
  141 + accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
  142 + smsService.sendTestSms(testSmsRequest);
  143 + } catch (Exception e) {
  144 + throw handleException(e);
  145 + }
  146 + }
  147 +
  148 + @PreAuthorize("hasAuthority('SYS_ADMIN')")
131 @RequestMapping(value = "/updates", method = RequestMethod.GET) 149 @RequestMapping(value = "/updates", method = RequestMethod.GET)
132 @ResponseBody 150 @ResponseBody
133 public UpdateMessage checkUpdates() throws ThingsboardException { 151 public UpdateMessage checkUpdates() throws ThingsboardException {
@@ -118,6 +118,7 @@ public class DeviceController extends BaseController { @@ -118,6 +118,7 @@ public class DeviceController extends BaseController {
118 118
119 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); 119 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
120 120
  121 + tbClusterService.onDeviceChange(savedDevice, null);
121 tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(), 122 tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),
122 savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null); 123 savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null);
123 tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), 124 tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(),
@@ -150,6 +151,9 @@ public class DeviceController extends BaseController { @@ -150,6 +151,9 @@ public class DeviceController extends BaseController {
150 Device device = checkDeviceId(deviceId, Operation.DELETE); 151 Device device = checkDeviceId(deviceId, Operation.DELETE);
151 deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId); 152 deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId);
152 153
  154 + tbClusterService.onDeviceDeleted(device, null);
  155 + tbClusterService.onEntityStateChange(device.getTenantId(), deviceId, ComponentLifecycleEvent.DELETED);
  156 +
153 logEntityAction(deviceId, device, 157 logEntityAction(deviceId, device,
154 device.getCustomerId(), 158 device.getCustomerId(),
155 ActionType.DELETED, null, strDeviceId); 159 ActionType.DELETED, null, strDeviceId);
@@ -17,21 +17,21 @@ package org.thingsboard.server.service.apiusage; @@ -17,21 +17,21 @@ package org.thingsboard.server.service.apiusage;
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.apache.commons.lang3.StringUtils;
20 import org.checkerframework.checker.nullness.qual.Nullable; 21 import org.checkerframework.checker.nullness.qual.Nullable;
21 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.beans.factory.annotation.Value; 23 import org.springframework.beans.factory.annotation.Value;
23 -import org.springframework.boot.context.event.ApplicationReadyEvent;  
24 import org.springframework.context.annotation.Lazy; 24 import org.springframework.context.annotation.Lazy;
25 -import org.springframework.context.event.EventListener;  
26 -import org.springframework.core.annotation.Order;  
27 -import org.springframework.data.util.Pair;  
28 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
  26 +import org.thingsboard.rule.engine.api.MailService;
29 import org.thingsboard.server.common.data.ApiFeature; 27 import org.thingsboard.server.common.data.ApiFeature;
30 import org.thingsboard.server.common.data.ApiUsageRecordKey; 28 import org.thingsboard.server.common.data.ApiUsageRecordKey;
31 import org.thingsboard.server.common.data.ApiUsageState; 29 import org.thingsboard.server.common.data.ApiUsageState;
  30 +import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
32 import org.thingsboard.server.common.data.ApiUsageStateValue; 31 import org.thingsboard.server.common.data.ApiUsageStateValue;
33 import org.thingsboard.server.common.data.Tenant; 32 import org.thingsboard.server.common.data.Tenant;
34 import org.thingsboard.server.common.data.TenantProfile; 33 import org.thingsboard.server.common.data.TenantProfile;
  34 +import org.thingsboard.server.common.data.exception.ThingsboardException;
35 import org.thingsboard.server.common.data.id.ApiUsageStateId; 35 import org.thingsboard.server.common.data.id.ApiUsageStateId;
36 import org.thingsboard.server.common.data.id.TenantId; 36 import org.thingsboard.server.common.data.id.TenantId;
37 import org.thingsboard.server.common.data.id.TenantProfileId; 37 import org.thingsboard.server.common.data.id.TenantProfileId;
@@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; @@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
45 import org.thingsboard.server.common.msg.queue.ServiceType; 45 import org.thingsboard.server.common.msg.queue.ServiceType;
46 import org.thingsboard.server.common.msg.queue.TbCallback; 46 import org.thingsboard.server.common.msg.queue.TbCallback;
47 import org.thingsboard.server.common.msg.tools.SchedulerUtils; 47 import org.thingsboard.server.common.msg.tools.SchedulerUtils;
  48 +import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
48 import org.thingsboard.server.dao.tenant.TenantService; 49 import org.thingsboard.server.dao.tenant.TenantService;
49 import org.thingsboard.server.dao.timeseries.TimeseriesService; 50 import org.thingsboard.server.dao.timeseries.TimeseriesService;
50 import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; 51 import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
@@ -54,14 +55,12 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -54,14 +55,12 @@ import org.thingsboard.server.queue.common.TbProtoQueueMsg;
54 import org.thingsboard.server.queue.discovery.PartitionChangeEvent; 55 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
55 import org.thingsboard.server.queue.discovery.PartitionService; 56 import org.thingsboard.server.queue.discovery.PartitionService;
56 import org.thingsboard.server.queue.scheduler.SchedulerComponent; 57 import org.thingsboard.server.queue.scheduler.SchedulerComponent;
57 -import org.thingsboard.server.queue.util.TbCoreComponent;  
58 -import org.thingsboard.server.dao.tenant.TbTenantProfileCache;  
59 import org.thingsboard.server.service.queue.TbClusterService; 58 import org.thingsboard.server.service.queue.TbClusterService;
60 import org.thingsboard.server.service.telemetry.InternalTelemetryService; 59 import org.thingsboard.server.service.telemetry.InternalTelemetryService;
61 60
62 import javax.annotation.PostConstruct; 61 import javax.annotation.PostConstruct;
  62 +import javax.annotation.PreDestroy;
63 import java.util.ArrayList; 63 import java.util.ArrayList;
64 -import java.util.HashMap;  
65 import java.util.HashSet; 64 import java.util.HashSet;
66 import java.util.List; 65 import java.util.List;
67 import java.util.Map; 66 import java.util.Map;
@@ -69,6 +68,8 @@ import java.util.Set; @@ -69,6 +68,8 @@ import java.util.Set;
69 import java.util.UUID; 68 import java.util.UUID;
70 import java.util.concurrent.ConcurrentHashMap; 69 import java.util.concurrent.ConcurrentHashMap;
71 import java.util.concurrent.ExecutionException; 70 import java.util.concurrent.ExecutionException;
  71 +import java.util.concurrent.ExecutorService;
  72 +import java.util.concurrent.Executors;
72 import java.util.concurrent.TimeUnit; 73 import java.util.concurrent.TimeUnit;
73 import java.util.concurrent.locks.Lock; 74 import java.util.concurrent.locks.Lock;
74 import java.util.concurrent.locks.ReentrantLock; 75 import java.util.concurrent.locks.ReentrantLock;
@@ -94,6 +95,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @@ -94,6 +95,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
94 private final ApiUsageStateService apiUsageStateService; 95 private final ApiUsageStateService apiUsageStateService;
95 private final SchedulerComponent scheduler; 96 private final SchedulerComponent scheduler;
96 private final TbTenantProfileCache tenantProfileCache; 97 private final TbTenantProfileCache tenantProfileCache;
  98 + private final MailService mailService;
97 99
98 @Lazy 100 @Lazy
99 @Autowired 101 @Autowired
@@ -112,13 +114,15 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @@ -112,13 +114,15 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
112 114
113 private final Lock updateLock = new ReentrantLock(); 115 private final Lock updateLock = new ReentrantLock();
114 116
  117 + private final ExecutorService mailExecutor;
  118 +
115 public DefaultTbApiUsageStateService(TbClusterService clusterService, 119 public DefaultTbApiUsageStateService(TbClusterService clusterService,
116 PartitionService partitionService, 120 PartitionService partitionService,
117 TenantService tenantService, 121 TenantService tenantService,
118 TimeseriesService tsService, 122 TimeseriesService tsService,
119 ApiUsageStateService apiUsageStateService, 123 ApiUsageStateService apiUsageStateService,
120 SchedulerComponent scheduler, 124 SchedulerComponent scheduler,
121 - TbTenantProfileCache tenantProfileCache) { 125 + TbTenantProfileCache tenantProfileCache, MailService mailService) {
122 this.clusterService = clusterService; 126 this.clusterService = clusterService;
123 this.partitionService = partitionService; 127 this.partitionService = partitionService;
124 this.tenantService = tenantService; 128 this.tenantService = tenantService;
@@ -126,6 +130,8 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @@ -126,6 +130,8 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
126 this.apiUsageStateService = apiUsageStateService; 130 this.apiUsageStateService = apiUsageStateService;
127 this.scheduler = scheduler; 131 this.scheduler = scheduler;
128 this.tenantProfileCache = tenantProfileCache; 132 this.tenantProfileCache = tenantProfileCache;
  133 + this.mailService = mailService;
  134 + this.mailExecutor = Executors.newSingleThreadExecutor();
129 } 135 }
130 136
131 @PostConstruct 137 @PostConstruct
@@ -286,7 +292,49 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @@ -286,7 +292,49 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
286 List<TsKvEntry> stateTelemetry = new ArrayList<>(); 292 List<TsKvEntry> stateTelemetry = new ArrayList<>();
287 result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name()))))); 293 result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name())))));
288 tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); 294 tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK);
289 - //TODO: notify tenant admin via email! 295 +
  296 + String email = tenantService.findTenantById(state.getTenantId()).getEmail();
  297 +
  298 + if (StringUtils.isNotEmpty(email)) {
  299 + result.forEach((apiFeature, stateValue) -> {
  300 + mailExecutor.submit(() -> {
  301 + try {
  302 + mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage(state, apiFeature, stateValue));
  303 + } catch (ThingsboardException e) {
  304 + log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e);
  305 + }
  306 + });
  307 + });
  308 + } else {
  309 + log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId());
  310 + }
  311 + }
  312 +
  313 + private ApiUsageStateMailMessage createStateMailMessage(TenantApiUsageState state, ApiFeature apiFeature, ApiUsageStateValue stateValue) {
  314 + StateChecker checker = getStateChecker(stateValue);
  315 + for (ApiUsageRecordKey apiUsageRecordKey : ApiUsageRecordKey.getKeys(apiFeature)) {
  316 + long threshold = state.getProfileThreshold(apiUsageRecordKey);
  317 + long warnThreshold = state.getProfileWarnThreshold(apiUsageRecordKey);
  318 + long value = state.get(apiUsageRecordKey);
  319 + if (checker.check(threshold, warnThreshold, value)) {
  320 + return new ApiUsageStateMailMessage(apiUsageRecordKey, threshold, value);
  321 + }
  322 + }
  323 + return null;
  324 + }
  325 +
  326 + private StateChecker getStateChecker(ApiUsageStateValue stateValue) {
  327 + if (ApiUsageStateValue.ENABLED.equals(stateValue)) {
  328 + return (t, wt, v) -> true;
  329 + } else if (ApiUsageStateValue.WARNING.equals(stateValue)) {
  330 + return (t, wt, v) -> v < t && v >= wt;
  331 + } else {
  332 + return (t, wt, v) -> v >= t;
  333 + }
  334 + }
  335 +
  336 + private interface StateChecker {
  337 + boolean check(long threshold, long warnThreshold, long value);
290 } 338 }
291 339
292 private void checkStartOfNextCycle() { 340 private void checkStartOfNextCycle() {
@@ -367,4 +415,10 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { @@ -367,4 +415,10 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService {
367 } 415 }
368 } 416 }
369 417
  418 + @PreDestroy
  419 + private void destroy() {
  420 + if (mailExecutor != null) {
  421 + mailExecutor.shutdownNow();
  422 + }
  423 + }
370 } 424 }
@@ -125,6 +125,10 @@ public class TenantApiUsageState { @@ -125,6 +125,10 @@ public class TenantApiUsageState {
125 return apiUsageState.getDbStorageState(); 125 return apiUsageState.getDbStorageState();
126 case JS: 126 case JS:
127 return apiUsageState.getJsExecState(); 127 return apiUsageState.getJsExecState();
  128 + case EMAIL:
  129 + return apiUsageState.getEmailExecState();
  130 + case SMS:
  131 + return apiUsageState.getSmsExecState();
128 default: 132 default:
129 return ApiUsageStateValue.ENABLED; 133 return ApiUsageStateValue.ENABLED;
130 } 134 }
@@ -145,6 +149,12 @@ public class TenantApiUsageState { @@ -145,6 +149,12 @@ public class TenantApiUsageState {
145 case JS: 149 case JS:
146 apiUsageState.setJsExecState(value); 150 apiUsageState.setJsExecState(value);
147 break; 151 break;
  152 + case EMAIL:
  153 + apiUsageState.setEmailExecState(value);
  154 + break;
  155 + case SMS:
  156 + apiUsageState.setSmsExecState(value);
  157 + break;
148 } 158 }
149 return !currentValue.equals(value); 159 return !currentValue.equals(value);
150 } 160 }
@@ -22,6 +22,7 @@ import com.google.common.util.concurrent.Futures; @@ -22,6 +22,7 @@ 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.MoreExecutors; 23 import com.google.common.util.concurrent.MoreExecutors;
24 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.apache.commons.lang.RandomStringUtils;
25 import org.springframework.beans.factory.annotation.Autowired; 26 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.stereotype.Service; 27 import org.springframework.stereotype.Service;
27 import org.springframework.util.StringUtils; 28 import org.springframework.util.StringUtils;
@@ -188,6 +189,11 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService { @@ -188,6 +189,11 @@ public class DeviceProvisionServiceImpl implements DeviceProvisionService {
188 Device device = deviceService.findDeviceByTenantIdAndName(profile.getTenantId(), provisionRequest.getDeviceName()); 189 Device device = deviceService.findDeviceByTenantIdAndName(profile.getTenantId(), provisionRequest.getDeviceName());
189 try { 190 try {
190 if (device == null) { 191 if (device == null) {
  192 + if (StringUtils.isEmpty(provisionRequest.getDeviceName())) {
  193 + String newDeviceName = RandomStringUtils.randomAlphanumeric(20);
  194 + log.info("Device name not found in provision request. Generated name is: {}", newDeviceName);
  195 + provisionRequest.setDeviceName(newDeviceName);
  196 + }
191 Device savedDevice = deviceService.saveDevice(provisionRequest, profile); 197 Device savedDevice = deviceService.saveDevice(provisionRequest, profile);
192 198
193 deviceStateService.onDeviceAdded(savedDevice); 199 deviceStateService.onDeviceAdded(savedDevice);
@@ -28,12 +28,21 @@ import org.thingsboard.server.common.data.Customer; @@ -28,12 +28,21 @@ import org.thingsboard.server.common.data.Customer;
28 import org.thingsboard.server.common.data.DataConstants; 28 import org.thingsboard.server.common.data.DataConstants;
29 import org.thingsboard.server.common.data.Device; 29 import org.thingsboard.server.common.data.Device;
30 import org.thingsboard.server.common.data.DeviceProfile; 30 import org.thingsboard.server.common.data.DeviceProfile;
  31 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
  32 +import org.thingsboard.server.common.data.DeviceProfileType;
  33 +import org.thingsboard.server.common.data.DeviceTransportType;
31 import org.thingsboard.server.common.data.Tenant; 34 import org.thingsboard.server.common.data.Tenant;
32 import org.thingsboard.server.common.data.TenantProfile; 35 import org.thingsboard.server.common.data.TenantProfile;
33 -import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;  
34 -import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;  
35 import org.thingsboard.server.common.data.User; 36 import org.thingsboard.server.common.data.User;
36 -import org.thingsboard.server.common.data.asset.Asset; 37 +import org.thingsboard.server.common.data.alarm.AlarmSeverity;
  38 +import org.thingsboard.server.common.data.device.profile.AlarmCondition;
  39 +import org.thingsboard.server.common.data.device.profile.AlarmRule;
  40 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
  42 +import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
  43 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  44 +import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
  45 +import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec;
37 import org.thingsboard.server.common.data.id.CustomerId; 46 import org.thingsboard.server.common.data.id.CustomerId;
38 import org.thingsboard.server.common.data.id.DeviceId; 47 import org.thingsboard.server.common.data.id.DeviceId;
39 import org.thingsboard.server.common.data.id.DeviceProfileId; 48 import org.thingsboard.server.common.data.id.DeviceProfileId;
@@ -42,19 +51,29 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; @@ -42,19 +51,29 @@ import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
42 import org.thingsboard.server.common.data.kv.BooleanDataEntry; 51 import org.thingsboard.server.common.data.kv.BooleanDataEntry;
43 import org.thingsboard.server.common.data.kv.DoubleDataEntry; 52 import org.thingsboard.server.common.data.kv.DoubleDataEntry;
44 import org.thingsboard.server.common.data.kv.LongDataEntry; 53 import org.thingsboard.server.common.data.kv.LongDataEntry;
45 -import org.thingsboard.server.common.data.relation.EntityRelation; 54 +import org.thingsboard.server.common.data.page.PageLink;
  55 +import org.thingsboard.server.common.data.query.BooleanFilterPredicate;
  56 +import org.thingsboard.server.common.data.query.DynamicValue;
  57 +import org.thingsboard.server.common.data.query.DynamicValueSourceType;
  58 +import org.thingsboard.server.common.data.query.EntityKey;
  59 +import org.thingsboard.server.common.data.query.EntityKeyType;
  60 +import org.thingsboard.server.common.data.query.EntityKeyValueType;
  61 +import org.thingsboard.server.common.data.query.FilterPredicateValue;
  62 +import org.thingsboard.server.common.data.query.KeyFilter;
  63 +import org.thingsboard.server.common.data.query.NumericFilterPredicate;
46 import org.thingsboard.server.common.data.security.Authority; 64 import org.thingsboard.server.common.data.security.Authority;
47 import org.thingsboard.server.common.data.security.DeviceCredentials; 65 import org.thingsboard.server.common.data.security.DeviceCredentials;
48 import org.thingsboard.server.common.data.security.UserCredentials; 66 import org.thingsboard.server.common.data.security.UserCredentials;
  67 +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
  68 +import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
49 import org.thingsboard.server.common.data.widget.WidgetsBundle; 69 import org.thingsboard.server.common.data.widget.WidgetsBundle;
50 -import org.thingsboard.server.dao.asset.AssetService;  
51 import org.thingsboard.server.dao.attributes.AttributesService; 70 import org.thingsboard.server.dao.attributes.AttributesService;
52 import org.thingsboard.server.dao.customer.CustomerService; 71 import org.thingsboard.server.dao.customer.CustomerService;
53 import org.thingsboard.server.dao.device.DeviceCredentialsService; 72 import org.thingsboard.server.dao.device.DeviceCredentialsService;
54 import org.thingsboard.server.dao.device.DeviceProfileService; 73 import org.thingsboard.server.dao.device.DeviceProfileService;
55 import org.thingsboard.server.dao.device.DeviceService; 74 import org.thingsboard.server.dao.device.DeviceService;
56 import org.thingsboard.server.dao.exception.DataValidationException; 75 import org.thingsboard.server.dao.exception.DataValidationException;
57 -import org.thingsboard.server.dao.relation.RelationService; 76 +import org.thingsboard.server.dao.rule.RuleChainService;
58 import org.thingsboard.server.dao.settings.AdminSettingsService; 77 import org.thingsboard.server.dao.settings.AdminSettingsService;
59 import org.thingsboard.server.dao.tenant.TenantProfileService; 78 import org.thingsboard.server.dao.tenant.TenantProfileService;
60 import org.thingsboard.server.dao.tenant.TenantService; 79 import org.thingsboard.server.dao.tenant.TenantService;
@@ -62,6 +81,8 @@ import org.thingsboard.server.dao.user.UserService; @@ -62,6 +81,8 @@ import org.thingsboard.server.dao.user.UserService;
62 import org.thingsboard.server.dao.widget.WidgetsBundleService; 81 import org.thingsboard.server.dao.widget.WidgetsBundleService;
63 82
64 import java.util.Arrays; 83 import java.util.Arrays;
  84 +import java.util.Collections;
  85 +import java.util.LinkedHashMap;
65 86
66 @Service 87 @Service
67 @Profile("install") 88 @Profile("install")
@@ -97,12 +118,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @@ -97,12 +118,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
97 private CustomerService customerService; 118 private CustomerService customerService;
98 119
99 @Autowired 120 @Autowired
100 - private RelationService relationService;  
101 -  
102 - @Autowired  
103 - private AssetService assetService;  
104 -  
105 - @Autowired  
106 private DeviceService deviceService; 121 private DeviceService deviceService;
107 122
108 @Autowired 123 @Autowired
@@ -114,6 +129,9 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @@ -114,6 +129,9 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
114 @Autowired 129 @Autowired
115 private DeviceCredentialsService deviceCredentialsService; 130 private DeviceCredentialsService deviceCredentialsService;
116 131
  132 + @Autowired
  133 + private RuleChainService ruleChainService;
  134 +
117 @Bean 135 @Bean
118 protected BCryptPasswordEncoder passwordEncoder() { 136 protected BCryptPasswordEncoder passwordEncoder() {
119 return new BCryptPasswordEncoder(); 137 return new BCryptPasswordEncoder();
@@ -245,19 +263,133 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @@ -245,19 +263,133 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
245 createDevice(demoTenant.getId(), null, defaultDeviceProfile.getId(), "Raspberry Pi Demo Device", "RASPBERRY_PI_DEMO_TOKEN", "Demo device that is used in " + 263 createDevice(demoTenant.getId(), null, defaultDeviceProfile.getId(), "Raspberry Pi Demo Device", "RASPBERRY_PI_DEMO_TOKEN", "Demo device that is used in " +
246 "Raspberry Pi GPIO control sample application"); 264 "Raspberry Pi GPIO control sample application");
247 265
248 - Asset thermostatAlarms = new Asset();  
249 - thermostatAlarms.setTenantId(demoTenant.getId());  
250 - thermostatAlarms.setName("Thermostat Alarms");  
251 - thermostatAlarms.setType("AlarmPropagationAsset");  
252 - thermostatAlarms = assetService.saveAsset(thermostatAlarms);  
253 -  
254 - DeviceProfile thermostatDeviceProfile = this.deviceProfileService.findOrCreateDeviceProfile(demoTenant.getId(), "thermostat");  
255 -  
256 - DeviceId t1Id = createDevice(demoTenant.getId(), null, thermostatDeviceProfile.getId(), "Thermostat T1", "T1_TEST_TOKEN", "Demo device for Thermostats dashboard").getId();  
257 - DeviceId t2Id = createDevice(demoTenant.getId(), null, thermostatDeviceProfile.getId(), "Thermostat T2", "T2_TEST_TOKEN", "Demo device for Thermostats dashboard").getId();  
258 -  
259 - relationService.saveRelation(thermostatAlarms.getTenantId(), new EntityRelation(thermostatAlarms.getId(), t1Id, "ToAlarmPropagationAsset"));  
260 - relationService.saveRelation(thermostatAlarms.getTenantId(), new EntityRelation(thermostatAlarms.getId(), t2Id, "ToAlarmPropagationAsset")); 266 + DeviceProfile thermostatDeviceProfile = new DeviceProfile();
  267 + thermostatDeviceProfile.setTenantId(demoTenant.getId());
  268 + thermostatDeviceProfile.setDefault(false);
  269 + thermostatDeviceProfile.setName("thermostat");
  270 + thermostatDeviceProfile.setType(DeviceProfileType.DEFAULT);
  271 + thermostatDeviceProfile.setTransportType(DeviceTransportType.DEFAULT);
  272 + thermostatDeviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED);
  273 + thermostatDeviceProfile.setDescription("Thermostat device profile");
  274 + thermostatDeviceProfile.setDefaultRuleChainId(ruleChainService.findTenantRuleChains(
  275 + demoTenant.getId(), new PageLink(1, 0, "Thermostat Alarms")).getData().get(0).getId());
  276 +
  277 + DeviceProfileData deviceProfileData = new DeviceProfileData();
  278 + DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
  279 + DefaultDeviceProfileTransportConfiguration transportConfiguration = new DefaultDeviceProfileTransportConfiguration();
  280 + DisabledDeviceProfileProvisionConfiguration provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(null);
  281 + deviceProfileData.setConfiguration(configuration);
  282 + deviceProfileData.setTransportConfiguration(transportConfiguration);
  283 + deviceProfileData.setProvisionConfiguration(provisionConfiguration);
  284 + thermostatDeviceProfile.setProfileData(deviceProfileData);
  285 +
  286 + DeviceProfileAlarm highTemperature = new DeviceProfileAlarm();
  287 + highTemperature.setId("highTemperatureAlarmID");
  288 + highTemperature.setAlarmType("High Temperature");
  289 + AlarmRule temperatureRule = new AlarmRule();
  290 + AlarmCondition temperatureCondition = new AlarmCondition();
  291 + temperatureCondition.setSpec(new SimpleAlarmConditionSpec());
  292 +
  293 + KeyFilter alarmTemperatureAttributeFilter = new KeyFilter();
  294 + alarmTemperatureAttributeFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "alarmTemperature"));
  295 + alarmTemperatureAttributeFilter.setValueType(EntityKeyValueType.BOOLEAN);
  296 + BooleanFilterPredicate alarmTemperatureAttributePredicate = new BooleanFilterPredicate();
  297 + alarmTemperatureAttributePredicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL);
  298 + alarmTemperatureAttributePredicate.setValue(new FilterPredicateValue<>(Boolean.TRUE));
  299 + alarmTemperatureAttributeFilter.setPredicate(alarmTemperatureAttributePredicate);
  300 +
  301 + KeyFilter temperatureTimeseriesFilter = new KeyFilter();
  302 + temperatureTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature"));
  303 + temperatureTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC);
  304 + NumericFilterPredicate temperatureTimeseriesFilterPredicate = new NumericFilterPredicate();
  305 + temperatureTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
  306 + FilterPredicateValue<Double> temperatureTimeseriesPredicateValue =
  307 + new FilterPredicateValue<>(25.0, null,
  308 + new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "thresholdTemperature"));
  309 + temperatureTimeseriesFilterPredicate.setValue(temperatureTimeseriesPredicateValue);
  310 + temperatureTimeseriesFilter.setPredicate(temperatureTimeseriesFilterPredicate);
  311 + temperatureCondition.setCondition(Arrays.asList(alarmTemperatureAttributeFilter, temperatureTimeseriesFilter));
  312 + temperatureRule.setAlarmDetails("Current temperature = ${temperature}");
  313 + temperatureRule.setCondition(temperatureCondition);
  314 + highTemperature.setCreateRules(new LinkedHashMap<>(Collections.singletonMap(AlarmSeverity.MAJOR, temperatureRule)));
  315 +
  316 + AlarmRule clearTemperatureRule = new AlarmRule();
  317 + AlarmCondition clearTemperatureCondition = new AlarmCondition();
  318 + clearTemperatureCondition.setSpec(new SimpleAlarmConditionSpec());
  319 +
  320 + KeyFilter clearTemperatureTimeseriesFilter = new KeyFilter();
  321 + clearTemperatureTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "temperature"));
  322 + clearTemperatureTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC);
  323 + NumericFilterPredicate clearTemperatureTimeseriesFilterPredicate = new NumericFilterPredicate();
  324 + clearTemperatureTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.LESS_OR_EQUAL);
  325 + FilterPredicateValue<Double> clearTemperatureTimeseriesPredicateValue =
  326 + new FilterPredicateValue<>(25.0, null,
  327 + new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "thresholdTemperature"));
  328 +
  329 + clearTemperatureTimeseriesFilterPredicate.setValue(clearTemperatureTimeseriesPredicateValue);
  330 + clearTemperatureTimeseriesFilter.setPredicate(clearTemperatureTimeseriesFilterPredicate);
  331 + clearTemperatureCondition.setCondition(Collections.singletonList(clearTemperatureTimeseriesFilter));
  332 + clearTemperatureRule.setCondition(clearTemperatureCondition);
  333 + clearTemperatureRule.setAlarmDetails("Current temperature = ${temperature}");
  334 + highTemperature.setClearRule(clearTemperatureRule);
  335 +
  336 + DeviceProfileAlarm lowHumidity = new DeviceProfileAlarm();
  337 + lowHumidity.setId("lowHumidityAlarmID");
  338 + lowHumidity.setAlarmType("Low Humidity");
  339 + AlarmRule humidityRule = new AlarmRule();
  340 + AlarmCondition humidityCondition = new AlarmCondition();
  341 + humidityCondition.setSpec(new SimpleAlarmConditionSpec());
  342 +
  343 + KeyFilter alarmHumidityAttributeFilter = new KeyFilter();
  344 + alarmHumidityAttributeFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "alarmHumidity"));
  345 + alarmHumidityAttributeFilter.setValueType(EntityKeyValueType.BOOLEAN);
  346 + BooleanFilterPredicate alarmHumidityAttributePredicate = new BooleanFilterPredicate();
  347 + alarmHumidityAttributePredicate.setOperation(BooleanFilterPredicate.BooleanOperation.EQUAL);
  348 + alarmHumidityAttributePredicate.setValue(new FilterPredicateValue<>(Boolean.TRUE));
  349 + alarmHumidityAttributeFilter.setPredicate(alarmHumidityAttributePredicate);
  350 +
  351 + KeyFilter humidityTimeseriesFilter = new KeyFilter();
  352 + humidityTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "humidity"));
  353 + humidityTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC);
  354 + NumericFilterPredicate humidityTimeseriesFilterPredicate = new NumericFilterPredicate();
  355 + humidityTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.LESS);
  356 + FilterPredicateValue<Double> humidityTimeseriesPredicateValue =
  357 + new FilterPredicateValue<>(60.0, null,
  358 + new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "thresholdHumidity"));
  359 + humidityTimeseriesFilterPredicate.setValue(humidityTimeseriesPredicateValue);
  360 + humidityTimeseriesFilter.setPredicate(humidityTimeseriesFilterPredicate);
  361 + humidityCondition.setCondition(Arrays.asList(alarmHumidityAttributeFilter, humidityTimeseriesFilter));
  362 +
  363 + humidityRule.setCondition(humidityCondition);
  364 + humidityRule.setAlarmDetails("Current humidity = ${humidity}");
  365 + lowHumidity.setCreateRules(new LinkedHashMap<>(Collections.singletonMap(AlarmSeverity.MINOR, humidityRule)));
  366 +
  367 + AlarmRule clearHumidityRule = new AlarmRule();
  368 + AlarmCondition clearHumidityCondition = new AlarmCondition();
  369 + clearHumidityCondition.setSpec(new SimpleAlarmConditionSpec());
  370 +
  371 + KeyFilter clearHumidityTimeseriesFilter = new KeyFilter();
  372 + clearHumidityTimeseriesFilter.setKey(new EntityKey(EntityKeyType.TIME_SERIES, "humidity"));
  373 + clearHumidityTimeseriesFilter.setValueType(EntityKeyValueType.NUMERIC);
  374 + NumericFilterPredicate clearHumidityTimeseriesFilterPredicate = new NumericFilterPredicate();
  375 + clearHumidityTimeseriesFilterPredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER_OR_EQUAL);
  376 + FilterPredicateValue<Double> clearHumidityTimeseriesPredicateValue =
  377 + new FilterPredicateValue<>(60.0, null,
  378 + new DynamicValue<>(DynamicValueSourceType.CURRENT_DEVICE, "thresholdHumidity"));
  379 +
  380 + clearHumidityTimeseriesFilterPredicate.setValue(clearHumidityTimeseriesPredicateValue);
  381 + clearHumidityTimeseriesFilter.setPredicate(clearHumidityTimeseriesFilterPredicate);
  382 + clearHumidityCondition.setCondition(Collections.singletonList(clearHumidityTimeseriesFilter));
  383 + clearHumidityRule.setCondition(clearHumidityCondition);
  384 + clearHumidityRule.setAlarmDetails("Current humidity = ${humidity}");
  385 + lowHumidity.setClearRule(clearHumidityRule);
  386 +
  387 + deviceProfileData.setAlarms(Arrays.asList(highTemperature, lowHumidity));
  388 +
  389 + DeviceProfile savedThermostatDeviceProfile = deviceProfileService.saveDeviceProfile(thermostatDeviceProfile);
  390 +
  391 + DeviceId t1Id = createDevice(demoTenant.getId(), null, savedThermostatDeviceProfile.getId(), "Thermostat T1", "T1_TEST_TOKEN", "Demo device for Thermostats dashboard").getId();
  392 + DeviceId t2Id = createDevice(demoTenant.getId(), null, savedThermostatDeviceProfile.getId(), "Thermostat T2", "T2_TEST_TOKEN", "Demo device for Thermostats dashboard").getId();
261 393
262 attributesService.save(demoTenant.getId(), t1Id, DataConstants.SERVER_SCOPE, 394 attributesService.save(demoTenant.getId(), t1Id, DataConstants.SERVER_SCOPE,
263 Arrays.asList(new BaseAttributeKvEntry(System.currentTimeMillis(), new DoubleDataEntry("latitude", 37.3948)), 395 Arrays.asList(new BaseAttributeKvEntry(System.currentTimeMillis(), new DoubleDataEntry("latitude", 37.3948)),
@@ -367,6 +367,8 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService @@ -367,6 +367,8 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
367 " db_storage varchar(32)," + 367 " db_storage varchar(32)," +
368 " re_exec varchar(32)," + 368 " re_exec varchar(32)," +
369 " js_exec varchar(32)," + 369 " js_exec varchar(32)," +
  370 + " email_exec varchar(32)," +
  371 + " sms_exec varchar(32)," +
370 " CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id)\n" + 372 " CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id)\n" +
371 ");"); 373 ");");
372 } catch (Exception e) { 374 } catch (Exception e) {
@@ -20,8 +20,10 @@ import freemarker.template.Configuration; @@ -20,8 +20,10 @@ import freemarker.template.Configuration;
20 import freemarker.template.Template; 20 import freemarker.template.Template;
21 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
22 import org.apache.commons.lang3.StringUtils; 22 import org.apache.commons.lang3.StringUtils;
  23 +import org.jetbrains.annotations.NotNull;
23 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.beans.factory.annotation.Autowired;
24 import org.springframework.context.MessageSource; 25 import org.springframework.context.MessageSource;
  26 +import org.springframework.context.annotation.Lazy;
25 import org.springframework.core.NestedRuntimeException; 27 import org.springframework.core.NestedRuntimeException;
26 import org.springframework.mail.javamail.JavaMailSenderImpl; 28 import org.springframework.mail.javamail.JavaMailSenderImpl;
27 import org.springframework.mail.javamail.MimeMessageHelper; 29 import org.springframework.mail.javamail.MimeMessageHelper;
@@ -29,12 +31,18 @@ import org.springframework.stereotype.Service; @@ -29,12 +31,18 @@ import org.springframework.stereotype.Service;
29 import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; 31 import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
30 import org.thingsboard.rule.engine.api.MailService; 32 import org.thingsboard.rule.engine.api.MailService;
31 import org.thingsboard.server.common.data.AdminSettings; 33 import org.thingsboard.server.common.data.AdminSettings;
  34 +import org.thingsboard.server.common.data.ApiFeature;
  35 +import org.thingsboard.server.common.data.ApiUsageRecordKey;
  36 +import org.thingsboard.server.common.data.ApiUsageStateMailMessage;
  37 +import org.thingsboard.server.common.data.ApiUsageStateValue;
32 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; 38 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
33 import org.thingsboard.server.common.data.exception.ThingsboardException; 39 import org.thingsboard.server.common.data.exception.ThingsboardException;
34 import org.thingsboard.server.common.data.id.EntityId; 40 import org.thingsboard.server.common.data.id.EntityId;
35 import org.thingsboard.server.common.data.id.TenantId; 41 import org.thingsboard.server.common.data.id.TenantId;
36 import org.thingsboard.server.dao.exception.IncorrectParameterException; 42 import org.thingsboard.server.dao.exception.IncorrectParameterException;
37 import org.thingsboard.server.dao.settings.AdminSettingsService; 43 import org.thingsboard.server.dao.settings.AdminSettingsService;
  44 +import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
  45 +import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
38 46
39 import javax.annotation.PostConstruct; 47 import javax.annotation.PostConstruct;
40 import javax.mail.MessagingException; 48 import javax.mail.MessagingException;
@@ -51,18 +59,28 @@ public class DefaultMailService implements MailService { @@ -51,18 +59,28 @@ public class DefaultMailService implements MailService {
51 public static final String MAIL_PROP = "mail."; 59 public static final String MAIL_PROP = "mail.";
52 public static final String TARGET_EMAIL = "targetEmail"; 60 public static final String TARGET_EMAIL = "targetEmail";
53 public static final String UTF_8 = "UTF-8"; 61 public static final String UTF_8 = "UTF-8";
54 - @Autowired  
55 - private MessageSource messages; 62 + public static final int _10K = 10000;
  63 + public static final int _1M = 1000000;
  64 +
  65 + private final MessageSource messages;
  66 + private final Configuration freemarkerConfig;
  67 + private final AdminSettingsService adminSettingsService;
  68 + private final TbApiUsageClient apiUsageClient;
56 69
  70 + @Lazy
57 @Autowired 71 @Autowired
58 - private Configuration freemarkerConfig; 72 + private TbApiUsageStateService apiUsageStateService;
59 73
60 private JavaMailSenderImpl mailSender; 74 private JavaMailSenderImpl mailSender;
61 75
62 private String mailFrom; 76 private String mailFrom;
63 77
64 - @Autowired  
65 - private AdminSettingsService adminSettingsService; 78 + public DefaultMailService(MessageSource messages, Configuration freemarkerConfig, AdminSettingsService adminSettingsService, TbApiUsageClient apiUsageClient) {
  79 + this.messages = messages;
  80 + this.freemarkerConfig = freemarkerConfig;
  81 + this.adminSettingsService = adminSettingsService;
  82 + this.apiUsageClient = apiUsageClient;
  83 + }
66 84
67 @PostConstruct 85 @PostConstruct
68 private void init() { 86 private void init() {
@@ -141,7 +159,7 @@ public class DefaultMailService implements MailService { @@ -141,7 +159,7 @@ public class DefaultMailService implements MailService {
141 } 159 }
142 160
143 @Override 161 @Override
144 - public void sendEmail(String email, String subject, String message) throws ThingsboardException { 162 + public void sendEmail(TenantId tenantId, String email, String subject, String message) throws ThingsboardException {
145 sendMail(mailSender, mailFrom, email, subject, message); 163 sendMail(mailSender, mailFrom, email, subject, message);
146 } 164 }
147 165
@@ -216,20 +234,23 @@ public class DefaultMailService implements MailService { @@ -216,20 +234,23 @@ public class DefaultMailService implements MailService {
216 } 234 }
217 235
218 @Override 236 @Override
219 - public void send(String from, String to, String cc, String bcc, String subject, String body) throws MessagingException {  
220 - MimeMessage mailMsg = mailSender.createMimeMessage();  
221 - MimeMessageHelper helper = new MimeMessageHelper(mailMsg, "UTF-8");  
222 - helper.setFrom(StringUtils.isBlank(from) ? mailFrom : from);  
223 - helper.setTo(to.split("\\s*,\\s*"));  
224 - if (!StringUtils.isBlank(cc)) {  
225 - helper.setCc(cc.split("\\s*,\\s*"));  
226 - }  
227 - if (!StringUtils.isBlank(bcc)) {  
228 - helper.setBcc(bcc.split("\\s*,\\s*")); 237 + public void send(TenantId tenantId, String from, String to, String cc, String bcc, String subject, String body) throws MessagingException {
  238 + if (apiUsageStateService.getApiUsageState(tenantId).isEmailSendEnabled()) {
  239 + MimeMessage mailMsg = mailSender.createMimeMessage();
  240 + MimeMessageHelper helper = new MimeMessageHelper(mailMsg, "UTF-8");
  241 + helper.setFrom(StringUtils.isBlank(from) ? mailFrom : from);
  242 + helper.setTo(to.split("\\s*,\\s*"));
  243 + if (!StringUtils.isBlank(cc)) {
  244 + helper.setCc(cc.split("\\s*,\\s*"));
  245 + }
  246 + if (!StringUtils.isBlank(bcc)) {
  247 + helper.setBcc(bcc.split("\\s*,\\s*"));
  248 + }
  249 + helper.setSubject(subject);
  250 + helper.setText(body);
  251 + mailSender.send(helper.getMimeMessage());
  252 + apiUsageClient.report(tenantId, ApiUsageRecordKey.EMAIL_EXEC_COUNT, 1);
229 } 253 }
230 - helper.setSubject(subject);  
231 - helper.setText(body);  
232 - mailSender.send(helper.getMimeMessage());  
233 } 254 }
234 255
235 @Override 256 @Override
@@ -246,6 +267,122 @@ public class DefaultMailService implements MailService { @@ -246,6 +267,122 @@ public class DefaultMailService implements MailService {
246 sendMail(mailSender, mailFrom, email, subject, message); 267 sendMail(mailSender, mailFrom, email, subject, message);
247 } 268 }
248 269
  270 + @Override
  271 + public void sendApiFeatureStateEmail(ApiFeature apiFeature, ApiUsageStateValue stateValue, String email, ApiUsageStateMailMessage msg) throws ThingsboardException {
  272 + String subject = messages.getMessage("api.usage.state", null, Locale.US);
  273 +
  274 + Map<String, Object> model = new HashMap<>();
  275 + model.put("apiFeature", apiFeature.getLabel());
  276 + model.put(TARGET_EMAIL, email);
  277 +
  278 + String message = null;
  279 +
  280 + switch (stateValue) {
  281 + case ENABLED:
  282 + model.put("apiLabel", toEnabledValueLabel(apiFeature));
  283 + message = mergeTemplateIntoString("state.enabled.ftl", model);
  284 + break;
  285 + case WARNING:
  286 + model.put("apiValueLabel", toDisabledValueLabel(apiFeature) + " " + toWarningValueLabel(msg.getKey(), msg.getValue(), msg.getThreshold()));
  287 + message = mergeTemplateIntoString("state.warning.ftl", model);
  288 + break;
  289 + case DISABLED:
  290 + model.put("apiLimitValueLabel", toDisabledValueLabel(apiFeature) + " " + toDisabledValueLabel(msg.getKey(), msg.getThreshold()));
  291 + message = mergeTemplateIntoString("state.disabled.ftl", model);
  292 + break;
  293 + }
  294 + sendMail(mailSender, mailFrom, email, subject, message);
  295 + }
  296 +
  297 + private String toEnabledValueLabel(ApiFeature apiFeature) {
  298 + switch (apiFeature) {
  299 + case DB:
  300 + return "save";
  301 + case TRANSPORT:
  302 + return "receive";
  303 + case JS:
  304 + return "invoke";
  305 + case RE:
  306 + return "process";
  307 + case EMAIL:
  308 + case SMS:
  309 + return "send";
  310 + default:
  311 + throw new RuntimeException("Not implemented!");
  312 + }
  313 + }
  314 +
  315 + private String toDisabledValueLabel(ApiFeature apiFeature) {
  316 + switch (apiFeature) {
  317 + case DB:
  318 + return "saved";
  319 + case TRANSPORT:
  320 + return "received";
  321 + case JS:
  322 + return "invoked";
  323 + case RE:
  324 + return "processed";
  325 + case EMAIL:
  326 + case SMS:
  327 + return "sent";
  328 + default:
  329 + throw new RuntimeException("Not implemented!");
  330 + }
  331 + }
  332 +
  333 + private String toWarningValueLabel(ApiUsageRecordKey key, long value, long threshold) {
  334 + String valueInM = getValueAsString(value);
  335 + String thresholdInM = getValueAsString(threshold);
  336 + switch (key) {
  337 + case STORAGE_DP_COUNT:
  338 + case TRANSPORT_DP_COUNT:
  339 + return valueInM + " out of " + thresholdInM + " allowed data points";
  340 + case TRANSPORT_MSG_COUNT:
  341 + return valueInM + " out of " + thresholdInM + " allowed messages";
  342 + case JS_EXEC_COUNT:
  343 + return valueInM + " out of " + thresholdInM + " allowed JavaScript functions";
  344 + case RE_EXEC_COUNT:
  345 + return valueInM + " out of " + thresholdInM + " allowed Rule Engine messages";
  346 + case EMAIL_EXEC_COUNT:
  347 + return valueInM + " out of " + thresholdInM + " allowed Email messages";
  348 + case SMS_EXEC_COUNT:
  349 + return valueInM + " out of " + thresholdInM + " allowed SMS messages";
  350 + default:
  351 + throw new RuntimeException("Not implemented!");
  352 + }
  353 + }
  354 +
  355 + private String toDisabledValueLabel(ApiUsageRecordKey key, long value) {
  356 + switch (key) {
  357 + case STORAGE_DP_COUNT:
  358 + case TRANSPORT_DP_COUNT:
  359 + return getValueAsString(value) + " data points";
  360 + case TRANSPORT_MSG_COUNT:
  361 + return getValueAsString(value) + " messages";
  362 + case JS_EXEC_COUNT:
  363 + return "JavaScript functions " + getValueAsString(value) + " times";
  364 + case RE_EXEC_COUNT:
  365 + return getValueAsString(value) + " Rule Engine messages";
  366 + case EMAIL_EXEC_COUNT:
  367 + return getValueAsString(value) + " Email messages";
  368 + case SMS_EXEC_COUNT:
  369 + return getValueAsString(value) + " SMS messages";
  370 + default:
  371 + throw new RuntimeException("Not implemented!");
  372 + }
  373 + }
  374 +
  375 + @NotNull
  376 + private String getValueAsString(long value) {
  377 + if (value > _1M && value % _1M < _10K) {
  378 + return value / _1M + "M";
  379 + } else if (value > _10K) {
  380 + return String.format("%.2fM", ((double) value) / 1000000);
  381 + } else {
  382 + return value + "";
  383 + }
  384 + }
  385 +
249 private void sendMail(JavaMailSenderImpl mailSender, 386 private void sendMail(JavaMailSenderImpl mailSender,
250 String mailFrom, String email, 387 String mailFrom, String email,
251 String subject, String message) throws ThingsboardException { 388 String subject, String message) throws ThingsboardException {
@@ -22,6 +22,7 @@ import org.springframework.scheduling.annotation.Scheduled; @@ -22,6 +22,7 @@ import org.springframework.scheduling.annotation.Scheduled;
22 import org.springframework.stereotype.Service; 22 import org.springframework.stereotype.Service;
23 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 23 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
24 import org.thingsboard.server.common.data.ApiUsageState; 24 import org.thingsboard.server.common.data.ApiUsageState;
  25 +import org.thingsboard.server.common.data.Device;
25 import org.thingsboard.server.common.data.DeviceProfile; 26 import org.thingsboard.server.common.data.DeviceProfile;
26 import org.thingsboard.server.common.data.EntityType; 27 import org.thingsboard.server.common.data.EntityType;
27 import org.thingsboard.server.common.data.HasName; 28 import org.thingsboard.server.common.data.HasName;
@@ -32,7 +33,6 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -32,7 +33,6 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
32 import org.thingsboard.server.common.data.id.EntityId; 33 import org.thingsboard.server.common.data.id.EntityId;
33 import org.thingsboard.server.common.data.id.RuleChainId; 34 import org.thingsboard.server.common.data.id.RuleChainId;
34 import org.thingsboard.server.common.data.id.TenantId; 35 import org.thingsboard.server.common.data.id.TenantId;
35 -import org.thingsboard.server.common.data.id.TenantProfileId;  
36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
37 import org.thingsboard.server.common.msg.TbMsg; 37 import org.thingsboard.server.common.msg.TbMsg;
38 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 38 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
@@ -237,6 +237,16 @@ public class DefaultTbClusterService implements TbClusterService { @@ -237,6 +237,16 @@ public class DefaultTbClusterService implements TbClusterService {
237 onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback); 237 onEntityDelete(TenantId.SYS_TENANT_ID, entity.getId(), entity.getName(), callback);
238 } 238 }
239 239
  240 + @Override
  241 + public void onDeviceChange(Device entity, TbQueueCallback callback) {
  242 + onEntityChange(entity.getTenantId(), entity.getId(), entity, callback);
  243 + }
  244 +
  245 + @Override
  246 + public void onDeviceDeleted(Device entity, TbQueueCallback callback) {
  247 + onEntityDelete(entity.getTenantId(), entity.getId(), entity.getName(), callback);
  248 + }
  249 +
240 public <T> void onEntityChange(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) { 250 public <T> void onEntityChange(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) {
241 String entityName = (entity instanceof HasName) ? ((HasName) entity).getName() : entity.getClass().getName(); 251 String entityName = (entity instanceof HasName) ? ((HasName) entity).getName() : entity.getClass().getName();
242 log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entityName); 252 log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entityName);
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 */ 15 */
16 package org.thingsboard.server.service.queue; 16 package org.thingsboard.server.service.queue;
17 17
  18 +import lombok.Getter;
  19 +import lombok.Setter;
18 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
19 import org.springframework.beans.factory.annotation.Value; 21 import org.springframework.beans.factory.annotation.Value;
20 import org.springframework.boot.context.event.ApplicationReadyEvent; 22 import org.springframework.boot.context.event.ApplicationReadyEvent;
@@ -76,6 +78,7 @@ import java.util.concurrent.ConcurrentMap; @@ -76,6 +78,7 @@ import java.util.concurrent.ConcurrentMap;
76 import java.util.concurrent.CountDownLatch; 78 import java.util.concurrent.CountDownLatch;
77 import java.util.concurrent.ExecutorService; 79 import java.util.concurrent.ExecutorService;
78 import java.util.concurrent.Executors; 80 import java.util.concurrent.Executors;
  81 +import java.util.concurrent.Future;
79 import java.util.concurrent.TimeUnit; 82 import java.util.concurrent.TimeUnit;
80 import java.util.function.Function; 83 import java.util.function.Function;
81 import java.util.stream.Collectors; 84 import java.util.stream.Collectors;
@@ -175,39 +178,48 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -175,39 +178,48 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
175 CountDownLatch processingTimeoutLatch = new CountDownLatch(1); 178 CountDownLatch processingTimeoutLatch = new CountDownLatch(1);
176 TbPackProcessingContext<TbProtoQueueMsg<ToCoreMsg>> ctx = new TbPackProcessingContext<>( 179 TbPackProcessingContext<TbProtoQueueMsg<ToCoreMsg>> ctx = new TbPackProcessingContext<>(
177 processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>()); 180 processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>());
178 - pendingMap.forEach((id, msg) -> {  
179 - log.trace("[{}] Creating main callback for message: {}", id, msg.getValue());  
180 - TbCallback callback = new TbPackCallback<>(id, ctx);  
181 - try {  
182 - ToCoreMsg toCoreMsg = msg.getValue();  
183 - if (toCoreMsg.hasToSubscriptionMgrMsg()) {  
184 - log.trace("[{}] Forwarding message to subscription manager service {}", id, toCoreMsg.getToSubscriptionMgrMsg());  
185 - forwardToSubMgrService(toCoreMsg.getToSubscriptionMgrMsg(), callback);  
186 - } else if (toCoreMsg.hasToDeviceActorMsg()) {  
187 - log.trace("[{}] Forwarding message to device actor {}", id, toCoreMsg.getToDeviceActorMsg());  
188 - forwardToDeviceActor(toCoreMsg.getToDeviceActorMsg(), callback);  
189 - } else if (toCoreMsg.hasDeviceStateServiceMsg()) {  
190 - log.trace("[{}] Forwarding message to state service {}", id, toCoreMsg.getDeviceStateServiceMsg());  
191 - forwardToStateService(toCoreMsg.getDeviceStateServiceMsg(), callback);  
192 - } else if (toCoreMsg.getToDeviceActorNotificationMsg() != null && !toCoreMsg.getToDeviceActorNotificationMsg().isEmpty()) {  
193 - Optional<TbActorMsg> actorMsg = encodingService.decode(toCoreMsg.getToDeviceActorNotificationMsg().toByteArray());  
194 - if (actorMsg.isPresent()) {  
195 - TbActorMsg tbActorMsg = actorMsg.get();  
196 - if (tbActorMsg.getMsgType().equals(MsgType.DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG)) {  
197 - tbCoreDeviceRpcService.forwardRpcRequestToDeviceActor((ToDeviceRpcRequestActorMsg) tbActorMsg);  
198 - } else {  
199 - log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get());  
200 - actorContext.tell(actorMsg.get()); 181 + PendingMsgHolder pendingMsgHolder = new PendingMsgHolder();
  182 + Future<?> packSubmitFuture = consumersExecutor.submit(() -> {
  183 + pendingMap.forEach((id, msg) -> {
  184 + log.trace("[{}] Creating main callback for message: {}", id, msg.getValue());
  185 + TbCallback callback = new TbPackCallback<>(id, ctx);
  186 + try {
  187 + ToCoreMsg toCoreMsg = msg.getValue();
  188 + pendingMsgHolder.setToCoreMsg(toCoreMsg);
  189 + if (toCoreMsg.hasToSubscriptionMgrMsg()) {
  190 + log.trace("[{}] Forwarding message to subscription manager service {}", id, toCoreMsg.getToSubscriptionMgrMsg());
  191 + forwardToSubMgrService(toCoreMsg.getToSubscriptionMgrMsg(), callback);
  192 + } else if (toCoreMsg.hasToDeviceActorMsg()) {
  193 + log.trace("[{}] Forwarding message to device actor {}", id, toCoreMsg.getToDeviceActorMsg());
  194 + forwardToDeviceActor(toCoreMsg.getToDeviceActorMsg(), callback);
  195 + } else if (toCoreMsg.hasDeviceStateServiceMsg()) {
  196 + log.trace("[{}] Forwarding message to state service {}", id, toCoreMsg.getDeviceStateServiceMsg());
  197 + forwardToStateService(toCoreMsg.getDeviceStateServiceMsg(), callback);
  198 + } else if (toCoreMsg.getToDeviceActorNotificationMsg() != null && !toCoreMsg.getToDeviceActorNotificationMsg().isEmpty()) {
  199 + Optional<TbActorMsg> actorMsg = encodingService.decode(toCoreMsg.getToDeviceActorNotificationMsg().toByteArray());
  200 + if (actorMsg.isPresent()) {
  201 + TbActorMsg tbActorMsg = actorMsg.get();
  202 + if (tbActorMsg.getMsgType().equals(MsgType.DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG)) {
  203 + tbCoreDeviceRpcService.forwardRpcRequestToDeviceActor((ToDeviceRpcRequestActorMsg) tbActorMsg);
  204 + } else {
  205 + log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get());
  206 + actorContext.tell(actorMsg.get());
  207 + }
201 } 208 }
  209 + callback.onSuccess();
202 } 210 }
203 - callback.onSuccess(); 211 + } catch (Throwable e) {
  212 + log.warn("[{}] Failed to process message: {}", id, msg, e);
  213 + callback.onFailure(e);
204 } 214 }
205 - } catch (Throwable e) {  
206 - log.warn("[{}] Failed to process message: {}", id, msg, e);  
207 - callback.onFailure(e);  
208 - } 215 + });
209 }); 216 });
210 if (!processingTimeoutLatch.await(packProcessingTimeout, TimeUnit.MILLISECONDS)) { 217 if (!processingTimeoutLatch.await(packProcessingTimeout, TimeUnit.MILLISECONDS)) {
  218 + if (!packSubmitFuture.isDone()) {
  219 + packSubmitFuture.cancel(true);
  220 + ToCoreMsg lastSubmitMsg = pendingMsgHolder.getToCoreMsg();
  221 + log.info("Timeout to process message: {}", lastSubmitMsg);
  222 + }
211 ctx.getAckMap().forEach((id, msg) -> log.debug("[{}] Timeout to process message: {}", id, msg.getValue())); 223 ctx.getAckMap().forEach((id, msg) -> log.debug("[{}] Timeout to process message: {}", id, msg.getValue()));
212 ctx.getFailedMap().forEach((id, msg) -> log.warn("[{}] Failed to process message: {}", id, msg.getValue())); 224 ctx.getFailedMap().forEach((id, msg) -> log.warn("[{}] Failed to process message: {}", id, msg.getValue()));
213 } 225 }
@@ -227,6 +239,12 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -227,6 +239,12 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
227 }); 239 });
228 } 240 }
229 241
  242 + private static class PendingMsgHolder {
  243 + @Getter
  244 + @Setter
  245 + private volatile ToCoreMsg toCoreMsg;
  246 + }
  247 +
230 @Override 248 @Override
231 protected ServiceType getServiceType() { 249 protected ServiceType getServiceType() {
232 return ServiceType.TB_CORE; 250 return ServiceType.TB_CORE;
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.queue; @@ -17,6 +17,7 @@ package org.thingsboard.server.service.queue;
17 17
18 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg; 18 import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
19 import org.thingsboard.server.common.data.ApiUsageState; 19 import org.thingsboard.server.common.data.ApiUsageState;
  20 +import org.thingsboard.server.common.data.Device;
20 import org.thingsboard.server.common.data.DeviceProfile; 21 import org.thingsboard.server.common.data.DeviceProfile;
21 import org.thingsboard.server.common.data.Tenant; 22 import org.thingsboard.server.common.data.Tenant;
22 import org.thingsboard.server.common.data.TenantProfile; 23 import org.thingsboard.server.common.data.TenantProfile;
@@ -66,4 +67,8 @@ public interface TbClusterService { @@ -66,4 +67,8 @@ public interface TbClusterService {
66 void onTenantDelete(Tenant tenant, TbQueueCallback callback); 67 void onTenantDelete(Tenant tenant, TbQueueCallback callback);
67 68
68 void onApiStateChange(ApiUsageState apiUsageState, TbQueueCallback callback); 69 void onApiStateChange(ApiUsageState apiUsageState, TbQueueCallback callback);
  70 +
  71 + void onDeviceChange(Device device, TbQueueCallback callback);
  72 +
  73 + void onDeviceDeleted(Device device, TbQueueCallback callback);
69 } 74 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.sms;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.rule.engine.api.sms.SmsSender;
  20 +import org.thingsboard.rule.engine.api.sms.exception.SmsParseException;
  21 +
  22 +import java.util.regex.Pattern;
  23 +
  24 +@Slf4j
  25 +public abstract class AbstractSmsSender implements SmsSender {
  26 +
  27 + private static final Pattern E_164_PHONE_NUMBER_PATTERN = Pattern.compile("^\\+[1-9]\\d{1,14}$");
  28 +
  29 + private static final int MAX_SMS_MESSAGE_LENGTH = 1600;
  30 + private static final int MAX_SMS_SEGMENT_LENGTH = 70;
  31 +
  32 + protected String validatePhoneNumber(String phoneNumber) throws SmsParseException {
  33 + phoneNumber = phoneNumber.trim();
  34 + if (!E_164_PHONE_NUMBER_PATTERN.matcher(phoneNumber).matches()) {
  35 + throw new SmsParseException("Invalid phone number format. Phone number must be in E.164 format.");
  36 + }
  37 + return phoneNumber;
  38 + }
  39 +
  40 + protected String prepareMessage(String message) {
  41 + message = message.replaceAll("^\"|\"$", "").replaceAll("\\\\n", "\n");
  42 + if (message.length() > MAX_SMS_MESSAGE_LENGTH) {
  43 + log.warn("SMS message exceeds maximum symbols length and will be truncated");
  44 + message = message.substring(0, MAX_SMS_MESSAGE_LENGTH);
  45 + }
  46 + return message;
  47 + }
  48 +
  49 + protected int countMessageSegments(String message) {
  50 + return (int)Math.ceil((double) message.length() / (double) MAX_SMS_SEGMENT_LENGTH);
  51 + }
  52 +
  53 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.sms;
  17 +
  18 +import org.springframework.stereotype.Component;
  19 +import org.thingsboard.rule.engine.api.sms.SmsSender;
  20 +import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
  21 +import org.thingsboard.rule.engine.api.sms.config.AwsSnsSmsProviderConfiguration;
  22 +import org.thingsboard.rule.engine.api.sms.config.SmsProviderConfiguration;
  23 +import org.thingsboard.rule.engine.api.sms.config.TwilioSmsProviderConfiguration;
  24 +import org.thingsboard.server.service.sms.aws.AwsSmsSender;
  25 +import org.thingsboard.server.service.sms.twilio.TwilioSmsSender;
  26 +
  27 +@Component
  28 +public class DefaultSmsSenderFactory implements SmsSenderFactory {
  29 +
  30 + @Override
  31 + public SmsSender createSmsSender(SmsProviderConfiguration config) {
  32 + switch (config.getType()) {
  33 + case AWS_SNS:
  34 + return new AwsSmsSender((AwsSnsSmsProviderConfiguration)config);
  35 + case TWILIO:
  36 + return new TwilioSmsSender((TwilioSmsProviderConfiguration)config);
  37 + default:
  38 + throw new RuntimeException("Unknown SMS provider type " + config.getType());
  39 + }
  40 + }
  41 +
  42 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.sms;
  17 +
  18 +import com.fasterxml.jackson.databind.JsonNode;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.core.NestedRuntimeException;
  21 +import org.springframework.stereotype.Service;
  22 +import org.thingsboard.rule.engine.api.SmsService;
  23 +import org.thingsboard.rule.engine.api.sms.SmsSender;
  24 +import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
  25 +import org.thingsboard.rule.engine.api.sms.config.SmsProviderConfiguration;
  26 +import org.thingsboard.rule.engine.api.sms.config.TestSmsRequest;
  27 +import org.thingsboard.server.common.data.AdminSettings;
  28 +import org.thingsboard.server.common.data.ApiUsageRecordKey;
  29 +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
  30 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  31 +import org.thingsboard.server.common.data.id.EntityId;
  32 +import org.thingsboard.server.common.data.id.TenantId;
  33 +import org.thingsboard.server.dao.settings.AdminSettingsService;
  34 +import org.thingsboard.server.dao.util.mapping.JacksonUtil;
  35 +import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
  36 +import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
  37 +
  38 +import javax.annotation.PostConstruct;
  39 +import javax.annotation.PreDestroy;
  40 +
  41 +@Service
  42 +@Slf4j
  43 +public class DefaultSmsService implements SmsService {
  44 +
  45 + private final SmsSenderFactory smsSenderFactory;
  46 + private final AdminSettingsService adminSettingsService;
  47 + private final TbApiUsageStateService apiUsageStateService;
  48 + private final TbApiUsageClient apiUsageClient;
  49 +
  50 + private SmsSender smsSender;
  51 +
  52 + public DefaultSmsService(SmsSenderFactory smsSenderFactory, AdminSettingsService adminSettingsService, TbApiUsageStateService apiUsageStateService, TbApiUsageClient apiUsageClient) {
  53 + this.smsSenderFactory = smsSenderFactory;
  54 + this.adminSettingsService = adminSettingsService;
  55 + this.apiUsageStateService = apiUsageStateService;
  56 + this.apiUsageClient = apiUsageClient;
  57 + }
  58 +
  59 + @PostConstruct
  60 + private void init() {
  61 + updateSmsConfiguration();
  62 + }
  63 +
  64 + @PreDestroy
  65 + private void destroy() {
  66 + if (this.smsSender != null) {
  67 + this.smsSender.destroy();
  68 + }
  69 + }
  70 +
  71 + @Override
  72 + public void updateSmsConfiguration() {
  73 + AdminSettings settings = adminSettingsService.findAdminSettingsByKey(new TenantId(EntityId.NULL_UUID), "sms");
  74 + if (settings != null) {
  75 + try {
  76 + JsonNode jsonConfig = settings.getJsonValue();
  77 + SmsProviderConfiguration configuration = JacksonUtil.convertValue(jsonConfig, SmsProviderConfiguration.class);
  78 + SmsSender newSmsSender = this.smsSenderFactory.createSmsSender(configuration);
  79 + if (this.smsSender != null) {
  80 + this.smsSender.destroy();
  81 + }
  82 + this.smsSender = newSmsSender;
  83 + } catch (Exception e) {
  84 + log.error("Failed to create SMS sender", e);
  85 + }
  86 + }
  87 + }
  88 +
  89 + private int sendSms(String numberTo, String message) throws ThingsboardException {
  90 + if (this.smsSender == null) {
  91 + throw new ThingsboardException("Unable to send SMS: no SMS provider configured!", ThingsboardErrorCode.GENERAL);
  92 + }
  93 + return this.sendSms(this.smsSender, numberTo, message);
  94 + }
  95 +
  96 + @Override
  97 + public void sendSms(TenantId tenantId, String[] numbersTo, String message) throws ThingsboardException {
  98 + if (apiUsageStateService.getApiUsageState(tenantId).isSmsSendEnabled()) {
  99 + int smsCount = 0;
  100 + try {
  101 + for (String numberTo : numbersTo) {
  102 + smsCount += this.sendSms(numberTo, message);
  103 + }
  104 + } finally {
  105 + if (smsCount > 0) {
  106 + apiUsageClient.report(tenantId, ApiUsageRecordKey.SMS_EXEC_COUNT, smsCount);
  107 + }
  108 + }
  109 + }
  110 + }
  111 +
  112 + @Override
  113 + public void sendTestSms(TestSmsRequest testSmsRequest) throws ThingsboardException {
  114 + SmsSender testSmsSender;
  115 + try {
  116 + testSmsSender = this.smsSenderFactory.createSmsSender(testSmsRequest.getProviderConfiguration());
  117 + } catch (Exception e) {
  118 + throw handleException(e);
  119 + }
  120 + this.sendSms(testSmsSender, testSmsRequest.getNumberTo(), testSmsRequest.getMessage());
  121 + testSmsSender.destroy();
  122 + }
  123 +
  124 + private int sendSms(SmsSender smsSender, String numberTo, String message) throws ThingsboardException {
  125 + try {
  126 + return smsSender.sendSms(numberTo, message);
  127 + } catch (Exception e) {
  128 + throw handleException(e);
  129 + }
  130 + }
  131 +
  132 + private ThingsboardException handleException(Exception exception) {
  133 + String message;
  134 + if (exception instanceof NestedRuntimeException) {
  135 + message = ((NestedRuntimeException) exception).getMostSpecificCause().getMessage();
  136 + } else {
  137 + message = exception.getMessage();
  138 + }
  139 + log.warn("Unable to send SMS: {}", message);
  140 + return new ThingsboardException(String.format("Unable to send SMS: %s", message),
  141 + ThingsboardErrorCode.GENERAL);
  142 + }
  143 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.sms;
  17 +
  18 +import org.springframework.beans.factory.annotation.Value;
  19 +import org.springframework.stereotype.Component;
  20 +import org.thingsboard.common.util.AbstractListeningExecutor;
  21 +
  22 +@Component
  23 +public class SmsExecutorService extends AbstractListeningExecutor {
  24 +
  25 + @Value("${actors.rule.sms_thread_pool_size}")
  26 + private int smsExecutorThreadPoolSize;
  27 +
  28 + @Override
  29 + protected int getThreadPollSize() {
  30 + return smsExecutorThreadPoolSize;
  31 + }
  32 +
  33 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.sms.aws;
  17 +
  18 +import com.amazonaws.auth.AWSCredentials;
  19 +import com.amazonaws.auth.AWSStaticCredentialsProvider;
  20 +import com.amazonaws.auth.BasicAWSCredentials;
  21 +import com.amazonaws.services.sns.AmazonSNS;
  22 +import com.amazonaws.services.sns.AmazonSNSClient;
  23 +import com.amazonaws.services.sns.model.PublishRequest;
  24 +import lombok.extern.slf4j.Slf4j;
  25 +import org.apache.commons.lang3.StringUtils;
  26 +import org.thingsboard.rule.engine.api.sms.config.AwsSnsSmsProviderConfiguration;
  27 +import org.thingsboard.rule.engine.api.sms.exception.SmsException;
  28 +import org.thingsboard.rule.engine.api.sms.exception.SmsSendException;
  29 +import org.thingsboard.server.service.sms.AbstractSmsSender;
  30 +
  31 +@Slf4j
  32 +public class AwsSmsSender extends AbstractSmsSender {
  33 +
  34 + private AmazonSNS snsClient;
  35 +
  36 + public AwsSmsSender(AwsSnsSmsProviderConfiguration config) {
  37 + if (StringUtils.isEmpty(config.getAccessKeyId()) || StringUtils.isEmpty(config.getSecretAccessKey()) || StringUtils.isEmpty(config.getRegion())) {
  38 + throw new IllegalArgumentException("Invalid AWS sms provider configuration: aws accessKeyId, aws secretAccessKey and aws region should be specified!");
  39 + }
  40 + AWSCredentials awsCredentials = new BasicAWSCredentials(config.getAccessKeyId(), config.getSecretAccessKey());
  41 + AWSStaticCredentialsProvider credProvider = new AWSStaticCredentialsProvider(awsCredentials);
  42 + this.snsClient = AmazonSNSClient.builder()
  43 + .withCredentials(credProvider)
  44 + .withRegion(config.getRegion())
  45 + .build();
  46 + }
  47 +
  48 + @Override
  49 + public int sendSms(String numberTo, String message) throws SmsException {
  50 + numberTo = this.validatePhoneNumber(numberTo);
  51 + message = this.prepareMessage(message);
  52 + try {
  53 + PublishRequest publishRequest = new PublishRequest()
  54 + .withPhoneNumber(numberTo)
  55 + .withMessage(message);
  56 + this.snsClient.publish(publishRequest);
  57 + return this.countMessageSegments(message);
  58 + } catch (Exception e) {
  59 + throw new SmsSendException("Failed to send SMS message - " + e.getMessage(), e);
  60 + }
  61 + }
  62 +
  63 + @Override
  64 + public void destroy() {
  65 + if (this.snsClient != null) {
  66 + try {
  67 + this.snsClient.shutdown();
  68 + } catch (Exception e) {
  69 + log.error("Failed to shutdown SNS client during destroy()", e);
  70 + }
  71 + }
  72 + }
  73 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.sms.twilio;
  17 +
  18 +import com.twilio.http.TwilioRestClient;
  19 +import com.twilio.rest.api.v2010.account.Message;
  20 +import com.twilio.type.PhoneNumber;
  21 +import org.apache.commons.lang3.StringUtils;
  22 +import org.thingsboard.rule.engine.api.sms.config.TwilioSmsProviderConfiguration;
  23 +import org.thingsboard.rule.engine.api.sms.exception.SmsException;
  24 +import org.thingsboard.rule.engine.api.sms.exception.SmsSendException;
  25 +import org.thingsboard.server.service.sms.AbstractSmsSender;
  26 +
  27 +public class TwilioSmsSender extends AbstractSmsSender {
  28 +
  29 + private TwilioRestClient twilioRestClient;
  30 + private String numberFrom;
  31 +
  32 + public TwilioSmsSender(TwilioSmsProviderConfiguration config) {
  33 + if (StringUtils.isEmpty(config.getAccountSid()) || StringUtils.isEmpty(config.getAccountToken()) || StringUtils.isEmpty(config.getNumberFrom())) {
  34 + throw new IllegalArgumentException("Invalid twilio sms provider configuration: accountSid, accountToken and numberFrom should be specified!");
  35 + }
  36 + this.numberFrom = this.validatePhoneNumber(config.getNumberFrom());
  37 + this.twilioRestClient = new TwilioRestClient.Builder(config.getAccountSid(), config.getAccountToken()).build();
  38 + }
  39 +
  40 + @Override
  41 + public int sendSms(String numberTo, String message) throws SmsException {
  42 + numberTo = this.validatePhoneNumber(numberTo);
  43 + message = this.prepareMessage(message);
  44 + try {
  45 + String numSegments = Message.creator(new PhoneNumber(numberTo), new PhoneNumber(this.numberFrom), message).create(this.twilioRestClient).getNumSegments();
  46 + return Integer.valueOf(numSegments);
  47 + } catch (Exception e) {
  48 + throw new SmsSendException("Failed to send SMS message - " + e.getMessage(), e);
  49 + }
  50 + }
  51 +
  52 + @Override
  53 + public void destroy() {
  54 +
  55 + }
  56 +}
@@ -21,12 +21,6 @@ import org.springframework.context.annotation.Lazy; @@ -21,12 +21,6 @@ import org.springframework.context.annotation.Lazy;
21 import org.springframework.context.event.EventListener; 21 import org.springframework.context.event.EventListener;
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.server.common.data.EntityType;  
25 -import org.thingsboard.server.common.data.EntityView;  
26 -import org.thingsboard.server.common.data.id.EntityId;  
27 -import org.thingsboard.server.common.data.id.EntityViewId;  
28 -import org.thingsboard.server.common.data.id.TenantId;  
29 -import org.thingsboard.server.dao.entityview.EntityViewService;  
30 import org.thingsboard.server.gen.transport.TransportProtos; 24 import org.thingsboard.server.gen.transport.TransportProtos;
31 import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent; 25 import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent;
32 import org.thingsboard.server.queue.discovery.PartitionChangeEvent; 26 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
@@ -36,7 +30,6 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; @@ -36,7 +30,6 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
36 import org.thingsboard.server.common.msg.queue.TbCallback; 30 import org.thingsboard.server.common.msg.queue.TbCallback;
37 import org.thingsboard.server.queue.util.TbCoreComponent; 31 import org.thingsboard.server.queue.util.TbCoreComponent;
38 import org.thingsboard.server.service.queue.TbClusterService; 32 import org.thingsboard.server.service.queue.TbClusterService;
39 -import org.thingsboard.server.service.telemetry.DefaultTelemetryWebSocketService;  
40 import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; 33 import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate;
41 import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate; 34 import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate;
42 35
@@ -49,7 +42,6 @@ import java.util.Set; @@ -49,7 +42,6 @@ import java.util.Set;
49 import java.util.concurrent.ConcurrentHashMap; 42 import java.util.concurrent.ConcurrentHashMap;
50 import java.util.concurrent.ExecutorService; 43 import java.util.concurrent.ExecutorService;
51 import java.util.concurrent.Executors; 44 import java.util.concurrent.Executors;
52 -import java.util.stream.Collectors;  
53 45
54 @Slf4j 46 @Slf4j
55 @TbCoreComponent 47 @TbCoreComponent
@@ -60,9 +52,6 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer @@ -60,9 +52,6 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer
60 private final Map<String, Map<Integer, TbSubscription>> subscriptionsBySessionId = new ConcurrentHashMap<>(); 52 private final Map<String, Map<Integer, TbSubscription>> subscriptionsBySessionId = new ConcurrentHashMap<>();
61 53
62 @Autowired 54 @Autowired
63 - private EntityViewService entityViewService;  
64 -  
65 - @Autowired  
66 private PartitionService partitionService; 55 private PartitionService partitionService;
67 56
68 @Autowired 57 @Autowired
@@ -72,17 +61,17 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer @@ -72,17 +61,17 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer
72 @Lazy 61 @Lazy
73 private SubscriptionManagerService subscriptionManagerService; 62 private SubscriptionManagerService subscriptionManagerService;
74 63
75 - private ExecutorService wsCallBackExecutor; 64 + private ExecutorService subscriptionUpdateExecutor;
76 65
77 @PostConstruct 66 @PostConstruct
78 public void initExecutor() { 67 public void initExecutor() {
79 - wsCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("ws-sub-callback")); 68 + subscriptionUpdateExecutor = Executors.newWorkStealingPool(20);
80 } 69 }
81 70
82 @PreDestroy 71 @PreDestroy
83 public void shutdownExecutor() { 72 public void shutdownExecutor() {
84 - if (wsCallBackExecutor != null) {  
85 - wsCallBackExecutor.shutdownNow(); 73 + if (subscriptionUpdateExecutor != null) {
  74 + subscriptionUpdateExecutor.shutdownNow();
86 } 75 }
87 } 76 }
88 77
@@ -148,7 +137,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer @@ -148,7 +137,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer
148 update.getLatestValues().forEach((key, value) -> attrSub.getKeyStates().put(key, value)); 137 update.getLatestValues().forEach((key, value) -> attrSub.getKeyStates().put(key, value));
149 break; 138 break;
150 } 139 }
151 - subscription.getUpdateConsumer().accept(sessionId, update); 140 + subscriptionUpdateExecutor.submit(() -> subscription.getUpdateConsumer().accept(sessionId, update));
152 } 141 }
153 callback.onSuccess(); 142 callback.onSuccess();
154 } 143 }
@@ -158,7 +147,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer @@ -158,7 +147,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer
158 TbSubscription subscription = subscriptionsBySessionId 147 TbSubscription subscription = subscriptionsBySessionId
159 .getOrDefault(sessionId, Collections.emptyMap()).get(update.getSubscriptionId()); 148 .getOrDefault(sessionId, Collections.emptyMap()).get(update.getSubscriptionId());
160 if (subscription != null && subscription.getType() == TbSubscriptionType.ALARMS) { 149 if (subscription != null && subscription.getType() == TbSubscriptionType.ALARMS) {
161 - subscription.getUpdateConsumer().accept(sessionId, update); 150 + subscriptionUpdateExecutor.submit(() -> subscription.getUpdateConsumer().accept(sessionId, update));
162 } 151 }
163 callback.onSuccess(); 152 callback.onSuccess();
164 } 153 }
@@ -54,12 +54,16 @@ import org.thingsboard.server.dao.device.provision.ProvisionResponse; @@ -54,12 +54,16 @@ import org.thingsboard.server.dao.device.provision.ProvisionResponse;
54 import org.thingsboard.server.dao.relation.RelationService; 54 import org.thingsboard.server.dao.relation.RelationService;
55 import org.thingsboard.server.dao.util.mapping.JacksonUtil; 55 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
56 import org.thingsboard.server.gen.transport.TransportProtos; 56 import org.thingsboard.server.gen.transport.TransportProtos;
  57 +import org.thingsboard.server.gen.transport.TransportProtos.DeviceCredentialsProto;
57 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; 58 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
58 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 59 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
59 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; 60 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg;
60 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; 61 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
61 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; 62 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
62 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; 63 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
  64 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
  65 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsgOrBuilder;
  66 +import org.thingsboard.server.gen.transport.TransportProtos.ProvisionResponseStatus;
63 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; 67 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
64 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; 68 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
65 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; 69 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
@@ -174,6 +178,8 @@ public class DefaultTransportApiService implements TransportApiService { @@ -174,6 +178,8 @@ public class DefaultTransportApiService implements TransportApiService {
174 if (!checkMqttCredentials(mqtt, credentials)) { 178 if (!checkMqttCredentials(mqtt, credentials)) {
175 credentials = null; 179 credentials = null;
176 } 180 }
  181 + } else {
  182 + return getEmptyTransportApiResponseFuture();
177 } 183 }
178 } 184 }
179 if (credentials == null) { 185 if (credentials == null) {
@@ -292,30 +298,32 @@ public class DefaultTransportApiService implements TransportApiService { @@ -292,30 +298,32 @@ public class DefaultTransportApiService implements TransportApiService {
292 requestMsg.getProvisionDeviceCredentialsMsg().getProvisionDeviceSecret())))); 298 requestMsg.getProvisionDeviceCredentialsMsg().getProvisionDeviceSecret()))));
293 } catch (ProvisionFailedException e) { 299 } catch (ProvisionFailedException e) {
294 return Futures.immediateFuture(getTransportApiResponseMsg( 300 return Futures.immediateFuture(getTransportApiResponseMsg(
295 - TransportProtos.DeviceCredentialsProto.getDefaultInstance(), 301 + new DeviceCredentials(),
296 TransportProtos.ProvisionResponseStatus.valueOf(e.getMessage()))); 302 TransportProtos.ProvisionResponseStatus.valueOf(e.getMessage())));
297 } 303 }
298 - return Futures.transform(provisionResponseFuture, provisionResponse -> getTransportApiResponseMsg(  
299 - getDeviceCredentials(provisionResponse.getDeviceCredentials()), TransportProtos.ProvisionResponseStatus.SUCCESS), 304 + return Futures.transform(provisionResponseFuture, provisionResponse -> getTransportApiResponseMsg(provisionResponse.getDeviceCredentials(), TransportProtos.ProvisionResponseStatus.SUCCESS),
300 dbCallbackExecutorService); 305 dbCallbackExecutorService);
301 } 306 }
302 307
303 - private TransportApiResponseMsg getTransportApiResponseMsg(TransportProtos.DeviceCredentialsProto deviceCredentials, TransportProtos.ProvisionResponseStatus status) {  
304 - return TransportApiResponseMsg.newBuilder()  
305 - .setProvisionDeviceResponseMsg(TransportProtos.ProvisionDeviceResponseMsg.newBuilder()  
306 - .setDeviceCredentials(deviceCredentials)  
307 - .setProvisionResponseStatus(status)  
308 - .build())  
309 - .build();  
310 - } 308 + private TransportApiResponseMsg getTransportApiResponseMsg(DeviceCredentials deviceCredentials, TransportProtos.ProvisionResponseStatus status) {
  309 + if (!status.equals(ProvisionResponseStatus.SUCCESS)) {
  310 + return TransportApiResponseMsg.newBuilder().setProvisionDeviceResponseMsg(TransportProtos.ProvisionDeviceResponseMsg.newBuilder().setStatus(status).build()).build();
  311 + }
  312 + TransportProtos.ProvisionDeviceResponseMsg.Builder provisionResponse = TransportProtos.ProvisionDeviceResponseMsg.newBuilder()
  313 + .setCredentialsType(TransportProtos.CredentialsType.valueOf(deviceCredentials.getCredentialsType().name()))
  314 + .setStatus(status);
  315 + switch (deviceCredentials.getCredentialsType()){
  316 + case ACCESS_TOKEN:
  317 + provisionResponse.setCredentialsValue(deviceCredentials.getCredentialsId());
  318 + break;
  319 + case MQTT_BASIC:
  320 + case X509_CERTIFICATE:
  321 + provisionResponse.setCredentialsValue(deviceCredentials.getCredentialsValue());
  322 + break;
  323 + }
311 324
312 - private TransportProtos.DeviceCredentialsProto getDeviceCredentials(DeviceCredentials deviceCredentials) {  
313 - return TransportProtos.DeviceCredentialsProto.newBuilder()  
314 - .setDeviceIdMSB(deviceCredentials.getDeviceId().getId().getMostSignificantBits())  
315 - .setDeviceIdLSB(deviceCredentials.getDeviceId().getId().getLeastSignificantBits())  
316 - .setCredentialsType(TransportProtos.CredentialsType.valueOf(deviceCredentials.getCredentialsType().name()))  
317 - .setCredentialsId(deviceCredentials.getCredentialsId())  
318 - .setCredentialsValue(deviceCredentials.getCredentialsValue() != null ? deviceCredentials.getCredentialsValue() : "") 325 + return TransportApiResponseMsg.newBuilder()
  326 + .setProvisionDeviceResponseMsg(provisionResponse.build())
319 .build(); 327 .build();
320 } 328 }
321 329
@@ -3,4 +3,5 @@ activation.subject=Your account activation on Thingsboard @@ -3,4 +3,5 @@ activation.subject=Your account activation on Thingsboard
3 account.activated.subject=Thingsboard - your account has been activated 3 account.activated.subject=Thingsboard - your account has been activated
4 reset.password.subject=Thingsboard - Password reset has been requested 4 reset.password.subject=Thingsboard - Password reset has been requested
5 password.was.reset.subject=Thingsboard - your account password has been reset 5 password.was.reset.subject=Thingsboard - your account password has been reset
6 -account.lockout.subject=Thingsboard - User account has been lockout  
  6 +account.lockout.subject=Thingsboard - User account has been lockout
  7 +api.usage.state=Thingsboard - Api Usage State for tenant has been updated
  1 +<#--
  2 +
  3 + Copyright © 2016-2020 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 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  19 + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  20 +<html xmlns="http://www.w3.org/1999/xhtml"
  21 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  22 +<head>
  23 + <meta name="viewport" content="width=device-width"/>
  24 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  25 + <title>Thingsboard - Api Usage State</title>
  26 +
  27 +
  28 + <style type="text/css">
  29 + img {
  30 + max-width: 100%;
  31 + }
  32 +
  33 + body {
  34 + -webkit-font-smoothing: antialiased;
  35 + -webkit-text-size-adjust: none;
  36 + width: 100% !important;
  37 + height: 100%;
  38 + line-height: 1.6em;
  39 + }
  40 +
  41 + body {
  42 + background-color: #f6f6f6;
  43 + }
  44 +
  45 + @media only screen and (max-width: 640px) {
  46 + body {
  47 + padding: 0 !important;
  48 + }
  49 +
  50 + h1 {
  51 + font-weight: 800 !important;
  52 + margin: 20px 0 5px !important;
  53 + }
  54 +
  55 + h2 {
  56 + font-weight: 800 !important;
  57 + margin: 20px 0 5px !important;
  58 + }
  59 +
  60 + h3 {
  61 + font-weight: 800 !important;
  62 + margin: 20px 0 5px !important;
  63 + }
  64 +
  65 + h4 {
  66 + font-weight: 800 !important;
  67 + margin: 20px 0 5px !important;
  68 + }
  69 +
  70 + h1 {
  71 + font-size: 22px !important;
  72 + }
  73 +
  74 + h2 {
  75 + font-size: 18px !important;
  76 + }
  77 +
  78 + h3 {
  79 + font-size: 16px !important;
  80 + }
  81 +
  82 + .container {
  83 + padding: 0 !important;
  84 + width: 100% !important;
  85 + }
  86 +
  87 + .content {
  88 + padding: 0 !important;
  89 + }
  90 +
  91 + .content-wrap {
  92 + padding: 10px !important;
  93 + }
  94 +
  95 + .invoice {
  96 + width: 100% !important;
  97 + }
  98 + }
  99 + </style>
  100 +</head>
  101 +
  102 +<body itemscope itemtype="http://schema.org/EmailMessage"
  103 + style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;"
  104 + bgcolor="#f6f6f6">
  105 +
  106 +<table class="main"
  107 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; border-radius: 3px; width: 100%; background-color: #f6f6f6; margin: 0px auto;"
  108 + cellspacing="0" cellpadding="0" bgcolor="#f6f6f6">
  109 + <tbody>
  110 + <tr style="box-sizing: border-box; margin: 0px;">
  111 + <td class="content-wrap" style="box-sizing: border-box; vertical-align: top; margin: 0px; padding: 20px;"
  112 + align="center" valign="top">
  113 + <table style="box-sizing: border-box; border: 1px solid #e9e9e9; border-radius: 3px; margin: 0px; height: 223px; padding: 20px; background-color: #ffffff; width: 600px; max-width: 600px !important;"
  114 + width="600" cellspacing="0" cellpadding="0">
  115 + <tbody>
  116 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  117 + <td class="content-block"
  118 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 84px;"
  119 + valign="top">
  120 + <h2>Your ThingsBoard account feature was disabled</h2>
  121 + </td>
  122 + </tr>
  123 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  124 + <td class="content-block"
  125 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
  126 + valign="top">We have disabled the ${apiFeature} for your account because ThingsBoard has already ${apiLimitValueLabel}.
  127 + </td>
  128 + </tr>
  129 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  130 + <td class="content-block"
  131 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 59px;"
  132 + valign="top">Please contact your system administrator to resolve the issue.
  133 + </td>
  134 + </tr>
  135 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  136 + <td class="content-block"
  137 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
  138 + valign="top">&mdash; The ThingsBoard
  139 + </td>
  140 + </tr>
  141 + </tbody>
  142 + </table>
  143 + </td>
  144 + </tr>
  145 + </tbody>
  146 +</table>
  147 +<table style="color: #999999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; margin: 0px auto; height: 64px; background-color: #f6f6f6; width: 100%;"
  148 + cellpadding="0px 0px 20px">
  149 + <tbody>
  150 + <tr style="box-sizing: border-box; margin: 0px;">
  151 + <td class="aligncenter content-block"
  152 + style="box-sizing: border-box; font-size: 12px; margin: 0px; padding: 0px 0px 20px; width: 600px; text-align: center; vertical-align: middle;"
  153 + align="center" valign="top">This email was sent to&nbsp;<a
  154 + style="box-sizing: border-box; color: #999999; margin: 0px;"
  155 + href="mailto:${targetEmail}">${targetEmail}</a>&nbsp;by ThingsBoard.
  156 + </td>
  157 + </tr>
  158 + </tbody>
  159 +</table>
  160 +</body>
  161 +</html>
  1 +<#--
  2 +
  3 + Copyright © 2016-2020 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 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  19 + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  20 +<html xmlns="http://www.w3.org/1999/xhtml"
  21 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  22 +<head>
  23 + <meta name="viewport" content="width=device-width"/>
  24 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  25 + <title>Thingsboard - Api Usage State</title>
  26 +
  27 +
  28 + <style type="text/css">
  29 + img {
  30 + max-width: 100%;
  31 + }
  32 +
  33 + body {
  34 + -webkit-font-smoothing: antialiased;
  35 + -webkit-text-size-adjust: none;
  36 + width: 100% !important;
  37 + height: 100%;
  38 + line-height: 1.6em;
  39 + }
  40 +
  41 + body {
  42 + background-color: #f6f6f6;
  43 + }
  44 +
  45 + @media only screen and (max-width: 640px) {
  46 + body {
  47 + padding: 0 !important;
  48 + }
  49 +
  50 + h1 {
  51 + font-weight: 800 !important;
  52 + margin: 20px 0 5px !important;
  53 + }
  54 +
  55 + h2 {
  56 + font-weight: 800 !important;
  57 + margin: 20px 0 5px !important;
  58 + }
  59 +
  60 + h3 {
  61 + font-weight: 800 !important;
  62 + margin: 20px 0 5px !important;
  63 + }
  64 +
  65 + h4 {
  66 + font-weight: 800 !important;
  67 + margin: 20px 0 5px !important;
  68 + }
  69 +
  70 + h1 {
  71 + font-size: 22px !important;
  72 + }
  73 +
  74 + h2 {
  75 + font-size: 18px !important;
  76 + }
  77 +
  78 + h3 {
  79 + font-size: 16px !important;
  80 + }
  81 +
  82 + .container {
  83 + padding: 0 !important;
  84 + width: 100% !important;
  85 + }
  86 +
  87 + .content {
  88 + padding: 0 !important;
  89 + }
  90 +
  91 + .content-wrap {
  92 + padding: 10px !important;
  93 + }
  94 +
  95 + .invoice {
  96 + width: 100% !important;
  97 + }
  98 + }
  99 + </style>
  100 +</head>
  101 +
  102 +<body itemscope itemtype="http://schema.org/EmailMessage"
  103 + style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;"
  104 + bgcolor="#f6f6f6">
  105 +
  106 +<table class="main"
  107 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; border-radius: 3px; width: 100%; background-color: #f6f6f6; margin: 0px auto;"
  108 + cellspacing="0" cellpadding="0" bgcolor="#f6f6f6">
  109 + <tbody>
  110 + <tr style="box-sizing: border-box; margin: 0px;">
  111 + <td class="content-wrap" style="box-sizing: border-box; vertical-align: top; margin: 0px; padding: 20px;"
  112 + align="center" valign="top">
  113 + <table style="box-sizing: border-box; border: 1px solid #e9e9e9; border-radius: 3px; margin: 0px; height: 223px; padding: 20px; background-color: #ffffff; width: 600px; max-width: 600px !important;"
  114 + width="600" cellspacing="0" cellpadding="0">
  115 + <tbody>
  116 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  117 + <td class="content-block"
  118 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 84px;"
  119 + valign="top">
  120 + <h2>Your ThingsBoard account feature was enabled</h2>
  121 + </td>
  122 + </tr>
  123 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  124 + <td class="content-block"
  125 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
  126 + valign="top">We have enabled the ${apiFeature} for your account and ThingsBoard is already able to ${apiLabel} messages.
  127 + </td>
  128 + </tr>
  129 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  130 + <td class="content-block"
  131 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
  132 + valign="top">&mdash; The ThingsBoard
  133 + </td>
  134 + </tr>
  135 + </tbody>
  136 + </table>
  137 + </td>
  138 + </tr>
  139 + </tbody>
  140 +</table>
  141 +<table style="color: #999999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; margin: 0px auto; height: 64px; background-color: #f6f6f6; width: 100%;"
  142 + cellpadding="0px 0px 20px">
  143 + <tbody>
  144 + <tr style="box-sizing: border-box; margin: 0px;">
  145 + <td class="aligncenter content-block"
  146 + style="box-sizing: border-box; font-size: 12px; margin: 0px; padding: 0px 0px 20px; width: 600px; text-align: center; vertical-align: middle;"
  147 + align="center" valign="top">This email was sent to&nbsp;<a
  148 + style="box-sizing: border-box; color: #999999; margin: 0px;"
  149 + href="mailto:${targetEmail}">${targetEmail}</a>&nbsp;by ThingsBoard.
  150 + </td>
  151 + </tr>
  152 + </tbody>
  153 +</table>
  154 +</body>
  155 +</html>
  1 +<#--
  2 +
  3 + Copyright © 2016-2020 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 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  19 + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  20 +<html xmlns="http://www.w3.org/1999/xhtml"
  21 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  22 +<head>
  23 + <meta name="viewport" content="width=device-width"/>
  24 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  25 + <title>Thingsboard - Api Usage State</title>
  26 +
  27 +
  28 + <style type="text/css">
  29 + img {
  30 + max-width: 100%;
  31 + }
  32 +
  33 + body {
  34 + -webkit-font-smoothing: antialiased;
  35 + -webkit-text-size-adjust: none;
  36 + width: 100% !important;
  37 + height: 100%;
  38 + line-height: 1.6em;
  39 + }
  40 +
  41 + body {
  42 + background-color: #f6f6f6;
  43 + }
  44 +
  45 + @media only screen and (max-width: 640px) {
  46 + body {
  47 + padding: 0 !important;
  48 + }
  49 +
  50 + h1 {
  51 + font-weight: 800 !important;
  52 + margin: 20px 0 5px !important;
  53 + }
  54 +
  55 + h2 {
  56 + font-weight: 800 !important;
  57 + margin: 20px 0 5px !important;
  58 + }
  59 +
  60 + h3 {
  61 + font-weight: 800 !important;
  62 + margin: 20px 0 5px !important;
  63 + }
  64 +
  65 + h4 {
  66 + font-weight: 800 !important;
  67 + margin: 20px 0 5px !important;
  68 + }
  69 +
  70 + h1 {
  71 + font-size: 22px !important;
  72 + }
  73 +
  74 + h2 {
  75 + font-size: 18px !important;
  76 + }
  77 +
  78 + h3 {
  79 + font-size: 16px !important;
  80 + }
  81 +
  82 + .container {
  83 + padding: 0 !important;
  84 + width: 100% !important;
  85 + }
  86 +
  87 + .content {
  88 + padding: 0 !important;
  89 + }
  90 +
  91 + .content-wrap {
  92 + padding: 10px !important;
  93 + }
  94 +
  95 + .invoice {
  96 + width: 100% !important;
  97 + }
  98 + }
  99 + </style>
  100 +</head>
  101 +
  102 +<body itemscope itemtype="http://schema.org/EmailMessage"
  103 + style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; line-height: 1.6em; background-color: #f6f6f6; margin: 0;"
  104 + bgcolor="#f6f6f6">
  105 +
  106 +<table class="main"
  107 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; border-radius: 3px; width: 100%; background-color: #f6f6f6; margin: 0px auto;"
  108 + cellspacing="0" cellpadding="0" bgcolor="#f6f6f6">
  109 + <tbody>
  110 + <tr style="box-sizing: border-box; margin: 0px;">
  111 + <td class="content-wrap" style="box-sizing: border-box; vertical-align: top; margin: 0px; padding: 20px;"
  112 + align="center" valign="top">
  113 + <table style="box-sizing: border-box; border: 1px solid #e9e9e9; border-radius: 3px; margin: 0px; height: 223px; padding: 20px; background-color: #ffffff; width: 600px; max-width: 600px !important;"
  114 + width="600" cellspacing="0" cellpadding="0">
  115 + <tbody>
  116 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  117 + <td class="content-block"
  118 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #348eda; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 84px;"
  119 + valign="top">
  120 + <h2>Your ThingsBoard account feature may be disabled soon</h2>
  121 + </td>
  122 + </tr>
  123 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  124 + <td class="content-block"
  125 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
  126 + valign="top">
  127 + ThingsBoard has already&nbsp;${apiValueLabel}.<br> ${apiFeature} will be disabled for your account once the limit will be reached.
  128 + </td>
  129 + </tr>
  130 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  131 + <td class="content-block"
  132 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 59px;"
  133 + valign="top">Please contact your system administrator to resolve the issue.
  134 + </td>
  135 + </tr>
  136 + <tr style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
  137 + <td class="content-block"
  138 + style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; vertical-align: top; margin: 0px; padding: 0px 0px 20px; height: 40px;"
  139 + valign="top">&mdash; The ThingsBoard
  140 + </td>
  141 + </tr>
  142 + </tbody>
  143 + </table>
  144 + </td>
  145 + </tr>
  146 + </tbody>
  147 +</table>
  148 +<table style="color: #999999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; box-sizing: border-box; margin: 0px auto; height: 64px; background-color: #f6f6f6; width: 100%;"
  149 + cellpadding="0px 0px 20px">
  150 + <tbody>
  151 + <tr style="box-sizing: border-box; margin: 0px;">
  152 + <td class="aligncenter content-block"
  153 + style="box-sizing: border-box; font-size: 12px; margin: 0px; padding: 0px 0px 20px; width: 600px; text-align: center; vertical-align: middle;"
  154 + align="center" valign="top">This email was sent to&nbsp;<a
  155 + style="box-sizing: border-box; color: #999999; margin: 0px;"
  156 + href="mailto:${targetEmail}">${targetEmail}</a>&nbsp;by ThingsBoard.
  157 + </td>
  158 + </tr>
  159 + </tbody>
  160 +</table>
  161 +</body>
  162 +</html>
@@ -281,8 +281,12 @@ actors: @@ -281,8 +281,12 @@ actors:
281 js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:50}" 281 js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:50}"
282 # Specify thread pool size for mail sender executor service 282 # Specify thread pool size for mail sender executor service
283 mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:50}" 283 mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:50}"
  284 + # Specify thread pool size for sms sender executor service
  285 + sms_thread_pool_size: "${ACTORS_RULE_SMS_THREAD_POOL_SIZE:50}"
284 # Whether to allow usage of system mail service for rules 286 # Whether to allow usage of system mail service for rules
285 allow_system_mail_service: "${ACTORS_RULE_ALLOW_SYSTEM_MAIL_SERVICE:true}" 287 allow_system_mail_service: "${ACTORS_RULE_ALLOW_SYSTEM_MAIL_SERVICE:true}"
  288 + # Whether to allow usage of system sms service for rules
  289 + allow_system_sms_service: "${ACTORS_RULE_ALLOW_SYSTEM_SMS_SERVICE:true}"
286 # Specify thread pool size for external call service 290 # Specify thread pool size for external call service
287 external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:50}" 291 external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:50}"
288 chain: 292 chain:
@@ -591,6 +595,7 @@ queue: @@ -591,6 +595,7 @@ queue:
591 linger.ms: "${TB_KAFKA_LINGER_MS:1}" 595 linger.ms: "${TB_KAFKA_LINGER_MS:1}"
592 buffer.memory: "${TB_BUFFER_MEMORY:33554432}" 596 buffer.memory: "${TB_BUFFER_MEMORY:33554432}"
593 replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" 597 replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}"
  598 + max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:0}"
594 max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" 599 max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}"
595 max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" 600 max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}"
596 fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" 601 fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}"
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
18 -import com.datastax.oss.driver.api.core.uuid.Uuids;  
19 import com.fasterxml.jackson.core.type.TypeReference; 18 import com.fasterxml.jackson.core.type.TypeReference;
20 import com.fasterxml.jackson.databind.JsonNode; 19 import com.fasterxml.jackson.databind.JsonNode;
21 import com.fasterxml.jackson.databind.ObjectMapper; 20 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,12 +32,7 @@ import org.junit.Rule; @@ -33,12 +32,7 @@ import org.junit.Rule;
33 import org.junit.rules.TestRule; 32 import org.junit.rules.TestRule;
34 import org.junit.rules.TestWatcher; 33 import org.junit.rules.TestWatcher;
35 import org.junit.runner.Description; 34 import org.junit.runner.Description;
36 -import org.junit.runner.RunWith;  
37 import org.springframework.beans.factory.annotation.Autowired; 35 import org.springframework.beans.factory.annotation.Autowired;
38 -import org.springframework.boot.test.context.SpringBootContextLoader;  
39 -import org.springframework.boot.test.context.SpringBootTest;  
40 -import org.springframework.context.annotation.ComponentScan;  
41 -import org.springframework.context.annotation.Configuration;  
42 import org.springframework.http.HttpHeaders; 36 import org.springframework.http.HttpHeaders;
43 import org.springframework.http.MediaType; 37 import org.springframework.http.MediaType;
44 import org.springframework.http.converter.HttpMessageConverter; 38 import org.springframework.http.converter.HttpMessageConverter;
@@ -46,10 +40,6 @@ import org.springframework.http.converter.StringHttpMessageConverter; @@ -46,10 +40,6 @@ import org.springframework.http.converter.StringHttpMessageConverter;
46 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 40 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
47 import org.springframework.mock.http.MockHttpInputMessage; 41 import org.springframework.mock.http.MockHttpInputMessage;
48 import org.springframework.mock.http.MockHttpOutputMessage; 42 import org.springframework.mock.http.MockHttpOutputMessage;
49 -import org.springframework.test.annotation.DirtiesContext;  
50 -import org.springframework.test.context.ActiveProfiles;  
51 -import org.springframework.test.context.ContextConfiguration;  
52 -import org.springframework.test.context.junit4.SpringRunner;  
53 import org.springframework.test.web.servlet.MockMvc; 43 import org.springframework.test.web.servlet.MockMvc;
54 import org.springframework.test.web.servlet.MvcResult; 44 import org.springframework.test.web.servlet.MvcResult;
55 import org.springframework.test.web.servlet.ResultActions; 45 import org.springframework.test.web.servlet.ResultActions;
@@ -58,7 +48,6 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilde @@ -58,7 +48,6 @@ import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilde
58 import org.springframework.util.LinkedMultiValueMap; 48 import org.springframework.util.LinkedMultiValueMap;
59 import org.springframework.util.MultiValueMap; 49 import org.springframework.util.MultiValueMap;
60 import org.springframework.web.context.WebApplicationContext; 50 import org.springframework.web.context.WebApplicationContext;
61 -import org.thingsboard.server.common.data.BaseData;  
62 import org.thingsboard.server.common.data.Customer; 51 import org.thingsboard.server.common.data.Customer;
63 import org.thingsboard.server.common.data.DeviceProfile; 52 import org.thingsboard.server.common.data.DeviceProfile;
64 import org.thingsboard.server.common.data.DeviceProfileType; 53 import org.thingsboard.server.common.data.DeviceProfileType;
@@ -68,11 +57,13 @@ import org.thingsboard.server.common.data.User; @@ -68,11 +57,13 @@ import org.thingsboard.server.common.data.User;
68 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; 57 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
69 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; 58 import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration;
70 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 59 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
71 -import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; 60 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  61 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  62 +import org.thingsboard.server.common.data.device.profile.MqttTopics;
  63 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  64 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
72 import org.thingsboard.server.common.data.id.HasId; 65 import org.thingsboard.server.common.data.id.HasId;
73 -import org.thingsboard.server.common.data.id.RuleChainId;  
74 import org.thingsboard.server.common.data.id.TenantId; 66 import org.thingsboard.server.common.data.id.TenantId;
75 -import org.thingsboard.server.common.data.id.UUIDBased;  
76 import org.thingsboard.server.common.data.page.PageLink; 67 import org.thingsboard.server.common.data.page.PageLink;
77 import org.thingsboard.server.common.data.page.TimePageLink; 68 import org.thingsboard.server.common.data.page.TimePageLink;
78 import org.thingsboard.server.common.data.security.Authority; 69 import org.thingsboard.server.common.data.security.Authority;
@@ -330,7 +321,7 @@ public abstract class AbstractWebTest { @@ -330,7 +321,7 @@ public abstract class AbstractWebTest {
330 } 321 }
331 } 322 }
332 323
333 - protected DeviceProfile createDeviceProfile(String name) { 324 + protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) {
334 DeviceProfile deviceProfile = new DeviceProfile(); 325 DeviceProfile deviceProfile = new DeviceProfile();
335 deviceProfile.setName(name); 326 deviceProfile.setName(name);
336 deviceProfile.setType(DeviceProfileType.DEFAULT); 327 deviceProfile.setType(DeviceProfileType.DEFAULT);
@@ -338,15 +329,34 @@ public abstract class AbstractWebTest { @@ -338,15 +329,34 @@ public abstract class AbstractWebTest {
338 deviceProfile.setDescription(name + " Test"); 329 deviceProfile.setDescription(name + " Test");
339 DeviceProfileData deviceProfileData = new DeviceProfileData(); 330 DeviceProfileData deviceProfileData = new DeviceProfileData();
340 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); 331 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
341 - DefaultDeviceProfileTransportConfiguration transportConfiguration = new DefaultDeviceProfileTransportConfiguration();  
342 deviceProfileData.setConfiguration(configuration); 332 deviceProfileData.setConfiguration(configuration);
343 - deviceProfileData.setTransportConfiguration(transportConfiguration); 333 + if (deviceProfileTransportConfiguration != null) {
  334 + deviceProfileData.setTransportConfiguration(deviceProfileTransportConfiguration);
  335 + } else {
  336 + deviceProfileData.setTransportConfiguration(new DefaultDeviceProfileTransportConfiguration());
  337 + }
344 deviceProfile.setProfileData(deviceProfileData); 338 deviceProfile.setProfileData(deviceProfileData);
345 deviceProfile.setDefault(false); 339 deviceProfile.setDefault(false);
346 deviceProfile.setDefaultRuleChainId(null); 340 deviceProfile.setDefaultRuleChainId(null);
347 return deviceProfile; 341 return deviceProfile;
348 } 342 }
349 343
  344 + protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration) {
  345 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
  346 + mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_TELEMETRY_TOPIC);
  347 + mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
  348 + mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
  349 + return mqttDeviceProfileTransportConfiguration;
  350 + }
  351 +
  352 + protected ProtoTransportPayloadConfiguration createProtoTransportPayloadConfiguration(String deviceAttributesProtoSchema, String deviceTelemetryProtoSchema) {
  353 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
  354 + protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(deviceAttributesProtoSchema);
  355 + protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(deviceTelemetryProtoSchema);
  356 + return protoTransportPayloadConfiguration;
  357 + }
  358 +
  359 +
350 protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception { 360 protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception {
351 MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables); 361 MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables);
352 setJwtToken(getRequest); 362 setJwtToken(getRequest);
@@ -16,6 +16,12 @@ @@ -16,6 +16,12 @@
16 package org.thingsboard.server.controller; 16 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 com.github.os72.protobuf.dynamic.DynamicSchema;
  20 +import com.google.protobuf.Descriptors;
  21 +import com.google.protobuf.DynamicMessage;
  22 +import com.google.protobuf.InvalidProtocolBufferException;
  23 +import com.google.protobuf.util.JsonFormat;
  24 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
19 import org.junit.After; 25 import org.junit.After;
20 import org.junit.Assert; 26 import org.junit.Assert;
21 import org.junit.Before; 27 import org.junit.Before;
@@ -28,7 +34,10 @@ import org.thingsboard.server.common.data.DeviceProfileType; @@ -28,7 +34,10 @@ import org.thingsboard.server.common.data.DeviceProfileType;
28 import org.thingsboard.server.common.data.DeviceTransportType; 34 import org.thingsboard.server.common.data.DeviceTransportType;
29 import org.thingsboard.server.common.data.Tenant; 35 import org.thingsboard.server.common.data.Tenant;
30 import org.thingsboard.server.common.data.User; 36 import org.thingsboard.server.common.data.User;
31 -import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials; 37 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  38 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  39 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  40 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
32 import org.thingsboard.server.common.data.page.PageData; 41 import org.thingsboard.server.common.data.page.PageData;
33 import org.thingsboard.server.common.data.page.PageLink; 42 import org.thingsboard.server.common.data.page.PageLink;
34 import org.thingsboard.server.common.data.security.Authority; 43 import org.thingsboard.server.common.data.security.Authority;
@@ -36,9 +45,13 @@ import org.thingsboard.server.common.data.security.Authority; @@ -36,9 +45,13 @@ import org.thingsboard.server.common.data.security.Authority;
36 import java.util.ArrayList; 45 import java.util.ArrayList;
37 import java.util.Collections; 46 import java.util.Collections;
38 import java.util.List; 47 import java.util.List;
  48 +import java.util.Set;
39 import java.util.stream.Collectors; 49 import java.util.stream.Collectors;
40 50
41 import static org.hamcrest.Matchers.containsString; 51 import static org.hamcrest.Matchers.containsString;
  52 +import static org.junit.Assert.assertEquals;
  53 +import static org.junit.Assert.assertNotNull;
  54 +import static org.junit.Assert.assertTrue;
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 55 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 56
44 public abstract class BaseDeviceProfileControllerTest extends AbstractControllerTest { 57 public abstract class BaseDeviceProfileControllerTest extends AbstractControllerTest {
@@ -78,7 +91,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -78,7 +91,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
78 91
79 @Test 92 @Test
80 public void testSaveDeviceProfile() throws Exception { 93 public void testSaveDeviceProfile() throws Exception {
81 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 94 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
82 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 95 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
83 Assert.assertNotNull(savedDeviceProfile); 96 Assert.assertNotNull(savedDeviceProfile);
84 Assert.assertNotNull(savedDeviceProfile.getId()); 97 Assert.assertNotNull(savedDeviceProfile.getId());
@@ -96,7 +109,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -96,7 +109,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
96 109
97 @Test 110 @Test
98 public void testFindDeviceProfileById() throws Exception { 111 public void testFindDeviceProfileById() throws Exception {
99 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 112 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
100 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 113 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
101 DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class); 114 DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
102 Assert.assertNotNull(foundDeviceProfile); 115 Assert.assertNotNull(foundDeviceProfile);
@@ -105,7 +118,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -105,7 +118,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
105 118
106 @Test 119 @Test
107 public void testFindDeviceProfileInfoById() throws Exception { 120 public void testFindDeviceProfileInfoById() throws Exception {
108 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 121 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
109 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 122 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
110 DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/"+savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class); 123 DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/"+savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class);
111 Assert.assertNotNull(foundDeviceProfileInfo); 124 Assert.assertNotNull(foundDeviceProfileInfo);
@@ -127,7 +140,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -127,7 +140,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
127 140
128 @Test 141 @Test
129 public void testSetDefaultDeviceProfile() throws Exception { 142 public void testSetDefaultDeviceProfile() throws Exception {
130 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1"); 143 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1", null);
131 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 144 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
132 DeviceProfile defaultDeviceProfile = doPost("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString()+"/default", null, DeviceProfile.class); 145 DeviceProfile defaultDeviceProfile = doPost("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString()+"/default", null, DeviceProfile.class);
133 Assert.assertNotNull(defaultDeviceProfile); 146 Assert.assertNotNull(defaultDeviceProfile);
@@ -147,19 +160,19 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -147,19 +160,19 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
147 160
148 @Test 161 @Test
149 public void testSaveDeviceProfileWithSameName() throws Exception { 162 public void testSaveDeviceProfileWithSameName() throws Exception {
150 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 163 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
151 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk()); 164 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk());
152 - DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile"); 165 + DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile", null);
153 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest()) 166 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest())
154 .andExpect(statusReason(containsString("Device profile with such name already exists"))); 167 .andExpect(statusReason(containsString("Device profile with such name already exists")));
155 } 168 }
156 169
157 @Test 170 @Test
158 public void testSaveDeviceProfileWithSameProvisionDeviceKey() throws Exception { 171 public void testSaveDeviceProfileWithSameProvisionDeviceKey() throws Exception {
159 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 172 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
160 deviceProfile.setProvisionDeviceKey("testProvisionDeviceKey"); 173 deviceProfile.setProvisionDeviceKey("testProvisionDeviceKey");
161 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk()); 174 doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk());
162 - DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2"); 175 + DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2", null);
163 deviceProfile2.setProvisionDeviceKey("testProvisionDeviceKey"); 176 deviceProfile2.setProvisionDeviceKey("testProvisionDeviceKey");
164 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest()) 177 doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest())
165 .andExpect(statusReason(containsString("Device profile with such provision device key already exists"))); 178 .andExpect(statusReason(containsString("Device profile with such provision device key already exists")));
@@ -168,7 +181,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -168,7 +181,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
168 @Ignore 181 @Ignore
169 @Test 182 @Test
170 public void testChangeDeviceProfileTypeWithExistingDevices() throws Exception { 183 public void testChangeDeviceProfileTypeWithExistingDevices() throws Exception {
171 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 184 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
172 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 185 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
173 Device device = new Device(); 186 Device device = new Device();
174 device.setName("Test device"); 187 device.setName("Test device");
@@ -183,7 +196,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -183,7 +196,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
183 196
184 @Test 197 @Test
185 public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception { 198 public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception {
186 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 199 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
187 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 200 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
188 Device device = new Device(); 201 Device device = new Device();
189 device.setName("Test device"); 202 device.setName("Test device");
@@ -197,7 +210,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -197,7 +210,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
197 210
198 @Test 211 @Test
199 public void testDeleteDeviceProfileWithExistingDevice() throws Exception { 212 public void testDeleteDeviceProfileWithExistingDevice() throws Exception {
200 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 213 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
201 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 214 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
202 215
203 Device device = new Device(); 216 Device device = new Device();
@@ -214,7 +227,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -214,7 +227,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
214 227
215 @Test 228 @Test
216 public void testDeleteDeviceProfile() throws Exception { 229 public void testDeleteDeviceProfile() throws Exception {
217 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"); 230 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null);
218 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); 231 DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
219 232
220 doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString()) 233 doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString())
@@ -235,7 +248,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -235,7 +248,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
235 deviceProfiles.addAll(pageData.getData()); 248 deviceProfiles.addAll(pageData.getData());
236 249
237 for (int i=0;i<28;i++) { 250 for (int i=0;i<28;i++) {
238 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i); 251 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i, null);
239 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); 252 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
240 } 253 }
241 254
@@ -280,7 +293,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -280,7 +293,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
280 deviceProfiles.addAll(deviceProfilePageData.getData()); 293 deviceProfiles.addAll(deviceProfilePageData.getData());
281 294
282 for (int i=0;i<28;i++) { 295 for (int i=0;i<28;i++) {
283 - DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i); 296 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i, null);
284 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); 297 deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
285 } 298 }
286 299
@@ -318,4 +331,341 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController @@ -318,4 +331,341 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
318 Assert.assertEquals(1, pageData.getTotalElements()); 331 Assert.assertEquals(1, pageData.getTotalElements());
319 } 332 }
320 333
  334 + @Test
  335 + public void testSaveProtoDeviceProfileWithInvalidProtoFile() throws Exception {
  336 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  337 + "\n" +
  338 + "package schemavalidation;\n" +
  339 + "\n" +
  340 + "message SchemaValidationTest {\n" +
  341 + " required int32 parameter = 1;\n" +
  342 + "}", "[Transport Configuration] failed to parse attributes proto schema due to: Syntax error in :6:4: 'required' label forbidden in proto3 field declarations");
  343 + }
  344 +
  345 + @Test
  346 + public void testSaveProtoDeviceProfileWithInvalidProtoSyntax() throws Exception {
  347 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto2\";\n" +
  348 + "\n" +
  349 + "package schemavalidation;\n" +
  350 + "\n" +
  351 + "message SchemaValidationTest {\n" +
  352 + " required int32 parameter = 1;\n" +
  353 + "}", "[Transport Configuration] invalid schema syntax: proto2 for attributes proto schema provided! Only proto3 allowed!");
  354 + }
  355 +
  356 + @Test
  357 + public void testSaveProtoDeviceProfileOptionsNotSupported() throws Exception {
  358 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  359 + "\n" +
  360 + "option java_package = \"com.test.schemavalidation\";\n" +
  361 + "option java_multiple_files = true;\n" +
  362 + "\n" +
  363 + "package schemavalidation;\n" +
  364 + "\n" +
  365 + "message SchemaValidationTest {\n" +
  366 + " int32 parameter = 1;\n" +
  367 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema options don't support!");
  368 + }
  369 +
  370 + @Test
  371 + public void testSaveProtoDeviceProfilePublicImportsNotSupported() throws Exception {
  372 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  373 + "\n" +
  374 + "import public \"oldschema.proto\";\n" +
  375 + "\n" +
  376 + "package schemavalidation;\n" +
  377 + "\n" +
  378 + "message SchemaValidationTest {\n" +
  379 + " int32 parameter = 1;\n" +
  380 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema public imports don't support!");
  381 + }
  382 +
  383 + @Test
  384 + public void testSaveProtoDeviceProfileImportsNotSupported() throws Exception {
  385 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  386 + "\n" +
  387 + "import \"oldschema.proto\";\n" +
  388 + "\n" +
  389 + "package schemavalidation;\n" +
  390 + "\n" +
  391 + "message SchemaValidationTest {\n" +
  392 + " int32 parameter = 1;\n" +
  393 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema imports don't support!");
  394 + }
  395 +
  396 + @Test
  397 + public void testSaveProtoDeviceProfileExtendDeclarationsNotSupported() throws Exception {
  398 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  399 + "\n" +
  400 + "package schemavalidation;\n" +
  401 + "\n" +
  402 + "extend google.protobuf.MethodOptions {\n" +
  403 + " MyMessage my_method_option = 50007;\n" +
  404 + "}", "[Transport Configuration] invalid attributes proto schema provided! Schema extend declarations don't support!");
  405 + }
  406 +
  407 + @Test
  408 + public void testSaveProtoDeviceProfileEnumOptionsNotSupported() throws Exception {
  409 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  410 + "\n" +
  411 + "package schemavalidation;\n" +
  412 + "\n" +
  413 + "enum testEnum {\n" +
  414 + " option allow_alias = true;\n" +
  415 + " DEFAULT = 0;\n" +
  416 + " STARTED = 1;\n" +
  417 + " RUNNING = 2;\n" +
  418 + "}\n" +
  419 + "\n" +
  420 + "message testMessage {\n" +
  421 + " int32 parameter = 1;\n" +
  422 + "}", "[Transport Configuration] invalid attributes proto schema provided! Enum definitions options are not supported!");
  423 + }
  424 +
  425 + @Test
  426 + public void testSaveProtoDeviceProfileNoOneMessageTypeExists() throws Exception {
  427 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  428 + "\n" +
  429 + "package schemavalidation;\n" +
  430 + "\n" +
  431 + "enum testEnum {\n" +
  432 + " DEFAULT = 0;\n" +
  433 + " STARTED = 1;\n" +
  434 + " RUNNING = 2;\n" +
  435 + "}", "[Transport Configuration] invalid attributes proto schema provided! At least one Message definition should exists!");
  436 + }
  437 +
  438 + @Test
  439 + public void testSaveProtoDeviceProfileMessageTypeOptionsNotSupported() throws Exception {
  440 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  441 + "\n" +
  442 + "package schemavalidation;\n" +
  443 + "\n" +
  444 + "message testMessage {\n" +
  445 + " option allow_alias = true;\n" +
  446 + " int32 parameter = 1;\n" +
  447 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition options don't support!");
  448 + }
  449 +
  450 + @Test
  451 + public void testSaveProtoDeviceProfileMessageTypeExtensionsNotSupported() throws Exception {
  452 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  453 + "\n" +
  454 + "package schemavalidation;\n" +
  455 + "\n" +
  456 + "message TestMessage {\n" +
  457 + " extensions 100 to 199;\n" +
  458 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition extensions don't support!");
  459 + }
  460 +
  461 + @Test
  462 + public void testSaveProtoDeviceProfileMessageTypeReservedElementsNotSupported() throws Exception {
  463 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  464 + "\n" +
  465 + "package schemavalidation;\n" +
  466 + "\n" +
  467 + "message Foo {\n" +
  468 + " reserved 2, 15, 9 to 11;\n" +
  469 + " reserved \"foo\", \"bar\";\n" +
  470 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition reserved elements don't support!");
  471 + }
  472 +
  473 + @Test
  474 + public void testSaveProtoDeviceProfileMessageTypeGroupsElementsNotSupported() throws Exception {
  475 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  476 + "\n" +
  477 + "package schemavalidation;\n" +
  478 + "\n" +
  479 + "message TestMessage {\n" +
  480 + " repeated group Result = 1 {\n" +
  481 + " string url = 2;\n" +
  482 + " string title = 3;\n" +
  483 + " repeated string snippets = 4;\n" +
  484 + " }\n" +
  485 + "}", "[Transport Configuration] invalid attributes proto schema provided! Message definition groups don't support!");
  486 + }
  487 +
  488 + @Test
  489 + public void testSaveProtoDeviceProfileOneOfsGroupsElementsNotSupported() throws Exception {
  490 + testSaveDeviceProfileWithInvalidProtoSchema("syntax = \"proto3\";\n" +
  491 + "\n" +
  492 + "package schemavalidation;\n" +
  493 + "\n" +
  494 + "message SampleMessage {\n" +
  495 + " oneof test_oneof {\n" +
  496 + " string name = 1;\n" +
  497 + " group Result = 2 {\n" +
  498 + " \tstring url = 3;\n" +
  499 + " \tstring title = 4;\n" +
  500 + " \trepeated string snippets = 5;\n" +
  501 + " }\n" +
  502 + " }" +
  503 + "}", "[Transport Configuration] invalid attributes proto schema provided! OneOf definition groups don't support!");
  504 + }
  505 +
  506 + @Test
  507 + public void testSaveProtoDeviceProfileWithMessageNestedTypes() throws Exception {
  508 + String schema = "syntax = \"proto3\";\n" +
  509 + "\n" +
  510 + "package testnested;\n" +
  511 + "\n" +
  512 + "message Outer {\n" +
  513 + " message MiddleAA {\n" +
  514 + " message Inner {\n" +
  515 + " int64 ival = 1;\n" +
  516 + " bool booly = 2;\n" +
  517 + " }\n" +
  518 + " Inner inner = 1;\n" +
  519 + " }\n" +
  520 + " message MiddleBB {\n" +
  521 + " message Inner {\n" +
  522 + " int32 ival = 1;\n" +
  523 + " bool booly = 2;\n" +
  524 + " }\n" +
  525 + " Inner inner = 1;\n" +
  526 + " }\n" +
  527 + " MiddleAA middleAA = 1;\n" +
  528 + " MiddleBB middleBB = 2;\n" +
  529 + "}";
  530 + DynamicSchema dynamicSchema = getDynamicSchema(schema);
  531 + assertNotNull(dynamicSchema);
  532 + Set<String> messageTypes = dynamicSchema.getMessageTypes();
  533 + assertEquals(5, messageTypes.size());
  534 + assertTrue(messageTypes.contains("testnested.Outer"));
  535 + assertTrue(messageTypes.contains("testnested.Outer.MiddleAA"));
  536 + assertTrue(messageTypes.contains("testnested.Outer.MiddleAA.Inner"));
  537 + assertTrue(messageTypes.contains("testnested.Outer.MiddleBB"));
  538 + assertTrue(messageTypes.contains("testnested.Outer.MiddleBB.Inner"));
  539 +
  540 + DynamicMessage.Builder middleAAInnerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA.Inner");
  541 + Descriptors.Descriptor middleAAInnerMsgDescriptor = middleAAInnerMsgBuilder.getDescriptorForType();
  542 + DynamicMessage middleAAInnerMsg = middleAAInnerMsgBuilder
  543 + .setField(middleAAInnerMsgDescriptor.findFieldByName("ival"), 1L)
  544 + .setField(middleAAInnerMsgDescriptor.findFieldByName("booly"), true)
  545 + .build();
  546 +
  547 + DynamicMessage.Builder middleAAMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA");
  548 + Descriptors.Descriptor middleAAMsgDescriptor = middleAAMsgBuilder.getDescriptorForType();
  549 + DynamicMessage middleAAMsg = middleAAMsgBuilder
  550 + .setField(middleAAMsgDescriptor.findFieldByName("inner"), middleAAInnerMsg)
  551 + .build();
  552 +
  553 + DynamicMessage.Builder middleBBInnerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleAA.Inner");
  554 + Descriptors.Descriptor middleBBInnerMsgDescriptor = middleBBInnerMsgBuilder.getDescriptorForType();
  555 + DynamicMessage middleBBInnerMsg = middleBBInnerMsgBuilder
  556 + .setField(middleBBInnerMsgDescriptor.findFieldByName("ival"), 0L)
  557 + .setField(middleBBInnerMsgDescriptor.findFieldByName("booly"), false)
  558 + .build();
  559 +
  560 + DynamicMessage.Builder middleBBMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer.MiddleBB");
  561 + Descriptors.Descriptor middleBBMsgDescriptor = middleBBMsgBuilder.getDescriptorForType();
  562 + DynamicMessage middleBBMsg = middleBBMsgBuilder
  563 + .setField(middleBBMsgDescriptor.findFieldByName("inner"), middleBBInnerMsg)
  564 + .build();
  565 +
  566 +
  567 + DynamicMessage.Builder outerMsgBuilder = dynamicSchema.newMessageBuilder("testnested.Outer");
  568 + Descriptors.Descriptor outerMsgBuilderDescriptor = outerMsgBuilder.getDescriptorForType();
  569 + DynamicMessage outerMsg = outerMsgBuilder
  570 + .setField(outerMsgBuilderDescriptor.findFieldByName("middleAA"), middleAAMsg)
  571 + .setField(outerMsgBuilderDescriptor.findFieldByName("middleBB"), middleBBMsg)
  572 + .build();
  573 +
  574 + assertEquals("{\n" +
  575 + " \"middleAA\": {\n" +
  576 + " \"inner\": {\n" +
  577 + " \"ival\": \"1\",\n" +
  578 + " \"booly\": true\n" +
  579 + " }\n" +
  580 + " },\n" +
  581 + " \"middleBB\": {\n" +
  582 + " \"inner\": {\n" +
  583 + " \"ival\": 0,\n" +
  584 + " \"booly\": false\n" +
  585 + " }\n" +
  586 + " }\n" +
  587 + "}", dynamicMsgToJson(outerMsgBuilderDescriptor, outerMsg.toByteArray()));
  588 + }
  589 +
  590 + @Test
  591 + public void testSaveProtoDeviceProfileWithMessageOneOfs() throws Exception {
  592 + String schema = "syntax = \"proto3\";\n" +
  593 + "\n" +
  594 + "package testoneofs;\n" +
  595 + "\n" +
  596 + "message SubMessage {\n" +
  597 + " repeated string name = 1;\n" +
  598 + "}\n" +
  599 + "\n" +
  600 + "message SampleMessage {\n" +
  601 + " oneof testOneOf {\n" +
  602 + " string name = 4;\n" +
  603 + " SubMessage subMessage = 9;\n" +
  604 + " }\n" +
  605 + "}";
  606 + DynamicSchema dynamicSchema = getDynamicSchema(schema);
  607 + assertNotNull(dynamicSchema);
  608 + Set<String> messageTypes = dynamicSchema.getMessageTypes();
  609 + assertEquals(2, messageTypes.size());
  610 + assertTrue(messageTypes.contains("testoneofs.SubMessage"));
  611 + assertTrue(messageTypes.contains("testoneofs.SampleMessage"));
  612 +
  613 + DynamicMessage.Builder sampleMsgBuilder = dynamicSchema.newMessageBuilder("testoneofs.SampleMessage");
  614 + Descriptors.Descriptor sampleMsgDescriptor = sampleMsgBuilder.getDescriptorForType();
  615 + assertNotNull(sampleMsgDescriptor);
  616 +
  617 + List<Descriptors.FieldDescriptor> fields = sampleMsgDescriptor.getFields();
  618 + assertEquals(2, fields.size());
  619 + DynamicMessage sampleMsg = sampleMsgBuilder
  620 + .setField(sampleMsgDescriptor.findFieldByName("name"), "Bob")
  621 + .build();
  622 + assertEquals("{\n" + " \"name\": \"Bob\"\n" + "}", dynamicMsgToJson(sampleMsgDescriptor, sampleMsg.toByteArray()));
  623 +
  624 + DynamicMessage.Builder subMsgBuilder = dynamicSchema.newMessageBuilder("testoneofs.SubMessage");
  625 + Descriptors.Descriptor subMsgDescriptor = subMsgBuilder.getDescriptorForType();
  626 + DynamicMessage subMsg = subMsgBuilder
  627 + .addRepeatedField(subMsgDescriptor.findFieldByName("name"), "Alice")
  628 + .addRepeatedField(subMsgDescriptor.findFieldByName("name"), "John")
  629 + .build();
  630 +
  631 + DynamicMessage sampleMsgWithOneOfSubMessage = sampleMsgBuilder.setField(sampleMsgDescriptor.findFieldByName("subMessage"), subMsg).build();
  632 + assertEquals("{\n" + " \"subMessage\": {\n" + " \"name\": [\"Alice\", \"John\"]\n" + " }\n" + "}",
  633 + dynamicMsgToJson(sampleMsgDescriptor, sampleMsgWithOneOfSubMessage.toByteArray()));
  634 + }
  635 +
  636 + private DeviceProfile testSaveDeviceProfileWithProtoPayloadType(String schema) throws Exception {
  637 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema);
  638 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration);
  639 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
  640 + DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
  641 + DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
  642 + Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName());
  643 + return savedDeviceProfile;
  644 + }
  645 +
  646 + private void testSaveDeviceProfileWithInvalidProtoSchema(String schema, String errorMsg) throws Exception {
  647 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema);
  648 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration);
  649 + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
  650 + doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
  651 + .andExpect(statusReason(containsString(errorMsg)));
  652 + }
  653 +
  654 + private DynamicSchema getDynamicSchema(String schema) throws Exception {
  655 + DeviceProfile deviceProfile = testSaveDeviceProfileWithProtoPayloadType(schema);
  656 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  657 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  658 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  659 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttDeviceProfileTransportConfiguration.getTransportPayloadTypeConfiguration();
  660 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  661 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  662 + ProtoFileElement protoFile = protoTransportPayloadConfiguration.getTransportProtoSchema(schema);
  663 + return protoTransportPayloadConfiguration.getDynamicSchema(protoFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  664 + }
  665 +
  666 + private String dynamicMsgToJson(Descriptors.Descriptor descriptor, byte[] payload) throws InvalidProtocolBufferException {
  667 + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor, payload);
  668 + return JsonFormat.printer().includingDefaultValueFields().print(dynamicMessage);
  669 + }
  670 +
321 } 671 }
@@ -38,7 +38,10 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon @@ -38,7 +38,10 @@ import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileCon
38 import org.thingsboard.server.common.data.device.profile.DeviceProfileData; 38 import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
39 import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration; 39 import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration;
40 import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; 40 import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
41 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; 42 import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  43 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  44 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
42 import org.thingsboard.server.common.data.security.Authority; 45 import org.thingsboard.server.common.data.security.Authority;
43 import org.thingsboard.server.common.data.security.DeviceCredentials; 46 import org.thingsboard.server.common.data.security.DeviceCredentials;
44 import org.thingsboard.server.controller.AbstractControllerTest; 47 import org.thingsboard.server.controller.AbstractControllerTest;
@@ -47,7 +50,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; @@ -47,7 +50,6 @@ import org.thingsboard.server.gen.transport.TransportProtos;
47 import java.util.ArrayList; 50 import java.util.ArrayList;
48 import java.util.List; 51 import java.util.List;
49 import java.util.concurrent.atomic.AtomicInteger; 52 import java.util.concurrent.atomic.AtomicInteger;
50 -import java.util.function.Supplier;  
51 53
52 import static org.junit.Assert.assertEquals; 54 import static org.junit.Assert.assertEquals;
53 import static org.junit.Assert.assertNotNull; 55 import static org.junit.Assert.assertNotNull;
@@ -60,6 +62,48 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -60,6 +62,48 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
60 62
61 private static final AtomicInteger atomicInteger = new AtomicInteger(2); 63 private static final AtomicInteger atomicInteger = new AtomicInteger(2);
62 64
  65 + public static final String DEVICE_TELEMETRY_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  66 + "\n" +
  67 + "package test;\n" +
  68 + "\n" +
  69 + "message PostTelemetry {\n" +
  70 + " string key1 = 1;\n" +
  71 + " bool key2 = 2;\n" +
  72 + " double key3 = 3;\n" +
  73 + " int32 key4 = 4;\n" +
  74 + " JsonObject key5 = 5;\n" +
  75 + "\n" +
  76 + " message JsonObject {\n" +
  77 + " int32 someNumber = 6;\n" +
  78 + " repeated int32 someArray = 7;\n" +
  79 + " NestedJsonObject someNestedObject = 8;\n" +
  80 + " message NestedJsonObject {\n" +
  81 + " string key = 9;\n" +
  82 + " }\n" +
  83 + " }\n" +
  84 + "}";
  85 +
  86 + public static final String DEVICE_ATTRIBUTES_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  87 + "\n" +
  88 + "package test;\n" +
  89 + "\n" +
  90 + "message PostAttributes {\n" +
  91 + " string key1 = 1;\n" +
  92 + " bool key2 = 2;\n" +
  93 + " double key3 = 3;\n" +
  94 + " int32 key4 = 4;\n" +
  95 + " JsonObject key5 = 5;\n" +
  96 + "\n" +
  97 + " message JsonObject {\n" +
  98 + " int32 someNumber = 6;\n" +
  99 + " repeated int32 someArray = 7;\n" +
  100 + " NestedJsonObject someNestedObject = 8;\n" +
  101 + " message NestedJsonObject {\n" +
  102 + " string key = 9;\n" +
  103 + " }\n" +
  104 + " }\n" +
  105 + "}";
  106 +
63 protected Tenant savedTenant; 107 protected Tenant savedTenant;
64 protected User tenantAdmin; 108 protected User tenantAdmin;
65 109
@@ -69,8 +113,10 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -69,8 +113,10 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
69 protected Device savedGateway; 113 protected Device savedGateway;
70 protected String gatewayAccessToken; 114 protected String gatewayAccessToken;
71 115
  116 + protected DeviceProfile deviceProfile;
  117 +
72 protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception { 118 protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
73 - this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, DeviceProfileProvisionType.DISABLED, null, null); 119 + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, DeviceProfileProvisionType.DISABLED, null, null);
74 } 120 }
75 121
76 protected void processBeforeTest(String deviceName, 122 protected void processBeforeTest(String deviceName,
@@ -78,6 +124,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -78,6 +124,8 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
78 TransportPayloadType payloadType, 124 TransportPayloadType payloadType,
79 String telemetryTopic, 125 String telemetryTopic,
80 String attributesTopic, 126 String attributesTopic,
  127 + String telemetryProtoSchema,
  128 + String attributesProtoSchema,
81 DeviceProfileProvisionType provisionType, 129 DeviceProfileProvisionType provisionType,
82 String provisionKey, String provisionSecret 130 String provisionKey, String provisionSecret
83 ) throws Exception { 131 ) throws Exception {
@@ -109,12 +157,12 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -109,12 +157,12 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
109 gateway.setAdditionalInfo(additionalInfo); 157 gateway.setAdditionalInfo(additionalInfo);
110 158
111 if (payloadType != null) { 159 if (payloadType != null) {
112 - DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, provisionType, provisionKey, provisionSecret);  
113 - DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class);  
114 - device.setType(savedDeviceProfile.getName());  
115 - device.setDeviceProfileId(savedDeviceProfile.getId());  
116 - gateway.setType(savedDeviceProfile.getName());  
117 - gateway.setDeviceProfileId(savedDeviceProfile.getId()); 160 + DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, provisionType, provisionKey, provisionSecret);
  161 + deviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class);
  162 + device.setType(deviceProfile.getName());
  163 + device.setDeviceProfileId(deviceProfile.getId());
  164 + gateway.setType(deviceProfile.getName());
  165 + gateway.setDeviceProfileId(deviceProfile.getId());
118 } 166 }
119 167
120 savedDevice = doPost("/api/device", device, Device.class); 168 savedDevice = doPost("/api/device", device, Device.class);
@@ -201,9 +249,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -201,9 +249,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
201 249
202 protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType, 250 protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType,
203 String telemetryTopic, String attributesTopic, 251 String telemetryTopic, String attributesTopic,
  252 + String telemetryProtoSchema, String attributesProtoSchema,
204 DeviceProfileProvisionType provisionType, 253 DeviceProfileProvisionType provisionType,
205 - String provisionKey, String provisionSecret  
206 - ) { 254 + String provisionKey, String provisionSecret) {
207 DeviceProfile deviceProfile = new DeviceProfile(); 255 DeviceProfile deviceProfile = new DeviceProfile();
208 deviceProfile.setName(transportPayloadType.name()); 256 deviceProfile.setName(transportPayloadType.name());
209 deviceProfile.setType(DeviceProfileType.DEFAULT); 257 deviceProfile.setType(DeviceProfileType.DEFAULT);
@@ -213,15 +261,30 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -213,15 +261,30 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
213 deviceProfile.setDescription(transportPayloadType.name() + " Test"); 261 deviceProfile.setDescription(transportPayloadType.name() + " Test");
214 DeviceProfileData deviceProfileData = new DeviceProfileData(); 262 DeviceProfileData deviceProfileData = new DeviceProfileData();
215 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); 263 DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
216 - MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration();  
217 - transportConfiguration.setTransportPayloadType(transportPayloadType); 264 + MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
218 if (!StringUtils.isEmpty(telemetryTopic)) { 265 if (!StringUtils.isEmpty(telemetryTopic)) {
219 - transportConfiguration.setDeviceTelemetryTopic(telemetryTopic); 266 + mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(telemetryTopic);
220 } 267 }
221 if (!StringUtils.isEmpty(attributesTopic)) { 268 if (!StringUtils.isEmpty(attributesTopic)) {
222 - transportConfiguration.setDeviceAttributesTopic(attributesTopic); 269 + mqttDeviceProfileTransportConfiguration.setDeviceAttributesTopic(attributesTopic);
223 } 270 }
224 - deviceProfileData.setTransportConfiguration(transportConfiguration); 271 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
  272 + if (TransportPayloadType.JSON.equals(transportPayloadType)) {
  273 + transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration();
  274 + } else {
  275 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
  276 + if (StringUtils.isEmpty(telemetryProtoSchema)) {
  277 + telemetryProtoSchema = DEVICE_TELEMETRY_PROTO_SCHEMA;
  278 + }
  279 + if (StringUtils.isEmpty(attributesProtoSchema)) {
  280 + attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA;
  281 + }
  282 + protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema);
  283 + protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
  284 + transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
  285 + }
  286 + mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
  287 + deviceProfileData.setTransportConfiguration(mqttDeviceProfileTransportConfiguration);
225 DeviceProfileProvisionConfiguration provisionConfiguration; 288 DeviceProfileProvisionConfiguration provisionConfiguration;
226 switch (provisionType) { 289 switch (provisionType) {
227 case ALLOW_CREATE_NEW_DEVICES: 290 case ALLOW_CREATE_NEW_DEVICES:
@@ -233,6 +296,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest @@ -233,6 +296,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest
233 case DISABLED: 296 case DISABLED:
234 default: 297 default:
235 provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret); 298 provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret);
  299 + break;
236 } 300 }
237 deviceProfileData.setProvisionConfiguration(provisionConfiguration); 301 deviceProfileData.setProvisionConfiguration(provisionConfiguration);
238 deviceProfileData.setConfiguration(configuration); 302 deviceProfileData.setConfiguration(configuration);
@@ -56,7 +56,6 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt @@ -56,7 +56,6 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt
56 return tsKvProtoList; 56 return tsKvProtoList;
57 } 57 }
58 58
59 -  
60 protected TransportProtos.TsKvProto getTsKvProto(String key, String value, TransportProtos.KeyValueType keyValueType) { 59 protected TransportProtos.TsKvProto getTsKvProto(String key, String value, TransportProtos.KeyValueType keyValueType) {
61 TransportProtos.TsKvProto.Builder tsKvProtoBuilder = TransportProtos.TsKvProto.newBuilder(); 60 TransportProtos.TsKvProto.Builder tsKvProtoBuilder = TransportProtos.TsKvProto.newBuilder();
62 TransportProtos.KeyValueProto keyValueProto = getKeyValueProto(key, value, keyValueType); 61 TransportProtos.KeyValueProto keyValueProto = getKeyValueProto(key, value, keyValueType);
@@ -18,9 +18,7 @@ package org.thingsboard.server.mqtt.attributes.request; @@ -18,9 +18,7 @@ package org.thingsboard.server.mqtt.attributes.request;
18 import com.google.protobuf.InvalidProtocolBufferException; 18 import com.google.protobuf.InvalidProtocolBufferException;
19 import io.netty.handler.codec.mqtt.MqttQoS; 19 import io.netty.handler.codec.mqtt.MqttQoS;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;  
22 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 21 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
23 -import org.eclipse.paho.client.mqttv3.MqttCallback;  
24 import org.eclipse.paho.client.mqttv3.MqttException; 22 import org.eclipse.paho.client.mqttv3.MqttException;
25 import org.eclipse.paho.client.mqttv3.MqttMessage; 23 import org.eclipse.paho.client.mqttv3.MqttMessage;
26 import org.junit.After; 24 import org.junit.After;
@@ -36,9 +34,7 @@ import java.util.concurrent.CountDownLatch; @@ -36,9 +34,7 @@ import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit; 34 import java.util.concurrent.TimeUnit;
37 35
38 import static org.junit.Assert.assertEquals; 36 import static org.junit.Assert.assertEquals;
39 -import static org.junit.Assert.assertFalse;  
40 import static org.junit.Assert.assertNotNull; 37 import static org.junit.Assert.assertNotNull;
41 -import static org.junit.Assert.assertTrue;  
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 38 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 39
44 @Slf4j 40 @Slf4j
@@ -18,14 +18,9 @@ package org.thingsboard.server.mqtt.attributes.request; @@ -18,14 +18,9 @@ package org.thingsboard.server.mqtt.attributes.request;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.junit.After; 19 import org.junit.After;
20 import org.junit.Before; 20 import org.junit.Before;
21 -import org.junit.Ignore;  
22 import org.junit.Test; 21 import org.junit.Test;
23 import org.thingsboard.server.common.data.TransportPayloadType; 22 import org.thingsboard.server.common.data.TransportPayloadType;
24 23
25 -import static org.junit.Assert.assertEquals;  
26 -import static org.junit.Assert.assertNotNull;  
27 -import static org.junit.Assert.assertTrue;  
28 -  
29 @Slf4j 24 @Slf4j
30 public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { 25 public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
31 26
@@ -15,18 +15,26 @@ @@ -15,18 +15,26 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.attributes.request; 16 package org.thingsboard.server.mqtt.attributes.request;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
18 import com.google.protobuf.InvalidProtocolBufferException; 21 import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
19 import io.netty.handler.codec.mqtt.MqttQoS; 23 import io.netty.handler.codec.mqtt.MqttQoS;
20 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
21 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 25 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
22 import org.eclipse.paho.client.mqttv3.MqttException; 26 import org.eclipse.paho.client.mqttv3.MqttException;
23 import org.eclipse.paho.client.mqttv3.MqttMessage; 27 import org.eclipse.paho.client.mqttv3.MqttMessage;
24 import org.junit.After; 28 import org.junit.After;
25 -import org.junit.Before;  
26 import org.junit.Test; 29 import org.junit.Test;
27 import org.thingsboard.server.common.data.Device; 30 import org.thingsboard.server.common.data.Device;
  31 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
28 import org.thingsboard.server.common.data.TransportPayloadType; 32 import org.thingsboard.server.common.data.TransportPayloadType;
  33 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  34 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  35 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
29 import org.thingsboard.server.common.data.device.profile.MqttTopics; 36 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  37 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
30 import org.thingsboard.server.gen.transport.TransportApiProtos; 38 import org.thingsboard.server.gen.transport.TransportApiProtos;
31 import org.thingsboard.server.gen.transport.TransportProtos; 39 import org.thingsboard.server.gen.transport.TransportProtos;
32 40
@@ -38,16 +46,33 @@ import java.util.concurrent.TimeUnit; @@ -38,16 +46,33 @@ import java.util.concurrent.TimeUnit;
38 import java.util.stream.Collectors; 46 import java.util.stream.Collectors;
39 47
40 import static org.junit.Assert.assertEquals; 48 import static org.junit.Assert.assertEquals;
  49 +import static org.junit.Assert.assertNotNull;
41 import static org.junit.Assert.assertTrue; 50 import static org.junit.Assert.assertTrue;
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 51 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 52
44 @Slf4j 53 @Slf4j
45 public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { 54 public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest {
46 55
47 - @Before  
48 - public void beforeTest() throws Exception {  
49 - processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null);  
50 - } 56 + public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" +
  57 + "\n" +
  58 + "package test;\n" +
  59 + "\n" +
  60 + "message PostAttributes {\n" +
  61 + " string attribute1 = 1;\n" +
  62 + " bool attribute2 = 2;\n" +
  63 + " double attribute3 = 3;\n" +
  64 + " int32 attribute4 = 4;\n" +
  65 + " JsonObject attribute5 = 5;\n" +
  66 + "\n" +
  67 + " message JsonObject {\n" +
  68 + " int32 someNumber = 6;\n" +
  69 + " repeated int32 someArray = 7;\n" +
  70 + " NestedJsonObject someNestedObject = 8;\n" +
  71 + " message NestedJsonObject {\n" +
  72 + " string key = 9;\n" +
  73 + " }\n" +
  74 + " }\n" +
  75 + "}";
51 76
52 @After 77 @After
53 public void afterTest() throws Exception { 78 public void afterTest() throws Exception {
@@ -56,21 +81,55 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends @@ -56,21 +81,55 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
56 81
57 @Test 82 @Test
58 public void testRequestAttributesValuesFromTheServer() throws Exception { 83 public void testRequestAttributesValuesFromTheServer() throws Exception {
  84 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
  85 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, DeviceProfileProvisionType.DISABLED, null, null);
59 processTestRequestAttributesValuesFromTheServer(); 86 processTestRequestAttributesValuesFromTheServer();
60 } 87 }
61 88
62 -  
63 @Test 89 @Test
64 public void testRequestAttributesValuesFromTheServerGateway() throws Exception { 90 public void testRequestAttributesValuesFromTheServerGateway() throws Exception {
  91 + super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null);
65 processTestGatewayRequestAttributesValuesFromTheServer(); 92 processTestGatewayRequestAttributesValuesFromTheServer();
66 } 93 }
67 94
68 protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception { 95 protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception {
69 doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); 96 doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
70 - String keys = "attribute1,attribute2,attribute3,attribute4,attribute5";  
71 - List<String> expectedKeys = Arrays.asList(keys.split(","));  
72 - TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys);  
73 - byte[] payload = postAttributeMsg.toByteArray(); 97 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  98 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  99 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  100 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  101 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  102 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  103 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(ATTRIBUTES_SCHEMA_STR);
  104 + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  105 +
  106 + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
  107 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  108 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  109 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  110 +
  111 + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
  112 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  113 + assertNotNull(jsonObjectBuilderDescriptor);
  114 + DynamicMessage jsonObject = jsonObjectBuilder
  115 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  116 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  117 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  118 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  119 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  120 + .build();
  121 +
  122 + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
  123 + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
  124 + assertNotNull(postAttributesMsgDescriptor);
  125 + DynamicMessage postAttributesMsg = postAttributesBuilder
  126 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute1"), "value1")
  127 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute2"), true)
  128 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute3"), 42.0)
  129 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute4"), 73)
  130 + .setField(postAttributesMsgDescriptor.findFieldByName("attribute5"), jsonObject)
  131 + .build();
  132 + byte[] payload = postAttributesMsg.toByteArray();
74 client.publish(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, new MqttMessage(payload)); 133 client.publish(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, new MqttMessage(payload));
75 client.subscribe(MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); 134 client.subscribe(MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttQoS.AT_MOST_ONCE.value());
76 } 135 }
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.request.sql; 16 package org.thingsboard.server.mqtt.attributes.request.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.request.sql; 16 package org.thingsboard.server.mqtt.attributes.request.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -18,11 +18,7 @@ package org.thingsboard.server.mqtt.attributes.updates; @@ -18,11 +18,7 @@ package org.thingsboard.server.mqtt.attributes.updates;
18 import com.google.protobuf.InvalidProtocolBufferException; 18 import com.google.protobuf.InvalidProtocolBufferException;
19 import io.netty.handler.codec.mqtt.MqttQoS; 19 import io.netty.handler.codec.mqtt.MqttQoS;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;  
22 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 21 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
23 -import org.eclipse.paho.client.mqttv3.MqttCallback;  
24 -import org.eclipse.paho.client.mqttv3.MqttException;  
25 -import org.eclipse.paho.client.mqttv3.MqttMessage;  
26 import org.junit.After; 22 import org.junit.After;
27 import org.junit.Before; 23 import org.junit.Before;
28 import org.junit.Test; 24 import org.junit.Test;
@@ -33,12 +29,10 @@ import org.thingsboard.server.dao.util.mapping.JacksonUtil; @@ -33,12 +29,10 @@ import org.thingsboard.server.dao.util.mapping.JacksonUtil;
33 import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest; 29 import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
34 30
35 import java.nio.charset.StandardCharsets; 31 import java.nio.charset.StandardCharsets;
36 -import java.util.concurrent.CountDownLatch;  
37 import java.util.concurrent.TimeUnit; 32 import java.util.concurrent.TimeUnit;
38 33
39 import static org.junit.Assert.assertEquals; 34 import static org.junit.Assert.assertEquals;
40 import static org.junit.Assert.assertNotNull; 35 import static org.junit.Assert.assertNotNull;
41 -import static org.junit.Assert.assertTrue;  
42 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 36 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
43 37
44 @Slf4j 38 @Slf4j
@@ -21,11 +21,6 @@ import org.junit.Before; @@ -21,11 +21,6 @@ import org.junit.Before;
21 import org.junit.Test; 21 import org.junit.Test;
22 import org.thingsboard.server.common.data.TransportPayloadType; 22 import org.thingsboard.server.common.data.TransportPayloadType;
23 23
24 -import static org.junit.Assert.assertEquals;  
25 -import static org.junit.Assert.assertFalse;  
26 -import static org.junit.Assert.assertNotNull;  
27 -import static org.junit.Assert.assertTrue;  
28 -  
29 @Slf4j 24 @Slf4j
30 public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { 25 public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest {
31 26
@@ -21,11 +21,9 @@ import org.junit.After; @@ -21,11 +21,9 @@ import org.junit.After;
21 import org.junit.Before; 21 import org.junit.Before;
22 import org.junit.Test; 22 import org.junit.Test;
23 import org.thingsboard.server.common.data.TransportPayloadType; 23 import org.thingsboard.server.common.data.TransportPayloadType;
24 -import org.thingsboard.server.common.data.device.profile.MqttTopics;  
25 import org.thingsboard.server.gen.transport.TransportApiProtos; 24 import org.thingsboard.server.gen.transport.TransportApiProtos;
26 import org.thingsboard.server.gen.transport.TransportProtos; 25 import org.thingsboard.server.gen.transport.TransportProtos;
27 26
28 -import java.nio.charset.StandardCharsets;  
29 import java.util.List; 27 import java.util.List;
30 import java.util.stream.Collectors; 28 import java.util.stream.Collectors;
31 29
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.updates.sql; 16 package org.thingsboard.server.mqtt.attributes.updates.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.attributes.updates.sql; 16 package org.thingsboard.server.mqtt.attributes.updates.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -20,7 +20,6 @@ import org.eclipse.paho.client.mqttv3.MqttAsyncClient; @@ -20,7 +20,6 @@ import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.eclipse.paho.client.mqttv3.MqttMessage; 20 import org.eclipse.paho.client.mqttv3.MqttMessage;
21 import org.junit.After; 21 import org.junit.After;
22 import org.junit.Before; 22 import org.junit.Before;
23 -import org.junit.Ignore;  
24 import org.junit.Test; 23 import org.junit.Test;
25 import org.thingsboard.server.common.data.ClaimRequest; 24 import org.thingsboard.server.common.data.ClaimRequest;
26 import org.thingsboard.server.common.data.Customer; 25 import org.thingsboard.server.common.data.Customer;
@@ -18,7 +18,6 @@ package org.thingsboard.server.mqtt.claim; @@ -18,7 +18,6 @@ package org.thingsboard.server.mqtt.claim;
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.junit.After; 19 import org.junit.After;
20 import org.junit.Before; 20 import org.junit.Before;
21 -import org.junit.Ignore;  
22 import org.junit.Test; 21 import org.junit.Test;
23 import org.thingsboard.server.common.data.TransportPayloadType; 22 import org.thingsboard.server.common.data.TransportPayloadType;
24 23
@@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 20 import org.junit.After;
21 import org.junit.Before; 21 import org.junit.Before;
22 -import org.junit.Ignore;  
23 import org.junit.Test; 22 import org.junit.Test;
24 import org.thingsboard.server.common.data.TransportPayloadType; 23 import org.thingsboard.server.common.data.TransportPayloadType;
25 import org.thingsboard.server.gen.transport.TransportApiProtos; 24 import org.thingsboard.server.gen.transport.TransportApiProtos;
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.claim.sql; 16 package org.thingsboard.server.mqtt.claim.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest;  
20 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest; 19 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.claim.sql; 16 package org.thingsboard.server.mqtt.claim.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest;  
20 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimProtoDeviceTest; 19 import org.thingsboard.server.mqtt.claim.AbstractMqttClaimProtoDeviceTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -94,34 +94,32 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -94,34 +94,32 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
94 94
95 95
96 protected void processTestProvisioningDisabledDevice() throws Exception { 96 protected void processTestProvisioningDisabledDevice() throws Exception {
97 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.DISABLED, null, null); 97 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
98 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 98 byte[] result = createMqttClientAndPublish().getPayloadBytes();
99 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 99 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
100 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); 100 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
101 - Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("provisionDeviceStatus").getAsString()); 101 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("status").getAsString());
102 } 102 }
103 103
104 104
105 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { 105 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
106 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 106 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
107 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 107 byte[] result = createMqttClientAndPublish().getPayloadBytes();
108 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 108 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
109 109
110 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 110 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
111 111
112 Assert.assertNotNull(createdDevice); 112 Assert.assertNotNull(createdDevice);
113 - Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString());  
114 113
115 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 114 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
116 115
117 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); 116 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
118 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString());  
119 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); 117 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
120 } 118 }
121 119
122 120
123 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { 121 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
124 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 122 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
125 String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\""; 123 String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
126 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); 124 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
127 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 125 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
@@ -129,20 +127,18 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -129,20 +127,18 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
129 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 127 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
130 128
131 Assert.assertNotNull(createdDevice); 129 Assert.assertNotNull(createdDevice);
132 - Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString());  
133 130
134 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 131 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
135 132
136 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); 133 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
137 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString());  
138 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "ACCESS_TOKEN"); 134 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "ACCESS_TOKEN");
139 Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token"); 135 Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token");
140 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); 136 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
141 } 137 }
142 138
143 139
144 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { 140 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
145 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 141 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
146 String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\""; 142 String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
147 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); 143 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
148 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 144 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
@@ -150,12 +146,10 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -150,12 +146,10 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
150 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 146 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
151 147
152 Assert.assertNotNull(createdDevice); 148 Assert.assertNotNull(createdDevice);
153 - Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString());  
154 149
155 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 150 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
156 151
157 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); 152 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
158 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString());  
159 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE"); 153 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE");
160 154
161 String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); 155 String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue());
@@ -164,12 +158,12 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -164,12 +158,12 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
164 Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); 158 Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash);
165 159
166 Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash"); 160 Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash");
167 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); 161 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
168 } 162 }
169 163
170 164
171 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { 165 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
172 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 166 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
173 String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\""; 167 String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\"";
174 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes(); 168 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
175 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 169 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
@@ -177,12 +171,10 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -177,12 +171,10 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
177 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 171 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
178 172
179 Assert.assertNotNull(createdDevice); 173 Assert.assertNotNull(createdDevice);
180 - Assert.assertEquals(createdDevice.getId().toString(), response.get("deviceId").getAsString());  
181 174
182 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 175 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
183 176
184 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); 177 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
185 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString());  
186 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "MQTT_BASIC"); 178 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "MQTT_BASIC");
187 Assert.assertEquals(deviceCredentials.getCredentialsId(), EncryptionUtil.getSha3Hash("|", "test_clientId", "test_username")); 179 Assert.assertEquals(deviceCredentials.getCredentialsId(), EncryptionUtil.getSha3Hash("|", "test_clientId", "test_username"));
188 180
@@ -192,29 +184,26 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn @@ -192,29 +184,26 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
192 mqttCredentials.setPassword("test_password"); 184 mqttCredentials.setPassword("test_password");
193 185
194 Assert.assertEquals(deviceCredentials.getCredentialsValue(), JacksonUtil.toString(mqttCredentials)); 186 Assert.assertEquals(deviceCredentials.getCredentialsValue(), JacksonUtil.toString(mqttCredentials));
195 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString());  
196 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); 187 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
197 } 188 }
198 189
199 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { 190 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
200 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret"); 191 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
201 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 192 byte[] result = createMqttClientAndPublish().getPayloadBytes();
202 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 193 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
203 - Assert.assertEquals(savedDevice.getId().toString(), response.get("deviceId").getAsString());  
204 194
205 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId()); 195 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
206 196
207 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); 197 Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
208 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.get("credentialsId").getAsString());  
209 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("provisionDeviceStatus").getAsString()); 198 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
210 } 199 }
211 200
212 protected void processTestProvisioningWithBadKeyDevice() throws Exception { 201 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
213 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret"); 202 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
214 byte[] result = createMqttClientAndPublish().getPayloadBytes(); 203 byte[] result = createMqttClientAndPublish().getPayloadBytes();
215 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); 204 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
216 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); 205 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
217 - Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("provisionDeviceStatus").getAsString()); 206 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.get("status").getAsString());
218 } 207 }
219 208
220 protected TestMqttCallback createMqttClientAndPublish() throws Exception { 209 protected TestMqttCallback createMqttClientAndPublish() throws Exception {
@@ -102,30 +102,28 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -102,30 +102,28 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
102 102
103 103
104 protected void processTestProvisioningDisabledDevice() throws Exception { 104 protected void processTestProvisioningDisabledDevice() throws Exception {
105 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.DISABLED, null, null); 105 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
106 ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 106 ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
107 Assert.assertNotNull(result); 107 Assert.assertNotNull(result);
108 - Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getProvisionResponseStatus().toString()); 108 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString());
109 } 109 }
110 110
111 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { 111 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
112 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 112 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
113 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 113 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
114 114
115 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 115 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
116 116
117 Assert.assertNotNull(createdDevice); 117 Assert.assertNotNull(createdDevice);
118 - Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB()));  
119 118
120 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 119 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
121 120
122 - Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString());  
123 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId());  
124 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); 121 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
  122 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
125 } 123 }
126 124
127 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { 125 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
128 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 126 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
129 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build(); 127 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
130 128
131 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes()); 129 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes());
@@ -133,19 +131,17 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -133,19 +131,17 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
133 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 131 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
134 132
135 Assert.assertNotNull(createdDevice); 133 Assert.assertNotNull(createdDevice);
136 - Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB()));  
137 134
138 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 135 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
139 136
140 - Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString());  
141 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); 137 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
142 Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.ACCESS_TOKEN); 138 Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.ACCESS_TOKEN);
143 Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token"); 139 Assert.assertEquals(deviceCredentials.getCredentialsId(), "test_token");
144 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); 140 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
145 } 141 }
146 142
147 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception { 143 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
148 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 144 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
149 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build(); 145 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
150 146
151 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes()); 147 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes());
@@ -153,12 +149,10 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -153,12 +149,10 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
153 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 149 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
154 150
155 Assert.assertNotNull(createdDevice); 151 Assert.assertNotNull(createdDevice);
156 - Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB()));  
157 152
158 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 153 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
159 154
160 - Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString());  
161 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); 155 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
162 Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE); 156 Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE);
163 157
164 String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue()); 158 String cert = EncryptionUtil.trimNewLines(deviceCredentials.getCredentialsValue());
@@ -167,11 +161,11 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -167,11 +161,11 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
167 Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash); 161 Assert.assertEquals(deviceCredentials.getCredentialsId(), sha3Hash);
168 162
169 Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash"); 163 Assert.assertEquals(deviceCredentials.getCredentialsValue(), "testHash");
170 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); 164 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
171 } 165 }
172 166
173 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception { 167 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
174 - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret"); 168 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
175 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg( 169 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg(
176 ValidateBasicMqttCredRequestMsg.newBuilder() 170 ValidateBasicMqttCredRequestMsg.newBuilder()
177 .setClientId("test_clientId") 171 .setClientId("test_clientId")
@@ -185,12 +179,10 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -185,12 +179,10 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
185 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); 179 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
186 180
187 Assert.assertNotNull(createdDevice); 181 Assert.assertNotNull(createdDevice);
188 - Assert.assertEquals(createdDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB()));  
189 182
190 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); 183 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId());
191 184
192 - Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString());  
193 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId()); 185 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
194 Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.MQTT_BASIC); 186 Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.MQTT_BASIC);
195 Assert.assertEquals(deviceCredentials.getCredentialsId(), EncryptionUtil.getSha3Hash("|", "test_clientId", "test_username")); 187 Assert.assertEquals(deviceCredentials.getCredentialsId(), EncryptionUtil.getSha3Hash("|", "test_clientId", "test_username"));
196 188
@@ -200,26 +192,23 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI @@ -200,26 +192,23 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
200 mqttCredentials.setPassword("test_password"); 192 mqttCredentials.setPassword("test_password");
201 193
202 Assert.assertEquals(deviceCredentials.getCredentialsValue(), JacksonUtil.toString(mqttCredentials)); 194 Assert.assertEquals(deviceCredentials.getCredentialsValue(), JacksonUtil.toString(mqttCredentials));
203 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId());  
204 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); 195 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
205 } 196 }
206 197
207 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception { 198 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
208 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret"); 199 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
209 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 200 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
210 - Assert.assertEquals(savedDevice.getId().getId(), new UUID(response.getDeviceCredentials().getDeviceIdMSB(), response.getDeviceCredentials().getDeviceIdLSB()));  
211 201
212 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId()); 202 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
213 203
214 - Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getDeviceCredentials().getCredentialsType().toString());  
215 - Assert.assertEquals(deviceCredentials.getCredentialsId(), response.getDeviceCredentials().getCredentialsId());  
216 - Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getProvisionResponseStatus().toString()); 204 + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
  205 + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
217 } 206 }
218 207
219 protected void processTestProvisioningWithBadKeyDevice() throws Exception { 208 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
220 - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret"); 209 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
221 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes()); 210 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
222 - Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getProvisionResponseStatus().toString()); 211 + Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString());
223 } 212 }
224 213
225 protected TestMqttCallback createMqttClientAndPublish() throws Exception { 214 protected TestMqttCallback createMqttClientAndPublish() throws Exception {
@@ -15,49 +15,14 @@ @@ -15,49 +15,14 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.rpc; 16 package org.thingsboard.server.mqtt.rpc;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 -import com.fasterxml.jackson.databind.node.ObjectNode;  
20 -import com.google.protobuf.InvalidProtocolBufferException;  
21 -import com.nimbusds.jose.util.StandardCharset;  
22 import com.datastax.oss.driver.api.core.uuid.Uuids; 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
23 -import io.netty.handler.codec.mqtt.MqttQoS;  
24 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
25 -import org.apache.commons.lang3.StringUtils;  
26 -import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;  
27 -import org.eclipse.paho.client.mqttv3.MqttAsyncClient;  
28 -import org.eclipse.paho.client.mqttv3.MqttCallback;  
29 -import org.eclipse.paho.client.mqttv3.MqttConnectOptions;  
30 -import org.eclipse.paho.client.mqttv3.MqttException;  
31 -import org.eclipse.paho.client.mqttv3.MqttMessage;  
32 import org.junit.After; 20 import org.junit.After;
33 import org.junit.Assert; 21 import org.junit.Assert;
34 import org.junit.Before; 22 import org.junit.Before;
35 -import org.junit.Ignore;  
36 import org.junit.Test; 23 import org.junit.Test;
37 -import org.thingsboard.server.common.data.Device;  
38 -import org.thingsboard.server.common.data.DeviceProfile;  
39 -import org.thingsboard.server.common.data.DeviceProfileType;  
40 -import org.thingsboard.server.common.data.DeviceTransportType;  
41 -import org.thingsboard.server.common.data.Tenant;  
42 -import org.thingsboard.server.common.data.TransportPayloadType;  
43 -import org.thingsboard.server.common.data.User;  
44 -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;  
45 -import org.thingsboard.server.common.data.device.profile.DeviceProfileData;  
46 -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;  
47 -import org.thingsboard.server.common.data.device.profile.MqttTopics;  
48 -import org.thingsboard.server.common.data.security.Authority;  
49 -import org.thingsboard.server.common.data.security.DeviceCredentials;  
50 -import org.thingsboard.server.controller.AbstractControllerTest;  
51 -import org.thingsboard.server.dao.util.mapping.JacksonUtil;  
52 import org.thingsboard.server.service.security.AccessValidator; 24 import org.thingsboard.server.service.security.AccessValidator;
53 25
54 -import java.util.Arrays;  
55 -import java.util.concurrent.CountDownLatch;  
56 -import java.util.concurrent.TimeUnit;  
57 -import java.util.concurrent.atomic.AtomicInteger;  
58 -  
59 -import static org.junit.Assert.assertEquals;  
60 -import static org.junit.Assert.assertNotNull;  
61 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 26 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
62 27
63 /** 28 /**
@@ -15,9 +15,7 @@ @@ -15,9 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.rpc; 16 package org.thingsboard.server.mqtt.rpc;
17 17
18 -import com.datastax.oss.driver.api.core.uuid.Uuids;  
19 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
20 -import com.fasterxml.jackson.databind.node.ObjectNode;  
21 import com.google.protobuf.InvalidProtocolBufferException; 19 import com.google.protobuf.InvalidProtocolBufferException;
22 import com.nimbusds.jose.util.StandardCharset; 20 import com.nimbusds.jose.util.StandardCharset;
23 import io.netty.handler.codec.mqtt.MqttQoS; 21 import io.netty.handler.codec.mqtt.MqttQoS;
@@ -26,35 +24,18 @@ import org.apache.commons.lang3.StringUtils; @@ -26,35 +24,18 @@ import org.apache.commons.lang3.StringUtils;
26 import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; 24 import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
27 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 25 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
28 import org.eclipse.paho.client.mqttv3.MqttCallback; 26 import org.eclipse.paho.client.mqttv3.MqttCallback;
29 -import org.eclipse.paho.client.mqttv3.MqttConnectOptions;  
30 import org.eclipse.paho.client.mqttv3.MqttException; 27 import org.eclipse.paho.client.mqttv3.MqttException;
31 import org.eclipse.paho.client.mqttv3.MqttMessage; 28 import org.eclipse.paho.client.mqttv3.MqttMessage;
32 -import org.junit.After;  
33 import org.junit.Assert; 29 import org.junit.Assert;
34 -import org.junit.Before;  
35 -import org.junit.Test;  
36 import org.thingsboard.server.common.data.Device; 30 import org.thingsboard.server.common.data.Device;
37 -import org.thingsboard.server.common.data.DeviceProfile;  
38 -import org.thingsboard.server.common.data.DeviceProfileType;  
39 -import org.thingsboard.server.common.data.DeviceTransportType;  
40 -import org.thingsboard.server.common.data.Tenant;  
41 import org.thingsboard.server.common.data.TransportPayloadType; 31 import org.thingsboard.server.common.data.TransportPayloadType;
42 -import org.thingsboard.server.common.data.User;  
43 -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;  
44 -import org.thingsboard.server.common.data.device.profile.DeviceProfileData;  
45 -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;  
46 import org.thingsboard.server.common.data.device.profile.MqttTopics; 32 import org.thingsboard.server.common.data.device.profile.MqttTopics;
47 -import org.thingsboard.server.common.data.security.Authority;  
48 -import org.thingsboard.server.common.data.security.DeviceCredentials;  
49 -import org.thingsboard.server.controller.AbstractControllerTest;  
50 import org.thingsboard.server.dao.util.mapping.JacksonUtil; 33 import org.thingsboard.server.dao.util.mapping.JacksonUtil;
51 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; 34 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
52 -import org.thingsboard.server.service.security.AccessValidator;  
53 35
54 import java.util.Arrays; 36 import java.util.Arrays;
55 import java.util.concurrent.CountDownLatch; 37 import java.util.concurrent.CountDownLatch;
56 import java.util.concurrent.TimeUnit; 38 import java.util.concurrent.TimeUnit;
57 -import java.util.concurrent.atomic.AtomicInteger;  
58 39
59 import static org.junit.Assert.assertEquals; 40 import static org.junit.Assert.assertEquals;
60 import static org.junit.Assert.assertNotNull; 41 import static org.junit.Assert.assertNotNull;
@@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 20 import org.junit.After;
21 import org.junit.Before; 21 import org.junit.Before;
22 -import org.junit.Ignore;  
23 import org.junit.Test; 22 import org.junit.Test;
24 import org.thingsboard.server.common.data.TransportPayloadType; 23 import org.thingsboard.server.common.data.TransportPayloadType;
25 24
@@ -22,16 +22,12 @@ import org.eclipse.paho.client.mqttv3.MqttException; @@ -22,16 +22,12 @@ import org.eclipse.paho.client.mqttv3.MqttException;
22 import org.eclipse.paho.client.mqttv3.MqttMessage; 22 import org.eclipse.paho.client.mqttv3.MqttMessage;
23 import org.junit.After; 23 import org.junit.After;
24 import org.junit.Before; 24 import org.junit.Before;
25 -import org.junit.Ignore;  
26 import org.junit.Test; 25 import org.junit.Test;
27 import org.thingsboard.server.common.data.TransportPayloadType; 26 import org.thingsboard.server.common.data.TransportPayloadType;
28 import org.thingsboard.server.common.data.device.profile.MqttTopics; 27 import org.thingsboard.server.common.data.device.profile.MqttTopics;
29 import org.thingsboard.server.gen.transport.TransportApiProtos; 28 import org.thingsboard.server.gen.transport.TransportApiProtos;
30 import org.thingsboard.server.gen.transport.TransportProtos; 29 import org.thingsboard.server.gen.transport.TransportProtos;
31 30
32 -import static org.junit.Assert.assertEquals;  
33 -import static org.junit.Assert.assertNotNull;  
34 -  
35 @Slf4j 31 @Slf4j
36 public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest { 32 public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest {
37 33
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.telemetry.attributes; 16 package org.thingsboard.server.mqtt.telemetry.attributes;
17 17
  18 +import com.fasterxml.jackson.core.JsonProcessingException;
18 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 20 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 21 import org.junit.After;
@@ -142,7 +143,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt @@ -142,7 +143,7 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt
142 143
143 } 144 }
144 145
145 - protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) { 146 + protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) throws JsonProcessingException {
146 for (Map<String, Object> map : deviceValues) { 147 for (Map<String, Object> map : deviceValues) {
147 String key = (String) map.get("key"); 148 String key = (String) map.get("key");
148 Object value = map.get("value"); 149 Object value = map.get("value");
@@ -15,18 +15,24 @@ @@ -15,18 +15,24 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.telemetry.attributes; 16 package org.thingsboard.server.mqtt.telemetry.attributes;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
18 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
19 import org.junit.After; 23 import org.junit.After;
20 -import org.junit.Before;  
21 import org.junit.Test; 24 import org.junit.Test;
22 import org.thingsboard.server.common.data.TransportPayloadType; 25 import org.thingsboard.server.common.data.TransportPayloadType;
  26 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  27 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  28 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  29 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
23 import org.thingsboard.server.gen.transport.TransportApiProtos; 30 import org.thingsboard.server.gen.transport.TransportApiProtos;
24 import org.thingsboard.server.gen.transport.TransportProtos; 31 import org.thingsboard.server.gen.transport.TransportProtos;
25 32
26 import java.util.Arrays; 33 import java.util.Arrays;
27 import java.util.List; 34 import java.util.List;
28 35
29 -import static org.junit.Assert.assertEquals;  
30 import static org.junit.Assert.assertNotNull; 36 import static org.junit.Assert.assertNotNull;
31 import static org.junit.Assert.assertTrue; 37 import static org.junit.Assert.assertTrue;
32 38
@@ -35,11 +41,6 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac @@ -35,11 +41,6 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac
35 41
36 private static final String POST_DATA_ATTRIBUTES_TOPIC = "proto/attributes"; 42 private static final String POST_DATA_ATTRIBUTES_TOPIC = "proto/attributes";
37 43
38 - @Before  
39 - public void beforeTest() throws Exception {  
40 - processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC);  
41 - }  
42 -  
43 @After 44 @After
44 public void afterTest() throws Exception { 45 public void afterTest() throws Exception {
45 processAfterTest(); 46 processAfterTest();
@@ -47,13 +48,49 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac @@ -47,13 +48,49 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac
47 48
48 @Test 49 @Test
49 public void testPushMqttAttributes() throws Exception { 50 public void testPushMqttAttributes() throws Exception {
  51 + super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC);
50 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 52 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
51 - TransportProtos.PostAttributeMsg msg = getPostAttributeMsg(expectedKeys);  
52 - processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, msg.toByteArray()); 53 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  54 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  55 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  56 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  57 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  58 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  59 + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_ATTRIBUTES_PROTO_SCHEMA);
  60 + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA);
  61 +
  62 + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject");
  63 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  64 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  65 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  66 +
  67 + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject");
  68 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  69 + assertNotNull(jsonObjectBuilderDescriptor);
  70 + DynamicMessage jsonObject = jsonObjectBuilder
  71 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  72 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  73 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  74 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  75 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  76 + .build();
  77 +
  78 + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes");
  79 + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType();
  80 + assertNotNull(postAttributesMsgDescriptor);
  81 + DynamicMessage postAttributesMsg = postAttributesBuilder
  82 + .setField(postAttributesMsgDescriptor.findFieldByName("key1"), "value1")
  83 + .setField(postAttributesMsgDescriptor.findFieldByName("key2"), true)
  84 + .setField(postAttributesMsgDescriptor.findFieldByName("key3"), 3.0)
  85 + .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4)
  86 + .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject)
  87 + .build();
  88 + processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, postAttributesMsg.toByteArray());
53 } 89 }
54 90
55 @Test 91 @Test
56 public void testPushMqttAttributesGateway() throws Exception { 92 public void testPushMqttAttributesGateway() throws Exception {
  93 + super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, null);
57 TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); 94 TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder();
58 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 95 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
59 String deviceName1 = "Device A"; 96 String deviceName1 = "Device A";
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql; 16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
17 17
18 import org.thingsboard.server.dao.service.DaoNoSqlTest; 18 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;
21 20
22 @DaoNoSqlTest 21 @DaoNoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql; 16 package org.thingsboard.server.mqtt.telemetry.attributes.nosql;
17 17
18 import org.thingsboard.server.dao.service.DaoNoSqlTest; 18 import org.thingsboard.server.dao.service.DaoNoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
21 20
22 @DaoNoSqlTest 21 @DaoNoSqlTest
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.attributes.sql; 16 package org.thingsboard.server.mqtt.telemetry.attributes.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest;
21 20
22 @DaoSqlTest 21 @DaoSqlTest
@@ -27,7 +27,6 @@ import org.junit.After; @@ -27,7 +27,6 @@ import org.junit.After;
27 import org.junit.Before; 27 import org.junit.Before;
28 import org.junit.Test; 28 import org.junit.Test;
29 import org.thingsboard.server.common.data.Device; 29 import org.thingsboard.server.common.data.Device;
30 -import org.thingsboard.server.common.data.TransportPayloadType;  
31 import org.thingsboard.server.common.data.device.profile.MqttTopics; 30 import org.thingsboard.server.common.data.device.profile.MqttTopics;
32 import org.thingsboard.server.common.data.id.DeviceId; 31 import org.thingsboard.server.common.data.id.DeviceId;
33 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; 32 import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest;
@@ -128,7 +127,34 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt @@ -128,7 +127,34 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt
128 } else { 127 } else {
129 getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet); 128 getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet);
130 } 129 }
131 - Map<String, List<Map<String, String>>> values = doGetAsync(getTelemetryValuesUrl, Map.class); 130 + start = System.currentTimeMillis();
  131 + end = System.currentTimeMillis() + 5000;
  132 + Map<String, List<Map<String, String>>> values = null;
  133 + while (start <= end) {
  134 + values = doGetAsync(getTelemetryValuesUrl, Map.class);
  135 + boolean valid = values.size() == expectedKeys.size();
  136 + if (valid) {
  137 + for (String key : expectedKeys) {
  138 + List<Map<String, String>> tsValues = values.get(key);
  139 + if (tsValues != null && tsValues.size() > 0) {
  140 + Object ts = tsValues.get(0).get("ts");
  141 + if (ts == null) {
  142 + valid = false;
  143 + break;
  144 + }
  145 + } else {
  146 + valid = false;
  147 + break;
  148 + }
  149 + }
  150 + }
  151 + if (valid) {
  152 + break;
  153 + }
  154 + Thread.sleep(100);
  155 + start += 100;
  156 + }
  157 + assertNotNull(values);
132 158
133 if (withTs) { 159 if (withTs) {
134 assertTs(values, expectedKeys, 10000, 0); 160 assertTs(values, expectedKeys, 10000, 0);
@@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics; @@ -27,7 +27,6 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
27 import java.util.Arrays; 27 import java.util.Arrays;
28 import java.util.List; 28 import java.util.List;
29 29
30 -import static org.junit.Assert.assertEquals;  
31 import static org.junit.Assert.assertNotNull; 30 import static org.junit.Assert.assertNotNull;
32 31
33 @Slf4j 32 @Slf4j
@@ -15,33 +15,36 @@ @@ -15,33 +15,36 @@
15 */ 15 */
16 package org.thingsboard.server.mqtt.telemetry.timeseries; 16 package org.thingsboard.server.mqtt.telemetry.timeseries;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
18 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
19 import org.eclipse.paho.client.mqttv3.MqttAsyncClient; 23 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
20 import org.junit.After; 24 import org.junit.After;
21 -import org.junit.Before;  
22 import org.junit.Test; 25 import org.junit.Test;
23 import org.thingsboard.server.common.data.Device; 26 import org.thingsboard.server.common.data.Device;
  27 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
24 import org.thingsboard.server.common.data.TransportPayloadType; 28 import org.thingsboard.server.common.data.TransportPayloadType;
  29 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  30 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
  31 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
25 import org.thingsboard.server.common.data.device.profile.MqttTopics; 32 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  33 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
26 import org.thingsboard.server.gen.transport.TransportApiProtos; 34 import org.thingsboard.server.gen.transport.TransportApiProtos;
27 import org.thingsboard.server.gen.transport.TransportProtos; 35 import org.thingsboard.server.gen.transport.TransportProtos;
28 36
29 import java.util.Arrays; 37 import java.util.Arrays;
30 import java.util.List; 38 import java.util.List;
31 39
32 -import static org.junit.Assert.assertEquals;  
33 import static org.junit.Assert.assertNotNull; 40 import static org.junit.Assert.assertNotNull;
  41 +import static org.junit.Assert.assertTrue;
34 42
35 @Slf4j 43 @Slf4j
36 public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends AbstractMqttTimeseriesIntegrationTest { 44 public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends AbstractMqttTimeseriesIntegrationTest {
37 45
38 private static final String POST_DATA_TELEMETRY_TOPIC = "proto/telemetry"; 46 private static final String POST_DATA_TELEMETRY_TOPIC = "proto/telemetry";
39 47
40 - @Before  
41 - public void beforeTest() throws Exception {  
42 - processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null);  
43 - }  
44 -  
45 @After 48 @After
46 public void afterTest() throws Exception { 49 public void afterTest() throws Exception {
47 processAfterTest(); 50 processAfterTest();
@@ -49,20 +52,127 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @@ -49,20 +52,127 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
49 52
50 @Test 53 @Test
51 public void testPushMqttTelemetry() throws Exception { 54 public void testPushMqttTelemetry() throws Exception {
  55 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null);
52 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 56 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
53 - TransportProtos.TsKvListProto tsKvListProto = getTsKvListProto(expectedKeys, 0);  
54 - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, tsKvListProto.toByteArray(), false); 57 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  58 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  59 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  60 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  61 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  62 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  63 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_TELEMETRY_PROTO_SCHEMA);
  64 + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
  65 +
  66 + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
  67 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  68 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  69 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  70 +
  71 + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
  72 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  73 + assertNotNull(jsonObjectBuilderDescriptor);
  74 + DynamicMessage jsonObject = jsonObjectBuilder
  75 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  76 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  77 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  78 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  79 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  80 + .build();
  81 +
  82 + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
  83 + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
  84 + assertNotNull(postTelemetryMsgDescriptor);
  85 + DynamicMessage postTelemetryMsg = postTelemetryBuilder
  86 + .setField(postTelemetryMsgDescriptor.findFieldByName("key1"), "value1")
  87 + .setField(postTelemetryMsgDescriptor.findFieldByName("key2"), true)
  88 + .setField(postTelemetryMsgDescriptor.findFieldByName("key3"), 3.0)
  89 + .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4)
  90 + .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject)
  91 + .build();
  92 + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, postTelemetryMsg.toByteArray(), false);
55 } 93 }
56 94
57 @Test 95 @Test
58 public void testPushMqttTelemetryWithTs() throws Exception { 96 public void testPushMqttTelemetryWithTs() throws Exception {
  97 + String schemaStr = "syntax =\"proto3\";\n" +
  98 + "\n" +
  99 + "package test;\n" +
  100 + "\n" +
  101 + "message PostTelemetry {\n" +
  102 + " int64 ts = 1;\n" +
  103 + " Values values = 2;\n" +
  104 + " \n" +
  105 + " message Values {\n" +
  106 + " string key1 = 3;\n" +
  107 + " bool key2 = 4;\n" +
  108 + " double key3 = 5;\n" +
  109 + " int32 key4 = 6;\n" +
  110 + " JsonObject key5 = 7;\n" +
  111 + " }\n" +
  112 + " \n" +
  113 + " message JsonObject {\n" +
  114 + " int32 someNumber = 8;\n" +
  115 + " repeated int32 someArray = 9;\n" +
  116 + " NestedJsonObject someNestedObject = 10;\n" +
  117 + " message NestedJsonObject {\n" +
  118 + " string key = 11;\n" +
  119 + " }\n" +
  120 + " }\n" +
  121 + "}";
  122 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, DeviceProfileProvisionType.DISABLED, null, null);
59 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 123 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
60 - TransportProtos.TsKvListProto tsKvListProto = getTsKvListProto(expectedKeys, 10000);  
61 - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, tsKvListProto.toByteArray(), true); 124 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  125 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  126 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  127 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  128 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  129 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  130 + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(schemaStr);
  131 + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema");
  132 +
  133 + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject");
  134 + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType();
  135 + assertNotNull(nestedJsonObjectBuilderDescriptor);
  136 + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build();
  137 +
  138 + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject");
  139 + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType();
  140 + assertNotNull(jsonObjectBuilderDescriptor);
  141 + DynamicMessage jsonObject = jsonObjectBuilder
  142 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNumber"), 42)
  143 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1)
  144 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2)
  145 + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3)
  146 + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject)
  147 + .build();
  148 +
  149 +
  150 + DynamicMessage.Builder valuesBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.Values");
  151 + Descriptors.Descriptor valuesDescriptor = valuesBuilder.getDescriptorForType();
  152 + assertNotNull(valuesDescriptor);
  153 +
  154 + DynamicMessage valuesMsg = valuesBuilder
  155 + .setField(valuesDescriptor.findFieldByName("key1"), "value1")
  156 + .setField(valuesDescriptor.findFieldByName("key2"), true)
  157 + .setField(valuesDescriptor.findFieldByName("key3"), 3.0)
  158 + .setField(valuesDescriptor.findFieldByName("key4"), 4)
  159 + .setField(valuesDescriptor.findFieldByName("key5"), jsonObject)
  160 + .build();
  161 +
  162 + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry");
  163 + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType();
  164 + assertNotNull(postTelemetryMsgDescriptor);
  165 + DynamicMessage postTelemetryMsg = postTelemetryBuilder
  166 + .setField(postTelemetryMsgDescriptor.findFieldByName("ts"), 10000L)
  167 + .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg)
  168 + .build();
  169 +
  170 + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, postTelemetryMsg.toByteArray(), true);
62 } 171 }
63 172
64 @Test 173 @Test
65 public void testPushMqttTelemetryGateway() throws Exception { 174 public void testPushMqttTelemetryGateway() throws Exception {
  175 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
66 TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder(); 176 TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder();
67 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); 177 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
68 String deviceName1 = "Device A"; 178 String deviceName1 = "Device A";
@@ -76,6 +186,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac @@ -76,6 +186,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
76 186
77 @Test 187 @Test
78 public void testGatewayConnect() throws Exception { 188 public void testGatewayConnect() throws Exception {
  189 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
79 String deviceName = "Device A"; 190 String deviceName = "Device A";
80 TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); 191 TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
81 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); 192 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql; 16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
21 20
22 /** 21 /**
@@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql; 16 package org.thingsboard.server.mqtt.telemetry.timeseries.sql;
17 17
18 import org.thingsboard.server.dao.service.DaoSqlTest; 18 import org.thingsboard.server.dao.service.DaoSqlTest;
19 -import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;  
20 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; 19 import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
21 20
22 /** 21 /**
@@ -71,6 +71,14 @@ @@ -71,6 +71,14 @@
71 <artifactId>java-driver-core</artifactId> 71 <artifactId>java-driver-core</artifactId>
72 <scope>test</scope> 72 <scope>test</scope>
73 </dependency> 73 </dependency>
  74 + <dependency>
  75 + <groupId>com.squareup.wire</groupId>
  76 + <artifactId>wire-schema</artifactId>
  77 + </dependency>
  78 + <dependency>
  79 + <groupId>org.thingsboard</groupId>
  80 + <artifactId>protobuf-dynamic</artifactId>
  81 + </dependency>
74 </dependencies> 82 </dependencies>
75 83
76 <build> 84 <build>
@@ -18,16 +18,21 @@ package org.thingsboard.server.common.data; @@ -18,16 +18,21 @@ package org.thingsboard.server.common.data;
18 import lombok.Getter; 18 import lombok.Getter;
19 19
20 public enum ApiFeature { 20 public enum ApiFeature {
21 - TRANSPORT("transportApiState"),  
22 - DB("dbApiState"),  
23 - RE("ruleEngineApiState"),  
24 - JS("jsExecutionApiState"); 21 + TRANSPORT("transportApiState", "Device API"),
  22 + DB("dbApiState", "Telemetry persistence"),
  23 + RE("ruleEngineApiState", "Rule Engine execution"),
  24 + JS("jsExecutionApiState", "JavaScript functions execution"),
  25 + EMAIL("emailApiState", "Email messages"),
  26 + SMS("smsApiState", "SMS messages");
25 27
26 @Getter 28 @Getter
27 private final String apiStateKey; 29 private final String apiStateKey;
  30 + @Getter
  31 + private final String label;
28 32
29 - ApiFeature(String apiStateKey) { 33 + ApiFeature(String apiStateKey, String label) {
30 this.apiStateKey = apiStateKey; 34 this.apiStateKey = apiStateKey;
  35 + this.label = label;
31 } 36 }
32 37
33 } 38 }
@@ -23,11 +23,15 @@ public enum ApiUsageRecordKey { @@ -23,11 +23,15 @@ public enum ApiUsageRecordKey {
23 TRANSPORT_DP_COUNT(ApiFeature.TRANSPORT, "transportDataPointsCount", "transportDataPointsLimit"), 23 TRANSPORT_DP_COUNT(ApiFeature.TRANSPORT, "transportDataPointsCount", "transportDataPointsLimit"),
24 STORAGE_DP_COUNT(ApiFeature.DB, "storageDataPointsCount", "storageDataPointsLimit"), 24 STORAGE_DP_COUNT(ApiFeature.DB, "storageDataPointsCount", "storageDataPointsLimit"),
25 RE_EXEC_COUNT(ApiFeature.RE, "ruleEngineExecutionCount", "ruleEngineExecutionLimit"), 25 RE_EXEC_COUNT(ApiFeature.RE, "ruleEngineExecutionCount", "ruleEngineExecutionLimit"),
26 - JS_EXEC_COUNT(ApiFeature.JS, "jsExecutionCount", "jsExecutionLimit"); 26 + JS_EXEC_COUNT(ApiFeature.JS, "jsExecutionCount", "jsExecutionLimit"),
  27 + EMAIL_EXEC_COUNT(ApiFeature.EMAIL, "emailCount", "emailLimit"),
  28 + SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit");
27 private static final ApiUsageRecordKey[] JS_RECORD_KEYS = {JS_EXEC_COUNT}; 29 private static final ApiUsageRecordKey[] JS_RECORD_KEYS = {JS_EXEC_COUNT};
28 private static final ApiUsageRecordKey[] RE_RECORD_KEYS = {RE_EXEC_COUNT}; 30 private static final ApiUsageRecordKey[] RE_RECORD_KEYS = {RE_EXEC_COUNT};
29 private static final ApiUsageRecordKey[] DB_RECORD_KEYS = {STORAGE_DP_COUNT}; 31 private static final ApiUsageRecordKey[] DB_RECORD_KEYS = {STORAGE_DP_COUNT};
30 private static final ApiUsageRecordKey[] TRANSPORT_RECORD_KEYS = {TRANSPORT_MSG_COUNT, TRANSPORT_DP_COUNT}; 32 private static final ApiUsageRecordKey[] TRANSPORT_RECORD_KEYS = {TRANSPORT_MSG_COUNT, TRANSPORT_DP_COUNT};
  33 + private static final ApiUsageRecordKey[] EMAIL_RECORD_KEYS = {EMAIL_EXEC_COUNT};
  34 + private static final ApiUsageRecordKey[] SMS_RECORD_KEYS = {SMS_EXEC_COUNT};
31 35
32 @Getter 36 @Getter
33 private final ApiFeature apiFeature; 37 private final ApiFeature apiFeature;
@@ -52,6 +56,10 @@ public enum ApiUsageRecordKey { @@ -52,6 +56,10 @@ public enum ApiUsageRecordKey {
52 return RE_RECORD_KEYS; 56 return RE_RECORD_KEYS;
53 case JS: 57 case JS:
54 return JS_RECORD_KEYS; 58 return JS_RECORD_KEYS;
  59 + case EMAIL:
  60 + return EMAIL_RECORD_KEYS;
  61 + case SMS:
  62 + return SMS_RECORD_KEYS;
55 default: 63 default:
56 return new ApiUsageRecordKey[]{}; 64 return new ApiUsageRecordKey[]{};
57 } 65 }
@@ -47,6 +47,12 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan @@ -47,6 +47,12 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan
47 @Getter 47 @Getter
48 @Setter 48 @Setter
49 private ApiUsageStateValue jsExecState; 49 private ApiUsageStateValue jsExecState;
  50 + @Getter
  51 + @Setter
  52 + private ApiUsageStateValue emailExecState;
  53 + @Getter
  54 + @Setter
  55 + private ApiUsageStateValue smsExecState;
50 56
51 public ApiUsageState() { 57 public ApiUsageState() {
52 super(); 58 super();
@@ -64,6 +70,8 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan @@ -64,6 +70,8 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan
64 this.dbStorageState = ur.getDbStorageState(); 70 this.dbStorageState = ur.getDbStorageState();
65 this.reExecState = ur.getReExecState(); 71 this.reExecState = ur.getReExecState();
66 this.jsExecState = ur.getJsExecState(); 72 this.jsExecState = ur.getJsExecState();
  73 + this.emailExecState = ur.getEmailExecState();
  74 + this.smsExecState = ur.getSmsExecState();
67 } 75 }
68 76
69 public boolean isTransportEnabled() { 77 public boolean isTransportEnabled() {
@@ -81,4 +89,12 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan @@ -81,4 +89,12 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan
81 public boolean isJsExecEnabled() { 89 public boolean isJsExecEnabled() {
82 return !ApiUsageStateValue.DISABLED.equals(jsExecState); 90 return !ApiUsageStateValue.DISABLED.equals(jsExecState);
83 } 91 }
  92 +
  93 + public boolean isEmailSendEnabled(){
  94 + return !ApiUsageStateValue.DISABLED.equals(emailExecState);
  95 + }
  96 +
  97 + public boolean isSmsSendEnabled(){
  98 + return !ApiUsageStateValue.DISABLED.equals(smsExecState);
  99 + }
84 } 100 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class ApiUsageStateMailMessage {
  22 + private final ApiUsageRecordKey key;
  23 + private final long threshold;
  24 + private final long value;
  25 +}
@@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.DeviceTransportType; @@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.DeviceTransportType;
29 property = "type") 29 property = "type")
30 @JsonSubTypes({ 30 @JsonSubTypes({
31 @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"), 31 @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"),
32 - @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"), 32 + @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"),
33 @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M")}) 33 @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M")})
34 public interface DeviceProfileTransportConfiguration { 34 public interface DeviceProfileTransportConfiguration {
35 35
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.device.profile;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.TransportPayloadType;
  20 +
  21 +@Data
  22 +public class JsonTransportPayloadConfiguration implements TransportPayloadTypeConfiguration {
  23 +
  24 + @Override
  25 + public TransportPayloadType getTransportPayloadType() {
  26 + return TransportPayloadType.JSON;
  27 + }
  28 +}
@@ -16,20 +16,27 @@ @@ -16,20 +16,27 @@
16 package org.thingsboard.server.common.data.device.profile; 16 package org.thingsboard.server.common.data.device.profile;
17 17
18 import lombok.Data; 18 import lombok.Data;
19 -import org.thingsboard.server.common.data.TransportPayloadType;  
20 import org.thingsboard.server.common.data.DeviceTransportType; 19 import org.thingsboard.server.common.data.DeviceTransportType;
21 20
22 @Data 21 @Data
23 public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { 22 public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
24 23
25 - private TransportPayloadType transportPayloadType = TransportPayloadType.JSON;  
26 -  
27 private String deviceTelemetryTopic = MqttTopics.DEVICE_TELEMETRY_TOPIC; 24 private String deviceTelemetryTopic = MqttTopics.DEVICE_TELEMETRY_TOPIC;
28 private String deviceAttributesTopic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC; 25 private String deviceAttributesTopic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC;
  26 + private TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
29 27
30 @Override 28 @Override
31 public DeviceTransportType getType() { 29 public DeviceTransportType getType() {
32 return DeviceTransportType.MQTT; 30 return DeviceTransportType.MQTT;
33 } 31 }
34 32
  33 + public TransportPayloadTypeConfiguration getTransportPayloadTypeConfiguration() {
  34 + if (transportPayloadTypeConfiguration != null) {
  35 + return transportPayloadTypeConfiguration;
  36 + } else {
  37 + return new JsonTransportPayloadConfiguration();
  38 + }
  39 + }
  40 +
  41 +
35 } 42 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.device.profile;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  20 +import com.github.os72.protobuf.dynamic.EnumDefinition;
  21 +import com.github.os72.protobuf.dynamic.MessageDefinition;
  22 +import com.google.protobuf.Descriptors;
  23 +import com.google.protobuf.DynamicMessage;
  24 +import com.squareup.wire.schema.Location;
  25 +import com.squareup.wire.schema.internal.parser.EnumConstantElement;
  26 +import com.squareup.wire.schema.internal.parser.EnumElement;
  27 +import com.squareup.wire.schema.internal.parser.FieldElement;
  28 +import com.squareup.wire.schema.internal.parser.MessageElement;
  29 +import com.squareup.wire.schema.internal.parser.OneOfElement;
  30 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
  31 +import com.squareup.wire.schema.internal.parser.ProtoParser;
  32 +import com.squareup.wire.schema.internal.parser.TypeElement;
  33 +import lombok.Data;
  34 +import lombok.extern.slf4j.Slf4j;
  35 +import org.thingsboard.server.common.data.TransportPayloadType;
  36 +
  37 +import java.util.ArrayList;
  38 +import java.util.Collections;
  39 +import java.util.List;
  40 +import java.util.stream.Collectors;
  41 +
  42 +@Slf4j
  43 +@Data
  44 +public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeConfiguration {
  45 +
  46 + public static final Location LOCATION = new Location("", "", -1, -1);
  47 + public static final String ATTRIBUTES_PROTO_SCHEMA = "attributes proto schema";
  48 + public static final String TELEMETRY_PROTO_SCHEMA = "telemetry proto schema";
  49 +
  50 + private String deviceTelemetryProtoSchema;
  51 + private String deviceAttributesProtoSchema;
  52 +
  53 + @Override
  54 + public TransportPayloadType getTransportPayloadType() {
  55 + return TransportPayloadType.PROTOBUF;
  56 + }
  57 +
  58 + public Descriptors.Descriptor getTelemetryDynamicMessageDescriptor(String deviceTelemetryProtoSchema) {
  59 + return getDescriptor(deviceTelemetryProtoSchema, TELEMETRY_PROTO_SCHEMA);
  60 + }
  61 +
  62 + public Descriptors.Descriptor getAttributesDynamicMessageDescriptor(String deviceAttributesProtoSchema) {
  63 + return getDescriptor(deviceAttributesProtoSchema, ATTRIBUTES_PROTO_SCHEMA);
  64 + }
  65 +
  66 + private Descriptors.Descriptor getDescriptor(String protoSchema, String schemaName) {
  67 + try {
  68 + ProtoFileElement protoFileElement = getTransportProtoSchema(protoSchema);
  69 + DynamicSchema dynamicSchema = getDynamicSchema(protoFileElement, schemaName);
  70 + String lastMsgName = getMessageTypes(protoFileElement.getTypes()).stream()
  71 + .map(MessageElement::getName).reduce((previous, last) -> last).get();
  72 + DynamicMessage.Builder builder = dynamicSchema.newMessageBuilder(lastMsgName);
  73 + return builder.getDescriptorForType();
  74 + } catch (Exception e) {
  75 + log.warn("Failed to get Message Descriptor due to {}", e.getMessage());
  76 + return null;
  77 + }
  78 + }
  79 +
  80 + public DynamicSchema getDynamicSchema(ProtoFileElement protoFileElement, String schemaName) {
  81 + DynamicSchema.Builder schemaBuilder = DynamicSchema.newBuilder();
  82 + schemaBuilder.setName(schemaName);
  83 + schemaBuilder.setPackage(!isEmptyStr(protoFileElement.getPackageName()) ?
  84 + protoFileElement.getPackageName() : schemaName.toLowerCase());
  85 + List<TypeElement> types = protoFileElement.getTypes();
  86 + List<MessageElement> messageTypes = getMessageTypes(types);
  87 +
  88 + if (!messageTypes.isEmpty()) {
  89 + List<EnumElement> enumTypes = getEnumElements(types);
  90 + if (!enumTypes.isEmpty()) {
  91 + enumTypes.forEach(enumElement -> {
  92 + EnumDefinition enumDefinition = getEnumDefinition(enumElement);
  93 + schemaBuilder.addEnumDefinition(enumDefinition);
  94 + });
  95 + }
  96 + List<MessageDefinition> messageDefinitions = getMessageDefinitions(messageTypes);
  97 + messageDefinitions.forEach(schemaBuilder::addMessageDefinition);
  98 + try {
  99 + return schemaBuilder.build();
  100 + } catch (Descriptors.DescriptorValidationException e) {
  101 + throw new RuntimeException("Failed to create dynamic schema due to: " + e.getMessage());
  102 + }
  103 + } else {
  104 + throw new RuntimeException("Failed to get Dynamic Schema! Message types is empty for schema:" + schemaName);
  105 + }
  106 + }
  107 +
  108 + public ProtoFileElement getTransportProtoSchema(String protoSchema) {
  109 + return new ProtoParser(LOCATION, protoSchema.toCharArray()).readProtoFile();
  110 + }
  111 +
  112 + private List<MessageElement> getMessageTypes(List<TypeElement> types) {
  113 + return types.stream()
  114 + .filter(typeElement -> typeElement instanceof MessageElement)
  115 + .map(typeElement -> (MessageElement) typeElement)
  116 + .collect(Collectors.toList());
  117 + }
  118 +
  119 + private List<EnumElement> getEnumElements(List<TypeElement> types) {
  120 + return types.stream()
  121 + .filter(typeElement -> typeElement instanceof EnumElement)
  122 + .map(typeElement -> (EnumElement) typeElement)
  123 + .collect(Collectors.toList());
  124 + }
  125 +
  126 + private List<MessageDefinition> getMessageDefinitions(List<MessageElement> messageElementsList) {
  127 + if (!messageElementsList.isEmpty()) {
  128 + List<MessageDefinition> messageDefinitions = new ArrayList<>();
  129 + messageElementsList.forEach(messageElement -> {
  130 + MessageDefinition.Builder messageDefinitionBuilder = MessageDefinition.newBuilder(messageElement.getName());
  131 +
  132 + List<TypeElement> nestedTypes = messageElement.getNestedTypes();
  133 + if (!nestedTypes.isEmpty()) {
  134 + List<EnumElement> nestedEnumTypes = getEnumElements(nestedTypes);
  135 + if (!nestedEnumTypes.isEmpty()) {
  136 + nestedEnumTypes.forEach(enumElement -> {
  137 + EnumDefinition nestedEnumDefinition = getEnumDefinition(enumElement);
  138 + messageDefinitionBuilder.addEnumDefinition(nestedEnumDefinition);
  139 + });
  140 + }
  141 + List<MessageElement> nestedMessageTypes = getMessageTypes(nestedTypes);
  142 + List<MessageDefinition> nestedMessageDefinitions = getMessageDefinitions(nestedMessageTypes);
  143 + nestedMessageDefinitions.forEach(messageDefinitionBuilder::addMessageDefinition);
  144 + }
  145 + List<FieldElement> messageElementFields = messageElement.getFields();
  146 + List<OneOfElement> oneOfs = messageElement.getOneOfs();
  147 + if (!oneOfs.isEmpty()) {
  148 + for (OneOfElement oneOfelement : oneOfs) {
  149 + MessageDefinition.OneofBuilder oneofBuilder = messageDefinitionBuilder.addOneof(oneOfelement.getName());
  150 + addMessageFieldsToTheOneOfDefinition(oneOfelement.getFields(), oneofBuilder);
  151 + }
  152 + }
  153 + if (!messageElementFields.isEmpty()) {
  154 + addMessageFieldsToTheMessageDefinition(messageElementFields, messageDefinitionBuilder);
  155 + }
  156 + messageDefinitions.add(messageDefinitionBuilder.build());
  157 + });
  158 + return messageDefinitions;
  159 + } else {
  160 + return Collections.emptyList();
  161 + }
  162 + }
  163 +
  164 + private EnumDefinition getEnumDefinition(EnumElement enumElement) {
  165 + List<EnumConstantElement> enumElementTypeConstants = enumElement.getConstants();
  166 + EnumDefinition.Builder enumDefinitionBuilder = EnumDefinition.newBuilder(enumElement.getName());
  167 + if (!enumElementTypeConstants.isEmpty()) {
  168 + enumElementTypeConstants.forEach(constantElement -> enumDefinitionBuilder.addValue(constantElement.getName(), constantElement.getTag()));
  169 + }
  170 + return enumDefinitionBuilder.build();
  171 + }
  172 +
  173 +
  174 + private void addMessageFieldsToTheMessageDefinition(List<FieldElement> messageElementFields, MessageDefinition.Builder messageDefinitionBuilder) {
  175 + messageElementFields.forEach(fieldElement -> {
  176 + String labelStr = null;
  177 + if (fieldElement.getLabel() != null) {
  178 + labelStr = fieldElement.getLabel().name().toLowerCase();
  179 + }
  180 + messageDefinitionBuilder.addField(
  181 + labelStr,
  182 + fieldElement.getType(),
  183 + fieldElement.getName(),
  184 + fieldElement.getTag());
  185 + });
  186 + }
  187 +
  188 + private void addMessageFieldsToTheOneOfDefinition(List<FieldElement> oneOfsElementFields, MessageDefinition.OneofBuilder oneofBuilder) {
  189 + oneOfsElementFields.forEach(fieldElement -> oneofBuilder.addField(
  190 + fieldElement.getType(),
  191 + fieldElement.getName(),
  192 + fieldElement.getTag()));
  193 + oneofBuilder.msgDefBuilder();
  194 + }
  195 +
  196 + private boolean isEmptyStr(String str) {
  197 + return str == null || "".equals(str);
  198 + }
  199 +
  200 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.device.profile;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
  20 +import com.fasterxml.jackson.annotation.JsonSubTypes;
  21 +import com.fasterxml.jackson.annotation.JsonTypeInfo;
  22 +import org.thingsboard.server.common.data.TransportPayloadType;
  23 +
  24 +@JsonIgnoreProperties(ignoreUnknown = true)
  25 +@JsonTypeInfo(
  26 + use = JsonTypeInfo.Id.NAME,
  27 + include = JsonTypeInfo.As.PROPERTY,
  28 + property = "transportPayloadType")
  29 +@JsonSubTypes({
  30 + @JsonSubTypes.Type(value = JsonTransportPayloadConfiguration.class, name = "JSON"),
  31 + @JsonSubTypes.Type(value = ProtoTransportPayloadConfiguration.class, name = "PROTOBUF")})
  32 +public interface TransportPayloadTypeConfiguration {
  33 +
  34 + @JsonIgnore
  35 + TransportPayloadType getTransportPayloadType();
  36 +
  37 +}
@@ -42,6 +42,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @@ -42,6 +42,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
42 private long maxJSExecutions; 42 private long maxJSExecutions;
43 private long maxDPStorageDays; 43 private long maxDPStorageDays;
44 private int maxRuleNodeExecutionsPerMessage; 44 private int maxRuleNodeExecutionsPerMessage;
  45 + private long maxEmails;
  46 + private long maxSms;
45 47
46 private double warnThreshold; 48 private double warnThreshold;
47 49
@@ -58,6 +60,10 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura @@ -58,6 +60,10 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
58 return maxREExecutions; 60 return maxREExecutions;
59 case STORAGE_DP_COUNT: 61 case STORAGE_DP_COUNT:
60 return maxDPStorageDays; 62 return maxDPStorageDays;
  63 + case EMAIL_EXEC_COUNT:
  64 + return maxEmails;
  65 + case SMS_EXEC_COUNT:
  66 + return maxSms;
61 } 67 }
62 return 0L; 68 return 0L;
63 } 69 }
@@ -46,7 +46,6 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue @@ -46,7 +46,6 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue
46 private TbKafkaConsumerTemplate(TbKafkaSettings settings, TbKafkaDecoder<T> decoder, 46 private TbKafkaConsumerTemplate(TbKafkaSettings settings, TbKafkaDecoder<T> decoder,
47 String clientId, String groupId, String topic, 47 String clientId, String groupId, String topic,
48 boolean autoCommit, int autoCommitIntervalMs, 48 boolean autoCommit, int autoCommitIntervalMs,
49 - int maxPollRecords,  
50 TbQueueAdmin admin) { 49 TbQueueAdmin admin) {
51 super(topic); 50 super(topic);
52 Properties props = settings.toProps(); 51 Properties props = settings.toProps();
@@ -54,6 +53,9 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue @@ -54,6 +53,9 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue
54 if (groupId != null) { 53 if (groupId != null) {
55 props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); 54 props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
56 } 55 }
  56 + if (settings.getMaxPollIntervalMs() > 0) {
  57 + props.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, settings.getMaxPollIntervalMs());
  58 + }
57 props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, settings.getMaxPollRecords()); 59 props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, settings.getMaxPollRecords());
58 props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, settings.getMaxPartitionFetchBytes()); 60 props.put(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG, settings.getMaxPartitionFetchBytes());
59 props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, settings.getFetchMaxBytes()); 61 props.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, settings.getFetchMaxBytes());
@@ -61,9 +63,6 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue @@ -61,9 +63,6 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue
61 props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitIntervalMs); 63 props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, autoCommitIntervalMs);
62 props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer"); 64 props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
63 props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArrayDeserializer"); 65 props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArrayDeserializer");
64 - if (maxPollRecords > 0) {  
65 - props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords);  
66 - }  
67 this.admin = admin; 66 this.admin = admin;
68 this.consumer = new KafkaConsumer<>(props); 67 this.consumer = new KafkaConsumer<>(props);
69 this.decoder = decoder; 68 this.decoder = decoder;
@@ -63,6 +63,10 @@ public class TbKafkaSettings { @@ -63,6 +63,10 @@ public class TbKafkaSettings {
63 @Getter 63 @Getter
64 private int maxPollRecords; 64 private int maxPollRecords;
65 65
  66 + @Value("${queue.kafka.max_poll_interval_ms:0}")
  67 + @Getter
  68 + private int maxPollIntervalMs;
  69 +
66 @Value("${queue.kafka.max_partition_fetch_bytes:16777216}") 70 @Value("${queue.kafka.max_partition_fetch_bytes:16777216}")
67 @Getter 71 @Getter
68 private int maxPartitionFetchBytes; 72 private int maxPartitionFetchBytes;
@@ -111,4 +115,5 @@ public class TbKafkaSettings { @@ -111,4 +115,5 @@ public class TbKafkaSettings {
111 } 115 }
112 return props; 116 return props;
113 } 117 }
  118 +
114 } 119 }
@@ -269,8 +269,9 @@ message ProvisionDeviceCredentialsMsg { @@ -269,8 +269,9 @@ message ProvisionDeviceCredentialsMsg {
269 } 269 }
270 270
271 message ProvisionDeviceResponseMsg { 271 message ProvisionDeviceResponseMsg {
272 - DeviceCredentialsProto deviceCredentials = 1;  
273 - ProvisionResponseStatus provisionResponseStatus = 2; 272 + ProvisionResponseStatus status = 1;
  273 + CredentialsType credentialsType = 2;
  274 + string credentialsValue = 3;
274 } 275 }
275 276
276 enum ProvisionResponseStatus { 277 enum ProvisionResponseStatus {