Browse Source

Merge branch 'master' of https://github.com/thingsboard/thingsboard into rate-limits-to-tenant-profile

pull/4650/head
AndrewVolosytnykhThingsboard 5 years ago
parent
commit
40d435f206
  1. 21
      application/src/main/data/json/demo/dashboards/firmware.json
  2. 14
      application/src/main/data/upgrade/3.2.2/schema_update.sql
  3. 42
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  4. 19
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  5. 2
      application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java
  6. 222
      application/src/main/java/org/thingsboard/server/controller/FirmwareController.java
  7. 222
      application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
  8. 136
      application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java
  9. 8
      application/src/main/java/org/thingsboard/server/service/ota/OtaPackageStateService.java
  10. 31
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
  11. 24
      application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
  12. 2
      application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java
  13. 2
      application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java
  14. 68
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  15. 19
      application/src/main/resources/thingsboard.yml
  16. 115
      application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java
  17. 4
      application/src/test/java/org/thingsboard/server/controller/sql/OtaPackageControllerSqlTest.java
  18. 13
      common/cache/src/main/java/org/thingsboard/server/cache/ota/CaffeineOtaPackageCache.java
  19. 8
      common/cache/src/main/java/org/thingsboard/server/cache/ota/OtaPackageDataCache.java
  20. 19
      common/cache/src/main/java/org/thingsboard/server/cache/ota/RedisOtaPackageDataCache.java
  21. 5
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
  22. 52
      common/dao-api/src/main/java/org/thingsboard/server/dao/firmware/FirmwareService.java
  23. 52
      common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java
  24. 3
      common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java
  25. 16
      common/data/src/main/java/org/thingsboard/server/common/data/Device.java
  26. 8
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java
  27. 2
      common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
  28. 8
      common/data/src/main/java/org/thingsboard/server/common/data/HasOtaPackage.java
  29. 10
      common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java
  30. 40
      common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java
  31. 4
      common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java
  32. 10
      common/data/src/main/java/org/thingsboard/server/common/data/id/OtaPackageId.java
  33. 2
      common/data/src/main/java/org/thingsboard/server/common/data/ota/ChecksumAlgorithm.java
  34. 6
      common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageKey.java
  35. 6
      common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageType.java
  36. 4
      common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageUpdateStatus.java
  37. 49
      common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageUtil.java
  38. 2
      common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java
  39. 10
      common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java
  40. 12
      common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java
  41. 8
      common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java
  42. 22
      common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java
  43. 22
      common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java
  44. 12
      common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java
  45. 12
      common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java
  46. 12
      common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java
  47. 12
      common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java
  48. 12
      common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java
  49. 12
      common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java
  50. 6
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java
  51. 4
      common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java
  52. 4
      common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueCoreSettings.java
  53. 18
      common/queue/src/main/proto/queue.proto
  54. 22
      common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
  55. 32
      common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java
  56. 159
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java
  57. 98
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java
  58. 152
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java
  59. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java
  60. 43
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  61. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  62. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  63. 89
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java
  64. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java
  65. 15
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java
  66. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java
  67. 58
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java
  68. 4
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java
  69. 4
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java
  70. 4
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java
  71. 5
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java
  72. 6
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java
  73. 6
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  74. 8
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java
  75. 16
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  76. 52
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  77. 12
      dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
  78. 379
      dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java
  79. 31
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  80. 6
      dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java
  81. 6
      dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java
  82. 70
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java
  83. 72
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageInfoEntity.java
  84. 366
      dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java
  85. 6
      dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java
  86. 18
      dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageInfoDao.java
  87. 20
      dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java
  88. 36
      dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java
  89. 60
      dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java
  90. 94
      dao/src/main/java/org/thingsboard/server/dao/sql/firmware/JpaFirmwareInfoDao.java
  91. 20
      dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java
  92. 94
      dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageInfoDao.java
  93. 60
      dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageInfoRepository.java
  94. 6
      dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageRepository.java
  95. 6
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java
  96. 14
      dao/src/main/resources/sql/schema-entities-hsql.sql
  97. 14
      dao/src/main/resources/sql/schema-entities.sql
  98. 4
      dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java
  99. 11
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java
  100. 14
      dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java

21
application/src/main/data/json/demo/dashboards/firmware.json

@ -1,5 +1,6 @@
{
"title": "Firmware",
"image": null,
"configuration": {
"description": "",
"widgets": {
@ -247,7 +248,7 @@
"name": "Edit firmware",
"icon": "edit",
"type": "customPretty",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div *ngIf=\"entity.deviceProfileId\" mat-dialog-content fxLayout=\"column\">\n <tb-firmware-autocomplete\n [useFullEntityId]=\"true\"\n [deviceProfileId]=\"entity.deviceProfileId.id\"\n formControlName=\"firmwareId\">\n </tb-firmware-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div *ngIf=\"entity.deviceProfileId\" mat-dialog-content fxLayout=\"column\">\n <tb-ota-package-autocomplete\n [useFullEntityId]=\"true\"\n [deviceProfileId]=\"entity.deviceProfileId.id\"\n formControlName=\"firmwareId\">\n </tb-ota-package-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customCss": "",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();\n}\n\nfunction EditEntityDialogController(instance) {\n let vm = instance;\n\n vm.entityName = entityName;\n vm.entity = {};\n\n vm.editEntityFormGroup = vm.fb.group({\n firmwareId: [null]\n });\n\n getEntityInfo();\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n\n vm.save = function() {\n vm.editEntityFormGroup.markAsPristine();\n saveEntity().subscribe(\n function () {\n // widgetContext.updateAliases();\n vm.dialogRef.close(null);\n }\n );\n };\n\n\n function getEntityInfo() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n vm.entity = data;\n vm.editEntityFormGroup.patchValue({\n firmwareId: vm.entity.firmwareId\n }, {emitEvent: false});\n }\n );\n }\n\n function saveEntity() {\n const formValues = vm.editEntityFormGroup.value;\n vm.entity.firmwareId = formValues.firmwareId;\n return deviceService.saveDevice(vm.entity);\n }\n}",
"customResources": [],
@ -257,7 +258,7 @@
"name": "Download firware",
"icon": "file_download",
"type": "custom",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet firmwareService = $injector.get(widgetContext.servicesMap.get('firmwareService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n firmwareService.downloadFirmware(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n firmwareService.downloadFirmware(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet otaPackageService = $injector.get(widgetContext.servicesMap.get('otaPackageService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"id": "12533058-42f6-e75f-620c-219c48d01ec0"
},
{
@ -1021,7 +1022,7 @@
"name": "Edit firmware",
"icon": "edit",
"type": "customPretty",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div mat-dialog-content fxLayout=\"column\">\n <tb-firmware-autocomplete\n [useFullEntityId]=\"true\"\n formControlName=\"firmwareId\">\n </tb-firmware-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div *ngIf=\"entity.deviceProfileId\" mat-dialog-content fxLayout=\"column\">\n <tb-ota-package-autocomplete\n [useFullEntityId]=\"true\"\n [deviceProfileId]=\"entity.deviceProfileId.id\"\n formControlName=\"firmwareId\">\n </tb-ota-package-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customCss": "",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();\n}\n\nfunction EditEntityDialogController(instance) {\n let vm = instance;\n\n vm.entityName = entityName;\n vm.entity = {};\n\n vm.editEntityFormGroup = vm.fb.group({\n firmwareId: [null]\n });\n\n getEntityInfo();\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n\n vm.save = function() {\n vm.editEntityFormGroup.markAsPristine();\n saveEntity().subscribe(\n function () {\n // widgetContext.updateAliases();\n vm.dialogRef.close(null);\n }\n );\n };\n\n\n function getEntityInfo() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n vm.entity = data;\n vm.editEntityFormGroup.patchValue({\n firmwareId: vm.entity.firmwareId\n }, {emitEvent: false});\n }\n );\n }\n\n function saveEntity() {\n const formValues = vm.editEntityFormGroup.value;\n vm.entity.firmwareId = formValues.firmwareId;\n return deviceService.saveDevice(vm.entity);\n }\n}",
"customResources": [],
@ -1031,7 +1032,7 @@
"name": "Download firware",
"icon": "file_download",
"type": "custom",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet firmwareService = $injector.get(widgetContext.servicesMap.get('firmwareService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n firmwareService.downloadFirmware(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n firmwareService.downloadFirmware(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet otaPackageService = $injector.get(widgetContext.servicesMap.get('otaPackageService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"id": "12533058-42f6-e75f-620c-219c48d01ec0"
},
{
@ -1297,7 +1298,7 @@
"name": "Edit firmware",
"icon": "edit",
"type": "customPretty",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div mat-dialog-content fxLayout=\"column\">\n <tb-firmware-autocomplete\n [useFullEntityId]=\"true\"\n formControlName=\"firmwareId\">\n </tb-firmware-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div *ngIf=\"entity.deviceProfileId\" mat-dialog-content fxLayout=\"column\">\n <tb-ota-package-autocomplete\n [useFullEntityId]=\"true\"\n [deviceProfileId]=\"entity.deviceProfileId.id\"\n formControlName=\"firmwareId\">\n </tb-ota-package-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customCss": "",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();\n}\n\nfunction EditEntityDialogController(instance) {\n let vm = instance;\n\n vm.entityName = entityName;\n vm.entity = {};\n\n vm.editEntityFormGroup = vm.fb.group({\n firmwareId: [null]\n });\n\n getEntityInfo();\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n\n vm.save = function() {\n vm.editEntityFormGroup.markAsPristine();\n saveEntity().subscribe(\n function () {\n // widgetContext.updateAliases();\n vm.dialogRef.close(null);\n }\n );\n };\n\n\n function getEntityInfo() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n vm.entity = data;\n vm.editEntityFormGroup.patchValue({\n firmwareId: vm.entity.firmwareId\n }, {emitEvent: false});\n }\n );\n }\n\n function saveEntity() {\n const formValues = vm.editEntityFormGroup.value;\n vm.entity.firmwareId = formValues.firmwareId;\n return deviceService.saveDevice(vm.entity);\n }\n}",
"customResources": [],
@ -1307,7 +1308,7 @@
"name": "Download firware",
"icon": "file_download",
"type": "custom",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet firmwareService = $injector.get(widgetContext.servicesMap.get('firmwareService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n firmwareService.downloadFirmware(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n firmwareService.downloadFirmware(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet otaPackageService = $injector.get(widgetContext.servicesMap.get('otaPackageService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"id": "12533058-42f6-e75f-620c-219c48d01ec0"
},
{
@ -1573,7 +1574,7 @@
"name": "Edit firmware",
"icon": "edit",
"type": "customPretty",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div mat-dialog-content fxLayout=\"column\">\n <tb-firmware-autocomplete\n [useFullEntityId]=\"true\"\n formControlName=\"firmwareId\">\n </tb-firmware-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div *ngIf=\"entity.deviceProfileId\" mat-dialog-content fxLayout=\"column\">\n <tb-ota-package-autocomplete\n [useFullEntityId]=\"true\"\n [deviceProfileId]=\"entity.deviceProfileId.id\"\n formControlName=\"firmwareId\">\n </tb-ota-package-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customCss": "",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();\n}\n\nfunction EditEntityDialogController(instance) {\n let vm = instance;\n\n vm.entityName = entityName;\n vm.entity = {};\n\n vm.editEntityFormGroup = vm.fb.group({\n firmwareId: [null]\n });\n\n getEntityInfo();\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n\n vm.save = function() {\n vm.editEntityFormGroup.markAsPristine();\n saveEntity().subscribe(\n function () {\n // widgetContext.updateAliases();\n vm.dialogRef.close(null);\n }\n );\n };\n\n\n function getEntityInfo() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n vm.entity = data;\n vm.editEntityFormGroup.patchValue({\n firmwareId: vm.entity.firmwareId\n }, {emitEvent: false});\n }\n );\n }\n\n function saveEntity() {\n const formValues = vm.editEntityFormGroup.value;\n vm.entity.firmwareId = formValues.firmwareId;\n return deviceService.saveDevice(vm.entity);\n }\n}",
"customResources": [],
@ -1583,7 +1584,7 @@
"name": "Download firware",
"icon": "file_download",
"type": "custom",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet firmwareService = $injector.get(widgetContext.servicesMap.get('firmwareService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n firmwareService.downloadFirmware(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n firmwareService.downloadFirmware(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet otaPackageService = $injector.get(widgetContext.servicesMap.get('otaPackageService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"id": "12533058-42f6-e75f-620c-219c48d01ec0"
},
{
@ -1849,7 +1850,7 @@
"name": "Edit firmware",
"icon": "edit",
"type": "customPretty",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div mat-dialog-content fxLayout=\"column\">\n <tb-firmware-autocomplete\n [useFullEntityId]=\"true\"\n formControlName=\"firmwareId\">\n </tb-firmware-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customHtml": "<form #editEntityForm=\"ngForm\" [formGroup]=\"editEntityFormGroup\"\n (ngSubmit)=\"save()\" class=\"edit-entity-form\">\n <mat-toolbar fxLayout=\"row\" color=\"primary\">\n <h2>Edit firmware {{entityName}}</h2>\n <span fxFlex></span>\n <button mat-icon-button (click)=\"cancel()\" type=\"button\">\n <mat-icon class=\"material-icons\">close</mat-icon>\n </button>\n </mat-toolbar>\n <mat-progress-bar color=\"warn\" mode=\"indeterminate\" *ngIf=\"isLoading$ | async\">\n </mat-progress-bar>\n <div style=\"height: 4px;\" *ngIf=\"!(isLoading$ | async)\"></div>\n <div *ngIf=\"entity.deviceProfileId\" mat-dialog-content fxLayout=\"column\">\n <tb-ota-package-autocomplete\n [useFullEntityId]=\"true\"\n [deviceProfileId]=\"entity.deviceProfileId.id\"\n formControlName=\"firmwareId\">\n </tb-ota-package-autocomplete>\n </div>\n <div mat-dialog-actions fxLayout=\"row\" fxLayoutAlign=\"end center\">\n <button mat-button color=\"primary\"\n type=\"button\"\n [disabled]=\"(isLoading$ | async)\"\n (click)=\"cancel()\" cdkFocusInitial>\n Cancel\n </button>\n <button mat-button mat-raised-button color=\"primary\"\n type=\"submit\"\n [disabled]=\"(isLoading$ | async) || editEntityForm.invalid || !editEntityForm.dirty\">\n Save\n </button>\n </div>\n</form>",
"customCss": "",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet deviceService = $injector.get(widgetContext.servicesMap.get('deviceService'));\n\nopenEditEntityDialog();\n\nfunction openEditEntityDialog() {\n customDialog.customDialog(htmlTemplate, EditEntityDialogController).subscribe();\n}\n\nfunction EditEntityDialogController(instance) {\n let vm = instance;\n\n vm.entityName = entityName;\n vm.entity = {};\n\n vm.editEntityFormGroup = vm.fb.group({\n firmwareId: [null]\n });\n\n getEntityInfo();\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n\n vm.save = function() {\n vm.editEntityFormGroup.markAsPristine();\n saveEntity().subscribe(\n function () {\n // widgetContext.updateAliases();\n vm.dialogRef.close(null);\n }\n );\n };\n\n\n function getEntityInfo() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n vm.entity = data;\n vm.editEntityFormGroup.patchValue({\n firmwareId: vm.entity.firmwareId\n }, {emitEvent: false});\n }\n );\n }\n\n function saveEntity() {\n const formValues = vm.editEntityFormGroup.value;\n vm.entity.firmwareId = formValues.firmwareId;\n return deviceService.saveDevice(vm.entity);\n }\n}",
"customResources": [],
@ -1859,7 +1860,7 @@
"name": "Download firware",
"icon": "file_download",
"type": "custom",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet firmwareService = $injector.get(widgetContext.servicesMap.get('firmwareService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n firmwareService.downloadFirmware(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n firmwareService.downloadFirmware(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"customFunction": "let $injector = widgetContext.$scope.$injector;\nlet entityService = $injector.get(widgetContext.servicesMap.get('entityService'));\nlet otaPackageService = $injector.get(widgetContext.servicesMap.get('otaPackageService'));\nlet deviceProfileService = $injector.get(widgetContext.servicesMap.get('deviceProfileService'));\n\ngetDeviceFirmware();\n\nfunction getDeviceFirmware() {\n entityService.getEntity(entityId.entityType, entityId.id).subscribe(\n function (data) {\n if (data.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(data.firmwareId.id).subscribe(); \n } else {\n deviceProfileService.getDeviceProfile(data.deviceProfileId.id).subscribe(\n function (deviceProfile) {\n if (deviceProfile.firmwareId !== null) {\n otaPackageService.downloadOtaPackage(deviceProfile.firmwareId.id).subscribe();\n } else {\n widgetContext.showToast('warn', 'Device ' + entityName +' has not firmware set.', 2000, 'top');\n\n }\n });\n }\n }\n );\n}",
"id": "12533058-42f6-e75f-620c-219c48d01ec0"
},
{

14
application/src/main/data/upgrade/3.2.2/schema_update.sql

@ -59,8 +59,8 @@ CREATE TABLE IF NOT EXISTS resource (
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
);
CREATE TABLE IF NOT EXISTS firmware (
id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
CREATE TABLE IF NOT EXISTS ota_package (
id uuid NOT NULL CONSTRAINT ota_package_pkey PRIMARY KEY,
created_time bigint NOT NULL,
tenant_id uuid NOT NULL,
device_profile_id uuid,
@ -75,7 +75,7 @@ CREATE TABLE IF NOT EXISTS firmware (
data_size bigint,
additional_info varchar,
search_text varchar(255),
CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
CONSTRAINT ota_package_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
);
ALTER TABLE dashboard
@ -101,13 +101,13 @@ DO $$
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device_profile') THEN
ALTER TABLE device_profile
ADD CONSTRAINT fk_firmware_device_profile
FOREIGN KEY (firmware_id) REFERENCES firmware(id);
FOREIGN KEY (firmware_id) REFERENCES ota_package(id);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device_profile') THEN
ALTER TABLE device_profile
ADD CONSTRAINT fk_software_device_profile
FOREIGN KEY (firmware_id) REFERENCES firmware(id);
FOREIGN KEY (firmware_id) REFERENCES ota_package(id);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_default_dashboard_device_profile') THEN
@ -119,13 +119,13 @@ DO $$
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device') THEN
ALTER TABLE device
ADD CONSTRAINT fk_firmware_device
FOREIGN KEY (firmware_id) REFERENCES firmware(id);
FOREIGN KEY (firmware_id) REFERENCES ota_package(id);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_software_device') THEN
ALTER TABLE device
ADD CONSTRAINT fk_software_device
FOREIGN KEY (firmware_id) REFERENCES firmware(id);
FOREIGN KEY (firmware_id) REFERENCES ota_package(id);
END IF;
END;
$$;

42
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -39,8 +39,8 @@ import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.TbResourceInfo;
@ -70,7 +70,7 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
@ -110,7 +110,7 @@ import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
@ -128,7 +128,7 @@ import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.firmware.FirmwareStateService;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.edge.rpc.EdgeGrpcService;
import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService;
@ -250,10 +250,10 @@ public abstract class BaseController {
protected TbResourceService resourceService;
@Autowired
protected FirmwareService firmwareService;
protected OtaPackageService otaPackageService;
@Autowired
protected FirmwareStateService firmwareStateService;
protected OtaPackageStateService otaPackageStateService;
@Autowired
protected TbQueueProducerProvider producerProvider;
@ -511,8 +511,8 @@ public abstract class BaseController {
case TB_RESOURCE:
checkResourceId(new TbResourceId(entityId.getId()), operation);
return;
case FIRMWARE:
checkFirmwareId(new FirmwareId(entityId.getId()), operation);
case OTA_PACKAGE:
checkOtaPackageId(new OtaPackageId(entityId.getId()), operation);
return;
default:
throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType());
@ -769,25 +769,25 @@ public abstract class BaseController {
}
}
Firmware checkFirmwareId(FirmwareId firmwareId, Operation operation) throws ThingsboardException {
OtaPackage checkOtaPackageId(OtaPackageId otaPackageId, Operation operation) throws ThingsboardException {
try {
validateId(firmwareId, "Incorrect firmwareId " + firmwareId);
Firmware firmware = firmwareService.findFirmwareById(getCurrentUser().getTenantId(), firmwareId);
checkNotNull(firmware);
accessControlService.checkPermission(getCurrentUser(), Resource.FIRMWARE, operation, firmwareId, firmware);
return firmware;
validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId);
OtaPackage otaPackage = otaPackageService.findOtaPackageById(getCurrentUser().getTenantId(), otaPackageId);
checkNotNull(otaPackage);
accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackage);
return otaPackage;
} catch (Exception e) {
throw handleException(e, false);
}
}
FirmwareInfo checkFirmwareInfoId(FirmwareId firmwareId, Operation operation) throws ThingsboardException {
OtaPackageInfo checkOtaPackageInfoId(OtaPackageId otaPackageId, Operation operation) throws ThingsboardException {
try {
validateId(firmwareId, "Incorrect firmwareId " + firmwareId);
FirmwareInfo firmwareInfo = firmwareService.findFirmwareInfoById(getCurrentUser().getTenantId(), firmwareId);
checkNotNull(firmwareInfo);
accessControlService.checkPermission(getCurrentUser(), Resource.FIRMWARE, operation, firmwareId, firmwareInfo);
return firmwareInfo;
validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId);
OtaPackageInfo otaPackageIn = otaPackageService.findOtaPackageInfoById(getCurrentUser().getTenantId(), otaPackageId);
checkNotNull(otaPackageIn);
accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackageIn);
return otaPackageIn;
} catch (Exception e) {
throw handleException(e, false);
}

19
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
@ -75,6 +76,7 @@ import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
@ -153,7 +155,7 @@ public class DeviceController extends BaseController {
deviceStateService.onDeviceUpdated(savedDevice);
}
firmwareStateService.update(savedDevice, oldDevice);
otaPackageStateService.update(savedDevice, oldDevice);
return savedDevice;
} catch (Exception e) {
@ -778,4 +780,19 @@ public class DeviceController extends BaseController {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/devices/count/{otaPackageType}", method = RequestMethod.GET)
@ResponseBody
public Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(@PathVariable("otaPackageType") String otaPackageType,
@RequestParam String deviceProfileId) throws ThingsboardException {
checkParameter("OtaPackageType", otaPackageType);
checkParameter("DeviceProfileId", deviceProfileId);
try {
return deviceService.countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(
getCurrentUser().getTenantId(), new DeviceProfileId(UUID.fromString(deviceProfileId)), OtaPackageType.valueOf(otaPackageType));
} catch (Exception e) {
throw handleException(e);
}
}
}

2
application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java

@ -168,7 +168,7 @@ public class DeviceProfileController extends BaseController {
null,
created ? ActionType.ADDED : ActionType.UPDATED, null);
firmwareStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
otaPackageStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged);
sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(),
deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);

222
application/src/main/java/org/thingsboard/server/controller/FirmwareController.java

@ -1,222 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.nio.ByteBuffer;
@Slf4j
@RestController
@TbCoreComponent
@RequestMapping("/api")
public class FirmwareController extends BaseController {
public static final String FIRMWARE_ID = "firmwareId";
public static final String CHECKSUM_ALGORITHM = "checksumAlgorithm";
@PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')")
@RequestMapping(value = "/firmware/{firmwareId}/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadFirmware(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException {
checkParameter(FIRMWARE_ID, strFirmwareId);
try {
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId));
Firmware firmware = checkFirmwareId(firmwareId, Operation.READ);
ByteArrayResource resource = new ByteArrayResource(firmware.getData().array());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + firmware.getFileName())
.header("x-filename", firmware.getFileName())
.contentLength(resource.contentLength())
.contentType(parseMediaType(firmware.getContentType()))
.body(resource);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/firmware/info/{firmwareId}", method = RequestMethod.GET)
@ResponseBody
public FirmwareInfo getFirmwareInfoById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException {
checkParameter(FIRMWARE_ID, strFirmwareId);
try {
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId));
return checkNotNull(firmwareService.findFirmwareInfoById(getTenantId(), firmwareId));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.GET)
@ResponseBody
public Firmware getFirmwareById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException {
checkParameter(FIRMWARE_ID, strFirmwareId);
try {
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId));
return checkFirmwareId(firmwareId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/firmware", method = RequestMethod.POST)
@ResponseBody
public FirmwareInfo saveFirmwareInfo(@RequestBody FirmwareInfo firmwareInfo) throws ThingsboardException {
boolean created = firmwareInfo.getId() == null;
try {
firmwareInfo.setTenantId(getTenantId());
checkEntity(firmwareInfo.getId(), firmwareInfo, Resource.FIRMWARE);
FirmwareInfo savedFirmwareInfo = firmwareService.saveFirmwareInfo(firmwareInfo);
logEntityAction(savedFirmwareInfo.getId(), savedFirmwareInfo,
null, created ? ActionType.ADDED : ActionType.UPDATED, null);
return savedFirmwareInfo;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.FIRMWARE), firmwareInfo,
null, created ? ActionType.ADDED : ActionType.UPDATED, e);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.POST)
@ResponseBody
public Firmware saveFirmwareData(@PathVariable(FIRMWARE_ID) String strFirmwareId,
@RequestParam(required = false) String checksum,
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr,
@RequestBody MultipartFile file) throws ThingsboardException {
checkParameter(FIRMWARE_ID, strFirmwareId);
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
try {
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId));
FirmwareInfo info = checkFirmwareInfoId(firmwareId, Operation.READ);
Firmware firmware = new Firmware(firmwareId);
firmware.setCreatedTime(info.getCreatedTime());
firmware.setTenantId(getTenantId());
firmware.setDeviceProfileId(info.getDeviceProfileId());
firmware.setType(info.getType());
firmware.setTitle(info.getTitle());
firmware.setVersion(info.getVersion());
firmware.setAdditionalInfo(info.getAdditionalInfo());
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase());
byte[] bytes = file.getBytes();
if (StringUtils.isEmpty(checksum)) {
checksum = firmwareService.generateChecksum(checksumAlgorithm, ByteBuffer.wrap(bytes));
}
firmware.setChecksumAlgorithm(checksumAlgorithm);
firmware.setChecksum(checksum);
firmware.setFileName(file.getOriginalFilename());
firmware.setContentType(file.getContentType());
firmware.setData(ByteBuffer.wrap(bytes));
firmware.setDataSize((long) bytes.length);
Firmware savedFirmware = firmwareService.saveFirmware(firmware);
logEntityAction(savedFirmware.getId(), savedFirmware, null, ActionType.UPDATED, null);
return savedFirmware;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.FIRMWARE), null, null, ActionType.UPDATED, e, strFirmwareId);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/firmwares", method = RequestMethod.GET)
@ResponseBody
public PageData<FirmwareInfo> getFirmwares(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(firmwareService.findTenantFirmwaresByTenantId(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/firmwares/{deviceProfileId}/{type}/{hasData}", method = RequestMethod.GET)
@ResponseBody
public PageData<FirmwareInfo> getFirmwares(@PathVariable("deviceProfileId") String strDeviceProfileId,
@PathVariable("type") String strType,
@PathVariable("hasData") boolean hasData,
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
checkParameter("type", strType);
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(),
new DeviceProfileId(toUUID(strDeviceProfileId)), FirmwareType.valueOf(strType), hasData, pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteFirmware(@PathVariable("firmwareId") String strFirmwareId) throws ThingsboardException {
checkParameter(FIRMWARE_ID, strFirmwareId);
try {
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId));
FirmwareInfo info = checkFirmwareInfoId(firmwareId, Operation.DELETE);
firmwareService.deleteFirmware(getTenantId(), firmwareId);
logEntityAction(firmwareId, info, null, ActionType.DELETED, null, strFirmwareId);
} catch (Exception e) {
logEntityAction(emptyId(EntityType.FIRMWARE), null, null, ActionType.DELETED, e, strFirmwareId);
throw handleException(e);
}
}
}

222
application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java

@ -0,0 +1,222 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.nio.ByteBuffer;
@Slf4j
@RestController
@TbCoreComponent
@RequestMapping("/api")
public class OtaPackageController extends BaseController {
public static final String OTA_PACKAGE_ID = "otaPackageId";
public static final String CHECKSUM_ALGORITHM = "checksumAlgorithm";
@PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadOtaPackage(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackage otaPackage = checkOtaPackageId(otaPackageId, Operation.READ);
ByteArrayResource resource = new ByteArrayResource(otaPackage.getData().array());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackage.getFileName())
.header("x-filename", otaPackage.getFileName())
.contentLength(resource.contentLength())
.contentType(parseMediaType(otaPackage.getContentType()))
.body(resource);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
public OtaPackageInfo getOtaPackageInfoById(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
return checkNotNull(otaPackageService.findOtaPackageInfoById(getTenantId(), otaPackageId));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
public OtaPackage getOtaPackageById(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
return checkOtaPackageId(otaPackageId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage", method = RequestMethod.POST)
@ResponseBody
public OtaPackageInfo saveOtaPackageInfo(@RequestBody OtaPackageInfo otaPackageInfo) throws ThingsboardException {
boolean created = otaPackageInfo.getId() == null;
try {
otaPackageInfo.setTenantId(getTenantId());
checkEntity(otaPackageInfo.getId(), otaPackageInfo, Resource.OTA_PACKAGE);
OtaPackageInfo savedOtaPackageInfo = otaPackageService.saveOtaPackageInfo(otaPackageInfo);
logEntityAction(savedOtaPackageInfo.getId(), savedOtaPackageInfo,
null, created ? ActionType.ADDED : ActionType.UPDATED, null);
return savedOtaPackageInfo;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.OTA_PACKAGE), otaPackageInfo,
null, created ? ActionType.ADDED : ActionType.UPDATED, e);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST)
@ResponseBody
public OtaPackage saveOtaPackageData(@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId,
@RequestParam(required = false) String checksum,
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr,
@RequestBody MultipartFile file) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackageInfo info = checkOtaPackageInfoId(otaPackageId, Operation.READ);
OtaPackage otaPackage = new OtaPackage(otaPackageId);
otaPackage.setCreatedTime(info.getCreatedTime());
otaPackage.setTenantId(getTenantId());
otaPackage.setDeviceProfileId(info.getDeviceProfileId());
otaPackage.setType(info.getType());
otaPackage.setTitle(info.getTitle());
otaPackage.setVersion(info.getVersion());
otaPackage.setAdditionalInfo(info.getAdditionalInfo());
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase());
byte[] bytes = file.getBytes();
if (StringUtils.isEmpty(checksum)) {
checksum = otaPackageService.generateChecksum(checksumAlgorithm, ByteBuffer.wrap(bytes));
}
otaPackage.setChecksumAlgorithm(checksumAlgorithm);
otaPackage.setChecksum(checksum);
otaPackage.setFileName(file.getOriginalFilename());
otaPackage.setContentType(file.getContentType());
otaPackage.setData(ByteBuffer.wrap(bytes));
otaPackage.setDataSize((long) bytes.length);
OtaPackage savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage);
logEntityAction(savedOtaPackage.getId(), savedOtaPackage, null, ActionType.UPDATED, null);
return savedOtaPackage;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.OTA_PACKAGE), null, null, ActionType.UPDATED, e, strOtaPackageId);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages", method = RequestMethod.GET)
@ResponseBody
public PageData<OtaPackageInfo> getOtaPackages(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantId(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}/{hasData}", method = RequestMethod.GET)
@ResponseBody
public PageData<OtaPackageInfo> getOtaPackages(@PathVariable("deviceProfileId") String strDeviceProfileId,
@PathVariable("type") String strType,
@PathVariable("hasData") boolean hasData,
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("deviceProfileId", strDeviceProfileId);
checkParameter("type", strType);
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(otaPackageService.findTenantOtaPackagesByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(),
new DeviceProfileId(toUUID(strDeviceProfileId)), OtaPackageType.valueOf(strType), hasData, pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteOtaPackage(@PathVariable("otaPackageId") String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackageInfo info = checkOtaPackageInfoId(otaPackageId, Operation.DELETE);
otaPackageService.deleteOtaPackage(getTenantId(), otaPackageId);
logEntityAction(otaPackageId, info, null, ActionType.DELETED, null, strOtaPackageId);
} catch (Exception e) {
logEntityAction(emptyId(EntityType.OTA_PACKAGE), null, null, ActionType.DELETED, e, strOtaPackageId);
throw handleException(e);
}
}
}

136
application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java → application/src/main/java/org/thingsboard/server/service/ota/DefaultOtaPackageStateService.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.firmware;
package org.thingsboard.server.service.ota;
import com.google.common.util.concurrent.FutureCallback;
import lombok.extern.slf4j.Slf4j;
@ -23,12 +23,9 @@ import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.common.data.firmware.FirmwareUtil;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKey;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@ -37,13 +34,16 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.queue.TbQueueProducer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
@ -58,44 +58,43 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.CHECKSUM;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.CHECKSUM_ALGORITHM;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.SIZE;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.TITLE;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.TS;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.VERSION;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTargetTelemetryKey;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getTelemetryKey;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM_ALGORITHM;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.SIZE;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.TITLE;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.TS;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.VERSION;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey;
import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getTargetTelemetryKey;
import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getTelemetryKey;
@Slf4j
@Service
@TbCoreComponent
public class DefaultFirmwareStateService implements FirmwareStateService {
public class DefaultOtaPackageStateService implements OtaPackageStateService {
private final TbClusterService tbClusterService;
private final FirmwareService firmwareService;
private final OtaPackageService otaPackageService;
private final DeviceService deviceService;
private final DeviceProfileService deviceProfileService;
private final RuleEngineTelemetryService telemetryService;
private final TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> fwStateMsgProducer;
private final TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> otaPackageStateMsgProducer;
public DefaultFirmwareStateService(TbClusterService tbClusterService, FirmwareService firmwareService,
DeviceService deviceService,
DeviceProfileService deviceProfileService,
RuleEngineTelemetryService telemetryService,
TbCoreQueueFactory coreQueueFactory) {
public DefaultOtaPackageStateService(TbClusterService tbClusterService, OtaPackageService otaPackageService,
DeviceService deviceService,
DeviceProfileService deviceProfileService,
RuleEngineTelemetryService telemetryService,
TbCoreQueueFactory coreQueueFactory) {
this.tbClusterService = tbClusterService;
this.firmwareService = firmwareService;
this.otaPackageService = otaPackageService;
this.deviceService = deviceService;
this.deviceProfileService = deviceProfileService;
this.telemetryService = telemetryService;
this.fwStateMsgProducer = coreQueueFactory.createToFirmwareStateServiceMsgProducer();
this.otaPackageStateMsgProducer = coreQueueFactory.createToOtaPackageStateServiceMsgProducer();
}
@Override
@ -105,14 +104,14 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
}
private void updateFirmware(Device device, Device oldDevice) {
FirmwareId newFirmwareId = device.getFirmwareId();
OtaPackageId newFirmwareId = device.getFirmwareId();
if (newFirmwareId == null) {
DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
newFirmwareId = newDeviceProfile.getFirmwareId();
}
if (oldDevice != null) {
if (newFirmwareId != null) {
FirmwareId oldFirmwareId = oldDevice.getFirmwareId();
OtaPackageId oldFirmwareId = oldDevice.getFirmwareId();
if (oldFirmwareId == null) {
DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId());
oldFirmwareId = oldDeviceProfile.getFirmwareId();
@ -132,14 +131,14 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
}
private void updateSoftware(Device device, Device oldDevice) {
FirmwareId newSoftwareId = device.getSoftwareId();
OtaPackageId newSoftwareId = device.getSoftwareId();
if (newSoftwareId == null) {
DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
newSoftwareId = newDeviceProfile.getSoftwareId();
}
if (oldDevice != null) {
if (newSoftwareId != null) {
FirmwareId oldSoftwareId = oldDevice.getSoftwareId();
OtaPackageId oldSoftwareId = oldDevice.getSoftwareId();
if (oldSoftwareId == null) {
DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId());
oldSoftwareId = oldDeviceProfile.getSoftwareId();
@ -170,33 +169,20 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
}
}
private void update(TenantId tenantId, DeviceProfile deviceProfile, FirmwareType firmwareType) {
Function<PageLink, PageData<Device>> getDevicesFunction;
private void update(TenantId tenantId, DeviceProfile deviceProfile, OtaPackageType otaPackageType) {
Consumer<Device> updateConsumer;
switch (firmwareType) {
case FIRMWARE:
getDevicesFunction = pl -> deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pl);
break;
case SOFTWARE:
getDevicesFunction = pl -> deviceService.findDevicesByTenantIdAndTypeAndEmptySoftware(tenantId, deviceProfile.getName(), pl);
break;
default:
log.warn("Unsupported firmware type: [{}]", firmwareType);
return;
}
if (deviceProfile.getFirmwareId() != null) {
long ts = System.currentTimeMillis();
updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts, firmwareType);
updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts, otaPackageType);
} else {
updateConsumer = d -> remove(d, firmwareType);
updateConsumer = d -> remove(d, otaPackageType);
}
PageLink pageLink = new PageLink(100);
PageData<Device> pageData;
do {
pageData = getDevicesFunction.apply(pageLink);
pageData = deviceService.findDevicesByTenantIdAndTypeAndEmptyOtaPackage(tenantId, deviceProfile.getId(), otaPackageType, pageLink);
pageData.getData().forEach(updateConsumer);
if (pageData.hasNext()) {
@ -206,60 +192,60 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
}
@Override
public boolean process(ToFirmwareStateServiceMsg msg) {
public boolean process(ToOtaPackageStateServiceMsg msg) {
boolean isSuccess = false;
FirmwareId targetFirmwareId = new FirmwareId(new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB()));
OtaPackageId targetOtaPackageId = new OtaPackageId(new UUID(msg.getOtaPackageIdMSB(), msg.getOtaPackageIdLSB()));
DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB()));
TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
FirmwareType firmwareType = FirmwareType.valueOf(msg.getType());
OtaPackageType firmwareType = OtaPackageType.valueOf(msg.getType());
long ts = msg.getTs();
Device device = deviceService.findDeviceById(tenantId, deviceId);
if (device == null) {
log.warn("[{}] [{}] Device was removed during firmware update msg was queued!", tenantId, deviceId);
} else {
FirmwareId currentFirmwareId = FirmwareUtil.getFirmwareId(device, firmwareType);
if (currentFirmwareId == null) {
OtaPackageId currentOtaPackageId = OtaPackageUtil.getOtaPackageId(device, firmwareType);
if (currentOtaPackageId == null) {
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId());
currentFirmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType);
currentOtaPackageId = OtaPackageUtil.getOtaPackageId(deviceProfile, firmwareType);
}
if (targetFirmwareId.equals(currentFirmwareId)) {
update(device, firmwareService.findFirmwareInfoById(device.getTenantId(), targetFirmwareId), ts);
if (targetOtaPackageId.equals(currentOtaPackageId)) {
update(device, otaPackageService.findOtaPackageInfoById(device.getTenantId(), targetOtaPackageId), ts);
isSuccess = true;
} else {
log.warn("[{}] [{}] Can`t update firmware for the device, target firmwareId: [{}], current firmwareId: [{}]!", tenantId, deviceId, targetFirmwareId, currentFirmwareId);
log.warn("[{}] [{}] Can`t update firmware for the device, target firmwareId: [{}], current firmwareId: [{}]!", tenantId, deviceId, targetOtaPackageId, currentOtaPackageId);
}
}
return isSuccess;
}
private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts, FirmwareType firmwareType) {
ToFirmwareStateServiceMsg msg = ToFirmwareStateServiceMsg.newBuilder()
private void send(TenantId tenantId, DeviceId deviceId, OtaPackageId firmwareId, long ts, OtaPackageType firmwareType) {
ToOtaPackageStateServiceMsg msg = ToOtaPackageStateServiceMsg.newBuilder()
.setTenantIdMSB(tenantId.getId().getMostSignificantBits())
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
.setDeviceIdMSB(deviceId.getId().getMostSignificantBits())
.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits())
.setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits())
.setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits())
.setOtaPackageIdMSB(firmwareId.getId().getMostSignificantBits())
.setOtaPackageIdLSB(firmwareId.getId().getLeastSignificantBits())
.setType(firmwareType.name())
.setTs(ts)
.build();
FirmwareInfo firmware = firmwareService.findFirmwareInfoById(tenantId, firmwareId);
OtaPackageInfo firmware = otaPackageService.findOtaPackageInfoById(tenantId, firmwareId);
if (firmware == null) {
log.warn("[{}] Failed to send firmware update because firmware was already deleted", firmwareId);
return;
}
TopicPartitionInfo tpi = new TopicPartitionInfo(fwStateMsgProducer.getDefaultTopic(), null, null, false);
fwStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null);
TopicPartitionInfo tpi = new TopicPartitionInfo(otaPackageStateMsgProducer.getDefaultTopic(), null, null, false);
otaPackageStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null);
List<TsKvEntry> telemetry = new ArrayList<>();
telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), TITLE), firmware.getTitle())));
telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTargetTelemetryKey(firmware.getType(), VERSION), firmware.getVersion())));
telemetry.add(new BasicTsKvEntry(ts, new LongDataEntry(getTargetTelemetryKey(firmware.getType(), TS), ts)));
telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), FirmwareUpdateStatus.QUEUED.name())));
telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), OtaPackageUpdateStatus.QUEUED.name())));
telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() {
@Override
@ -275,11 +261,11 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
}
private void update(Device device, FirmwareInfo firmware, long ts) {
private void update(Device device, OtaPackageInfo firmware, long ts) {
TenantId tenantId = device.getTenantId();
DeviceId deviceId = device.getId();
BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), FirmwareUpdateStatus.INITIATED.name()));
BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(getTelemetryKey(firmware.getType(), STATE), OtaPackageUpdateStatus.INITIATED.name()));
telemetryService.saveAndNotify(tenantId, deviceId, Collections.singletonList(status), new FutureCallback<>() {
@Override
@ -313,14 +299,14 @@ public class DefaultFirmwareStateService implements FirmwareStateService {
});
}
private void remove(Device device, FirmwareType firmwareType) {
telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, FirmwareUtil.getAttributeKeys(firmwareType),
private void remove(Device device, OtaPackageType firmwareType) {
telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, OtaPackageUtil.getAttributeKeys(firmwareType),
new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Void tmp) {
log.trace("[{}] Success remove target firmware attributes!", device.getId());
Set<AttributeKey> keysToNotify = new HashSet<>();
FirmwareUtil.ALL_FW_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key)));
OtaPackageUtil.ALL_FW_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key)));
tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(device.getTenantId(), device.getId(), keysToNotify), null);
}

8
application/src/main/java/org/thingsboard/server/service/firmware/FirmwareStateService.java → application/src/main/java/org/thingsboard/server/service/ota/OtaPackageStateService.java

@ -13,18 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.firmware;
package org.thingsboard.server.service.ota;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
public interface FirmwareStateService {
public interface OtaPackageStateService {
void update(Device device, Device oldDevice);
void update(DeviceProfile deviceProfile, boolean isFirmwareChanged, boolean isSoftwareChanged);
boolean process(ToFirmwareStateServiceMsg msg);
boolean process(ToOtaPackageStateServiceMsg msg);
}

31
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java

@ -50,7 +50,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionCloseP
import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdateProto;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
import org.thingsboard.server.queue.TbQueueConsumer;
@ -60,7 +60,7 @@ import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.firmware.FirmwareStateService;
import org.thingsboard.server.service.ota.OtaPackageStateService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.queue.processing.AbstractConsumerService;
import org.thingsboard.server.service.queue.processing.IdMsgPair;
@ -75,7 +75,6 @@ import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWra
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@ -101,9 +100,9 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
@Value("${queue.core.stats.enabled:false}")
private boolean statsEnabled;
@Value("${queue.core.firmware.pack-interval-ms:60000}")
@Value("${queue.core.ota.pack-interval-ms:60000}")
private long firmwarePackInterval;
@Value("${queue.core.firmware.pack-size:100}")
@Value("${queue.core.ota.pack-size:100}")
private int firmwarePackSize;
private final TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> mainConsumer;
@ -113,10 +112,10 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
private final SubscriptionManagerService subscriptionManagerService;
private final TbCoreDeviceRpcService tbCoreDeviceRpcService;
private final EdgeNotificationService edgeNotificationService;
private final FirmwareStateService firmwareStateService;
private final OtaPackageStateService firmwareStateService;
private final TbCoreConsumerStats stats;
protected final TbQueueConsumer<TbProtoQueueMsg<ToUsageStatsServiceMsg>> usageStatsConsumer;
private final TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> firmwareStatesConsumer;
private final TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> firmwareStatesConsumer;
protected volatile ExecutorService usageStatsExecutor;
@ -135,11 +134,11 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
TbTenantProfileCache tenantProfileCache,
TbApiUsageStateService apiUsageStateService,
EdgeNotificationService edgeNotificationService,
FirmwareStateService firmwareStateService) {
OtaPackageStateService firmwareStateService) {
super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, apiUsageStateService, tbCoreQueueFactory.createToCoreNotificationsMsgConsumer());
this.mainConsumer = tbCoreQueueFactory.createToCoreMsgConsumer();
this.usageStatsConsumer = tbCoreQueueFactory.createToUsageStatsServiceMsgConsumer();
this.firmwareStatesConsumer = tbCoreQueueFactory.createToFirmwareStateServiceMsgConsumer();
this.firmwareStatesConsumer = tbCoreQueueFactory.createToOtaPackageStateServiceMsgConsumer();
this.stateService = stateService;
this.localSubscriptionService = localSubscriptionService;
this.subscriptionManagerService = subscriptionManagerService;
@ -173,7 +172,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
public void onApplicationEvent(ApplicationReadyEvent event) {
super.onApplicationEvent(event);
launchUsageStatsConsumer();
launchFirmwareUpdateNotificationConsumer();
launchOtaPackageUpdateNotificationConsumer();
}
@Override
@ -361,20 +360,20 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
});
}
private void launchFirmwareUpdateNotificationConsumer() {
private void launchOtaPackageUpdateNotificationConsumer() {
long maxProcessingTimeoutPerRecord = firmwarePackInterval / firmwarePackSize;
firmwareStatesExecutor.submit(() -> {
while (!stopped) {
try {
List<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> msgs = firmwareStatesConsumer.poll(getNotificationPollDuration());
List<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> msgs = firmwareStatesConsumer.poll(getNotificationPollDuration());
if (msgs.isEmpty()) {
continue;
}
long timeToSleep = maxProcessingTimeoutPerRecord;
for (TbProtoQueueMsg<ToFirmwareStateServiceMsg> msg : msgs) {
for (TbProtoQueueMsg<ToOtaPackageStateServiceMsg> msg : msgs) {
try {
long startTime = System.currentTimeMillis();
boolean isSuccessUpdate = handleFirmwareUpdates(msg);
boolean isSuccessUpdate = handleOtaPackageUpdates(msg);
long endTime = System.currentTimeMillis();
long spentTime = endTime - startTime;
timeToSleep = timeToSleep - spentTime;
@ -402,7 +401,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
}
}
}
log.info("TB Firmware States Consumer stopped.");
log.info("TB Ota Package States Consumer stopped.");
});
}
@ -410,7 +409,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
statsService.process(msg, callback);
}
private boolean handleFirmwareUpdates(TbProtoQueueMsg<ToFirmwareStateServiceMsg> msg) {
private boolean handleOtaPackageUpdates(TbProtoQueueMsg<ToOtaPackageStateServiceMsg> msg) {
return firmwareStateService.process(msg.getValue());
}

24
application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java

@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
@ -46,7 +46,7 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TbResourceId;
@ -63,7 +63,7 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
@ -135,7 +135,7 @@ public class AccessValidator {
protected ResourceService resourceService;
@Autowired
protected FirmwareService firmwareService;
protected OtaPackageService otaPackageService;
private ExecutorService executor;
@ -232,8 +232,8 @@ public class AccessValidator {
case TB_RESOURCE:
validateResource(currentUser, operation, entityId, callback);
return;
case FIRMWARE:
validateFirmware(currentUser, operation, entityId, callback);
case OTA_PACKAGE:
validateOtaPackage(currentUser, operation, entityId, callback);
return;
default:
//TODO: add support of other entities
@ -300,20 +300,20 @@ public class AccessValidator {
}
}
private void validateFirmware(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
private void validateOtaPackage(final SecurityUser currentUser, Operation operation, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
FirmwareInfo firmware = firmwareService.findFirmwareInfoById(currentUser.getTenantId(), new FirmwareId(entityId.getId()));
if (firmware == null) {
callback.onSuccess(ValidationResult.entityNotFound("Firmware with requested id wasn't found!"));
OtaPackageInfo otaPackage = otaPackageService.findOtaPackageInfoById(currentUser.getTenantId(), new OtaPackageId(entityId.getId()));
if (otaPackage == null) {
callback.onSuccess(ValidationResult.entityNotFound("OtaPackage with requested id wasn't found!"));
} else {
try {
accessControlService.checkPermission(currentUser, Resource.FIRMWARE, operation, entityId, firmware);
accessControlService.checkPermission(currentUser, Resource.OTA_PACKAGE, operation, entityId, otaPackage);
} catch (ThingsboardException e) {
callback.onSuccess(ValidationResult.accessDenied(e.getMessage()));
}
callback.onSuccess(ValidationResult.ok(firmware));
callback.onSuccess(ValidationResult.ok(otaPackage));
}
}
}

2
application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java

@ -38,7 +38,7 @@ public enum Resource {
DEVICE_PROFILE(EntityType.DEVICE_PROFILE),
API_USAGE_STATE(EntityType.API_USAGE_STATE),
TB_RESOURCE(EntityType.TB_RESOURCE),
FIRMWARE(EntityType.FIRMWARE),
OTA_PACKAGE(EntityType.OTA_PACKAGE),
EDGE(EntityType.EDGE);
private final EntityType entityType;

2
application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java

@ -42,7 +42,7 @@ public class TenantAdminPermissions extends AbstractPermissions {
put(Resource.DEVICE_PROFILE, tenantEntityPermissionChecker);
put(Resource.API_USAGE_STATE, tenantEntityPermissionChecker);
put(Resource.TB_RESOURCE, tbResourcePermissionChecker);
put(Resource.FIRMWARE, tenantEntityPermissionChecker);
put(Resource.OTA_PACKAGE, tenantEntityPermissionChecker);
put(Resource.EDGE, tenantEntityPermissionChecker);
}

68
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -26,27 +26,27 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cache.firmware.FirmwareDataCache;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData;
import org.thingsboard.server.common.data.device.profile.ProvisionDeviceProfileCredentials;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.FirmwareUtil;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -64,7 +64,7 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
import org.thingsboard.server.dao.device.provision.ProvisionRequest;
import org.thingsboard.server.dao.device.provision.ProvisionResponse;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -124,8 +124,8 @@ public class DefaultTransportApiService implements TransportApiService {
private final DataDecodingEncodingService dataDecodingEncodingService;
private final DeviceProvisionService deviceProvisionService;
private final TbResourceService resourceService;
private final FirmwareService firmwareService;
private final FirmwareDataCache firmwareDataCache;
private final OtaPackageService otaPackageService;
private final OtaPackageDataCache otaPackageDataCache;
private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
@ -134,7 +134,7 @@ public class DefaultTransportApiService implements TransportApiService {
RelationService relationService, DeviceCredentialsService deviceCredentialsService,
DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
DeviceProvisionService deviceProvisionService, TbResourceService resourceService, FirmwareService firmwareService, FirmwareDataCache firmwareDataCache) {
DeviceProvisionService deviceProvisionService, TbResourceService resourceService, OtaPackageService otaPackageService, OtaPackageDataCache otaPackageDataCache) {
this.deviceProfileCache = deviceProfileCache;
this.tenantProfileCache = tenantProfileCache;
this.apiUsageStateService = apiUsageStateService;
@ -147,8 +147,8 @@ public class DefaultTransportApiService implements TransportApiService {
this.dataDecodingEncodingService = dataDecodingEncodingService;
this.deviceProvisionService = deviceProvisionService;
this.resourceService = resourceService;
this.firmwareService = firmwareService;
this.firmwareDataCache = firmwareDataCache;
this.otaPackageService = otaPackageService;
this.otaPackageDataCache = otaPackageDataCache;
}
@Override
@ -184,8 +184,8 @@ public class DefaultTransportApiService implements TransportApiService {
result = handle(transportApiRequestMsg.getDeviceRequestMsg());
} else if (transportApiRequestMsg.hasDeviceCredentialsRequestMsg()) {
result = handle(transportApiRequestMsg.getDeviceCredentialsRequestMsg());
} else if (transportApiRequestMsg.hasFirmwareRequestMsg()) {
result = handle(transportApiRequestMsg.getFirmwareRequestMsg());
} else if (transportApiRequestMsg.hasOtaPackageRequestMsg()) {
result = handle(transportApiRequestMsg.getOtaPackageRequestMsg());
}
return Futures.transform(Optional.ofNullable(result).orElseGet(this::getEmptyTransportApiResponseFuture),
@ -511,50 +511,50 @@ public class DefaultTransportApiService implements TransportApiService {
}
}
private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetFirmwareRequestMsg requestMsg) {
private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.GetOtaPackageRequestMsg requestMsg) {
TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB()));
FirmwareType firmwareType = FirmwareType.valueOf(requestMsg.getType());
OtaPackageType otaPackageType = OtaPackageType.valueOf(requestMsg.getType());
Device device = deviceService.findDeviceById(tenantId, deviceId);
if (device == null) {
return getEmptyTransportApiResponseFuture();
}
FirmwareId firmwareId = FirmwareUtil.getFirmwareId(device, firmwareType);
if (firmwareId == null) {
OtaPackageId otaPackageId = OtaPackageUtil.getOtaPackageId(device, otaPackageType);
if (otaPackageId == null) {
DeviceProfile deviceProfile = deviceProfileCache.find(device.getDeviceProfileId());
firmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType);
otaPackageId = OtaPackageUtil.getOtaPackageId(deviceProfile, otaPackageType);
}
TransportProtos.GetFirmwareResponseMsg.Builder builder = TransportProtos.GetFirmwareResponseMsg.newBuilder();
TransportProtos.GetOtaPackageResponseMsg.Builder builder = TransportProtos.GetOtaPackageResponseMsg.newBuilder();
if (firmwareId == null) {
if (otaPackageId == null) {
builder.setResponseStatus(TransportProtos.ResponseStatus.NOT_FOUND);
} else {
FirmwareInfo firmwareInfo = firmwareService.findFirmwareInfoById(tenantId, firmwareId);
OtaPackageInfo otaPackageInfo = otaPackageService.findOtaPackageInfoById(tenantId, otaPackageId);
if (firmwareInfo == null) {
if (otaPackageInfo == null) {
builder.setResponseStatus(TransportProtos.ResponseStatus.NOT_FOUND);
} else {
builder.setResponseStatus(TransportProtos.ResponseStatus.SUCCESS);
builder.setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits());
builder.setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits());
builder.setType(firmwareInfo.getType().name());
builder.setTitle(firmwareInfo.getTitle());
builder.setVersion(firmwareInfo.getVersion());
builder.setFileName(firmwareInfo.getFileName());
builder.setContentType(firmwareInfo.getContentType());
if (!firmwareDataCache.has(firmwareId.toString())) {
Firmware firmware = firmwareService.findFirmwareById(tenantId, firmwareId);
firmwareDataCache.put(firmwareId.toString(), firmware.getData().array());
builder.setOtaPackageIdMSB(otaPackageId.getId().getMostSignificantBits());
builder.setOtaPackageIdLSB(otaPackageId.getId().getLeastSignificantBits());
builder.setType(otaPackageInfo.getType().name());
builder.setTitle(otaPackageInfo.getTitle());
builder.setVersion(otaPackageInfo.getVersion());
builder.setFileName(otaPackageInfo.getFileName());
builder.setContentType(otaPackageInfo.getContentType());
if (!otaPackageDataCache.has(otaPackageId.toString())) {
OtaPackage otaPackage = otaPackageService.findOtaPackageById(tenantId, otaPackageId);
otaPackageDataCache.put(otaPackageId.toString(), otaPackage.getData().array());
}
}
}
return Futures.immediateFuture(
TransportApiResponseMsg.newBuilder()
.setFirmwareResponseMsg(builder.build())
.setOtaPackageResponseMsg(builder.build())
.build());
}

19
application/src/main/resources/thingsboard.yml

@ -371,7 +371,10 @@ caffeine:
tokensOutdatageTime:
timeToLiveInMinutes: 20000
maxSize: 10000
firmwares:
otaPackages:
timeToLiveInMinutes: 60
maxSize: 10
otaPackagesData:
timeToLiveInMinutes: 60
maxSize: 10
edges:
@ -497,7 +500,7 @@ audit-log:
"device_profile": "${AUDIT_LOG_MASK_DEVICE_PROFILE:W}"
"edge": "${AUDIT_LOG_MASK_EDGE:W}"
"tb_resource": "${AUDIT_LOG_MASK_RESOURCE:W}"
"firmware": "${AUDIT_LOG_MASK_FIRMWARE:W}"
"ota_package": "${AUDIT_LOG_MASK_OTA_PACKAGE:W}"
sink:
# Type of external sink. possible options: none, elasticsearch
type: "${AUDIT_LOG_SINK_TYPE:none}"
@ -749,7 +752,7 @@ queue:
sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}"
security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}"
consumer-properties-per-topic:
tb_firmware:
tb_ota_package:
- key: max.poll.records
value: 10
other:
@ -759,7 +762,7 @@ queue:
transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100;min.insync.replicas:1}"
fw-updates: "${TB_QUEUE_KAFKA_FW_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}"
ota-updates: "${TB_QUEUE_KAFKA_OTA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}"
consumer-stats:
enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}"
print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}"
@ -830,10 +833,10 @@ queue:
poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}"
partitions: "${TB_QUEUE_CORE_PARTITIONS:10}"
pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:2000}"
firmware:
topic: "${TB_QUEUE_CORE_FW_TOPIC:tb_firmware}"
pack-interval-ms: "${TB_QUEUE_CORE_FW_PACK_INTERVAL_MS:60000}"
pack-size: "${TB_QUEUE_CORE_FW_PACK_SIZE:100}"
ota:
topic: "${TB_QUEUE_CORE_OTA_TOPIC:tb_ota_package}"
pack-interval-ms: "${TB_QUEUE_CORE_OTA_PACK_INTERVAL_MS:60000}"
pack-size: "${TB_QUEUE_CORE_OTA_PACK_SIZE:100}"
usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}"
stats:
enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}"

115
application/src/test/java/org/thingsboard/server/controller/BaseFirmwareControllerTest.java → application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java

@ -25,11 +25,10 @@ import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequ
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -41,11 +40,11 @@ import java.util.Collections;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
public abstract class BaseFirmwareControllerTest extends AbstractControllerTest {
public abstract class BaseOtaPackageControllerTest extends AbstractControllerTest {
private IdComparator<FirmwareInfo> idComparator = new IdComparator<>();
private IdComparator<OtaPackageInfo> idComparator = new IdComparator<>();
public static final String TITLE = "My firmware";
private static final String FILE_NAME = "filename.txt";
@ -93,13 +92,13 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
@Test
public void testSaveFirmware() throws Exception {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
Assert.assertNotNull(savedFirmwareInfo);
Assert.assertNotNull(savedFirmwareInfo.getId());
@ -112,19 +111,19 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
save(savedFirmwareInfo);
FirmwareInfo foundFirmwareInfo = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class);
OtaPackageInfo foundFirmwareInfo = doGet("/api/otaPackage/info/" + savedFirmwareInfo.getId().getId().toString(), OtaPackageInfo.class);
Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle());
}
@Test
public void testSaveFirmwareData() throws Exception {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
Assert.assertNotNull(savedFirmwareInfo);
Assert.assertNotNull(savedFirmwareInfo.getId());
@ -137,12 +136,12 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
save(savedFirmwareInfo);
FirmwareInfo foundFirmwareInfo = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class);
OtaPackageInfo foundFirmwareInfo = doGet("/api/otaPackage/info/" + savedFirmwareInfo.getId().getId().toString(), OtaPackageInfo.class);
Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle());
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array());
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
OtaPackage savedFirmware = savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
Assert.assertEquals(FILE_NAME, savedFirmware.getFileName());
Assert.assertEquals(CONTENT_TYPE, savedFirmware.getContentType());
@ -150,97 +149,97 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
@Test
public void testUpdateFirmwareFromDifferentTenant() throws Exception {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
loginDifferentTenant();
doPost("/api/firmware", savedFirmwareInfo, FirmwareInfo.class, status().isForbidden());
doPost("/api/otaPackage", savedFirmwareInfo, OtaPackageInfo.class, status().isForbidden());
deleteDifferentTenant();
}
@Test
public void testFindFirmwareInfoById() throws Exception {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
FirmwareInfo foundFirmware = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class);
OtaPackageInfo foundFirmware = doGet("/api/otaPackage/info/" + savedFirmwareInfo.getId().getId().toString(), OtaPackageInfo.class);
Assert.assertNotNull(foundFirmware);
Assert.assertEquals(savedFirmwareInfo, foundFirmware);
}
@Test
public void testFindFirmwareById() throws Exception {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array());
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
OtaPackage savedFirmware = savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
Firmware foundFirmware = doGet("/api/firmware/" + savedFirmwareInfo.getId().getId().toString(), Firmware.class);
OtaPackage foundFirmware = doGet("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString(), OtaPackage.class);
Assert.assertNotNull(foundFirmware);
Assert.assertEquals(savedFirmware, foundFirmware);
}
@Test
public void testDeleteFirmware() throws Exception {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
doDelete("/api/firmware/" + savedFirmwareInfo.getId().getId().toString())
doDelete("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString())
.andExpect(status().isOk());
doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString())
doGet("/api/otaPackage/info/" + savedFirmwareInfo.getId().getId().toString())
.andExpect(status().isNotFound());
}
@Test
public void testFindTenantFirmwares() throws Exception {
List<FirmwareInfo> firmwares = new ArrayList<>();
List<OtaPackageInfo> otaPackages = new ArrayList<>();
for (int i = 0; i < 165; i++) {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION + i);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
if (i > 100) {
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array());
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
firmwares.add(new FirmwareInfo(savedFirmware));
OtaPackage savedFirmware = savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
otaPackages.add(new OtaPackageInfo(savedFirmware));
} else {
firmwares.add(savedFirmwareInfo);
otaPackages.add(savedFirmwareInfo);
}
}
List<FirmwareInfo> loadedFirmwares = new ArrayList<>();
List<OtaPackageInfo> loadedFirmwares = new ArrayList<>();
PageLink pageLink = new PageLink(24);
PageData<FirmwareInfo> pageData;
PageData<OtaPackageInfo> pageData;
do {
pageData = doGetTypedWithPageLink("/api/firmwares?",
pageData = doGetTypedWithPageLink("/api/otaPackages?",
new TypeReference<>() {
}, pageLink);
loadedFirmwares.addAll(pageData.getData());
@ -249,41 +248,41 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
}
} while (pageData.hasNext());
Collections.sort(firmwares, idComparator);
Collections.sort(otaPackages, idComparator);
Collections.sort(loadedFirmwares, idComparator);
Assert.assertEquals(firmwares, loadedFirmwares);
Assert.assertEquals(otaPackages, loadedFirmwares);
}
@Test
public void testFindTenantFirmwaresByHasData() throws Exception {
List<FirmwareInfo> firmwaresWithData = new ArrayList<>();
List<FirmwareInfo> firmwaresWithoutData = new ArrayList<>();
List<OtaPackageInfo> otaPackagesWithData = new ArrayList<>();
List<OtaPackageInfo> otaPackagesWithoutData = new ArrayList<>();
for (int i = 0; i < 165; i++) {
FirmwareInfo firmwareInfo = new FirmwareInfo();
OtaPackageInfo firmwareInfo = new OtaPackageInfo();
firmwareInfo.setDeviceProfileId(deviceProfileId);
firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION + i);
FirmwareInfo savedFirmwareInfo = save(firmwareInfo);
OtaPackageInfo savedFirmwareInfo = save(firmwareInfo);
if (i > 100) {
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array());
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
firmwaresWithData.add(new FirmwareInfo(savedFirmware));
OtaPackage savedFirmware = savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM);
otaPackagesWithData.add(new OtaPackageInfo(savedFirmware));
} else {
firmwaresWithoutData.add(savedFirmwareInfo);
otaPackagesWithoutData.add(savedFirmwareInfo);
}
}
List<FirmwareInfo> loadedFirmwaresWithData = new ArrayList<>();
List<OtaPackageInfo> loadedFirmwaresWithData = new ArrayList<>();
PageLink pageLink = new PageLink(24);
PageData<FirmwareInfo> pageData;
PageData<OtaPackageInfo> pageData;
do {
pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/true?",
pageData = doGetTypedWithPageLink("/api/otaPackages/" + deviceProfileId.toString() + "/FIRMWARE/true?",
new TypeReference<>() {
}, pageLink);
loadedFirmwaresWithData.addAll(pageData.getData());
@ -292,10 +291,10 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
}
} while (pageData.hasNext());
List<FirmwareInfo> loadedFirmwaresWithoutData = new ArrayList<>();
List<OtaPackageInfo> loadedFirmwaresWithoutData = new ArrayList<>();
pageLink = new PageLink(24);
do {
pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/false?",
pageData = doGetTypedWithPageLink("/api/otaPackages/" + deviceProfileId.toString() + "/FIRMWARE/false?",
new TypeReference<>() {
}, pageLink);
loadedFirmwaresWithoutData.addAll(pageData.getData());
@ -304,25 +303,25 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest
}
} while (pageData.hasNext());
Collections.sort(firmwaresWithData, idComparator);
Collections.sort(firmwaresWithoutData, idComparator);
Collections.sort(otaPackagesWithData, idComparator);
Collections.sort(otaPackagesWithoutData, idComparator);
Collections.sort(loadedFirmwaresWithData, idComparator);
Collections.sort(loadedFirmwaresWithoutData, idComparator);
Assert.assertEquals(firmwaresWithData, loadedFirmwaresWithData);
Assert.assertEquals(firmwaresWithoutData, loadedFirmwaresWithoutData);
Assert.assertEquals(otaPackagesWithData, loadedFirmwaresWithData);
Assert.assertEquals(otaPackagesWithoutData, loadedFirmwaresWithoutData);
}
private FirmwareInfo save(FirmwareInfo firmwareInfo) throws Exception {
return doPost("/api/firmware", firmwareInfo, FirmwareInfo.class);
private OtaPackageInfo save(OtaPackageInfo firmwareInfo) throws Exception {
return doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class);
}
protected Firmware savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception {
protected OtaPackage savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception {
MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params);
postRequest.file(content);
setJwtToken(postRequest);
return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), Firmware.class);
return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), OtaPackage.class);
}
}

4
application/src/test/java/org/thingsboard/server/controller/sql/FirmwareControllerSqlTest.java → application/src/test/java/org/thingsboard/server/controller/sql/OtaPackageControllerSqlTest.java

@ -15,9 +15,9 @@
*/
package org.thingsboard.server.controller.sql;
import org.thingsboard.server.controller.BaseFirmwareControllerTest;
import org.thingsboard.server.controller.BaseOtaPackageControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
@DaoSqlTest
public class FirmwareControllerSqlTest extends BaseFirmwareControllerTest {
public class OtaPackageControllerSqlTest extends BaseOtaPackageControllerTest {
}

13
common/cache/src/main/java/org/thingsboard/server/cache/firmware/CaffeineFirmwareCache.java → common/cache/src/main/java/org/thingsboard/server/cache/ota/CaffeineOtaPackageCache.java

@ -13,19 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.cache.firmware;
package org.thingsboard.server.cache.ota;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE;
import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_CACHE;
import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_DATA_CACHE;
@Service
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
@RequiredArgsConstructor
public class CaffeineFirmwareCache implements FirmwareDataCache {
public class CaffeineOtaPackageCache implements OtaPackageDataCache {
private final CacheManager cacheManager;
@ -36,7 +37,7 @@ public class CaffeineFirmwareCache implements FirmwareDataCache {
@Override
public byte[] get(String key, int chunkSize, int chunk) {
byte[] data = cacheManager.getCache(FIRMWARE_CACHE).get(key, byte[].class);
byte[] data = cacheManager.getCache(OTA_PACKAGE_DATA_CACHE).get(key, byte[].class);
if (chunkSize < 1) {
return data;
@ -58,11 +59,11 @@ public class CaffeineFirmwareCache implements FirmwareDataCache {
@Override
public void put(String key, byte[] value) {
cacheManager.getCache(FIRMWARE_CACHE).putIfAbsent(key, value);
cacheManager.getCache(OTA_PACKAGE_DATA_CACHE).putIfAbsent(key, value);
}
@Override
public void evict(String key) {
cacheManager.getCache(FIRMWARE_CACHE).evict(key);
cacheManager.getCache(OTA_PACKAGE_DATA_CACHE).evict(key);
}
}

8
common/cache/src/main/java/org/thingsboard/server/cache/firmware/FirmwareDataCache.java → common/cache/src/main/java/org/thingsboard/server/cache/ota/OtaPackageDataCache.java

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.cache.firmware;
package org.thingsboard.server.cache.ota;
public interface FirmwareDataCache {
public interface OtaPackageDataCache {
byte[] get(String key);
@ -25,8 +25,8 @@ public interface FirmwareDataCache {
void evict(String key);
default boolean has(String firmwareId) {
byte[] data = get(firmwareId, 1, 0);
default boolean has(String otaPackageId) {
byte[] data = get(otaPackageId, 1, 0);
return data != null && data.length > 0;
}
}

19
common/cache/src/main/java/org/thingsboard/server/cache/firmware/RedisFirmwareDataCache.java → common/cache/src/main/java/org/thingsboard/server/cache/ota/RedisOtaPackageDataCache.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.cache.firmware;
package org.thingsboard.server.cache.ota;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -21,12 +21,13 @@ import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Service;
import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE;
import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_CACHE;
import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_DATA_CACHE;
@Service
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
@RequiredArgsConstructor
public class RedisFirmwareDataCache implements FirmwareDataCache {
public class RedisOtaPackageDataCache implements OtaPackageDataCache {
private final RedisConnectionFactory redisConnectionFactory;
@ -39,30 +40,30 @@ public class RedisFirmwareDataCache implements FirmwareDataCache {
public byte[] get(String key, int chunkSize, int chunk) {
try (RedisConnection connection = redisConnectionFactory.getConnection()) {
if (chunkSize == 0) {
return connection.get(toFirmwareCacheKey(key));
return connection.get(toOtaPackageCacheKey(key));
}
int startIndex = chunkSize * chunk;
int endIndex = startIndex + chunkSize - 1;
return connection.getRange(toFirmwareCacheKey(key), startIndex, endIndex);
return connection.getRange(toOtaPackageCacheKey(key), startIndex, endIndex);
}
}
@Override
public void put(String key, byte[] value) {
try (RedisConnection connection = redisConnectionFactory.getConnection()) {
connection.set(toFirmwareCacheKey(key), value);
connection.set(toOtaPackageCacheKey(key), value);
}
}
@Override
public void evict(String key) {
try (RedisConnection connection = redisConnectionFactory.getConnection()) {
connection.del(toFirmwareCacheKey(key));
connection.del(toOtaPackageCacheKey(key));
}
}
private byte[] toFirmwareCacheKey(String key) {
return String.format("%s::%s", FIRMWARE_CACHE, key).getBytes();
private byte[] toOtaPackageCacheKey(String key) {
return String.format("%s::%s", OTA_PACKAGE_DATA_CACHE, key).getBytes();
}
}

5
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java

@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials;
@ -63,9 +64,9 @@ public interface DeviceService {
PageData<Device> findDevicesByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink);
PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink);
PageData<Device> findDevicesByTenantIdAndTypeAndEmptyOtaPackage(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType type, PageLink pageLink);
PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink);
Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType otaPackageType);
PageData<DeviceInfo> findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink);

52
common/dao-api/src/main/java/org/thingsboard/server/dao/firmware/FirmwareService.java

@ -1,52 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.firmware;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import java.nio.ByteBuffer;
public interface FirmwareService {
FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo);
Firmware saveFirmware(Firmware firmware);
String generateChecksum(ChecksumAlgorithm checksumAlgorithm, ByteBuffer data);
Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId);
FirmwareInfo findFirmwareInfoById(TenantId tenantId, FirmwareId firmwareId);
ListenableFuture<FirmwareInfo> findFirmwareInfoByIdAsync(TenantId tenantId, FirmwareId firmwareId);
PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink);
PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink);
void deleteFirmware(TenantId tenantId, FirmwareId firmwareId);
void deleteFirmwaresByTenantId(TenantId tenantId);
}

52
common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java

@ -0,0 +1,52 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.ota;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import java.nio.ByteBuffer;
public interface OtaPackageService {
OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo);
OtaPackage saveOtaPackage(OtaPackage otaPackage);
String generateChecksum(ChecksumAlgorithm checksumAlgorithm, ByteBuffer data);
OtaPackage findOtaPackageById(TenantId tenantId, OtaPackageId otaPackageId);
OtaPackageInfo findOtaPackageInfoById(TenantId tenantId, OtaPackageId otaPackageId);
ListenableFuture<OtaPackageInfo> findOtaPackageInfoByIdAsync(TenantId tenantId, OtaPackageId otaPackageId);
PageData<OtaPackageInfo> findTenantOtaPackagesByTenantId(TenantId tenantId, PageLink pageLink);
PageData<OtaPackageInfo> findTenantOtaPackagesByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType otaPackageType, boolean hasData, PageLink pageLink);
void deleteOtaPackage(TenantId tenantId, OtaPackageId otaPackageId);
void deleteOtaPackagesByTenantId(TenantId tenantId);
}

3
common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java

@ -29,5 +29,6 @@ public class CacheConstants {
public static final String DEVICE_PROFILE_CACHE = "deviceProfiles";
public static final String ATTRIBUTES_CACHE = "attributes";
public static final String TOKEN_OUTDATAGE_TIME_CACHE = "tokensOutdatageTime";
public static final String FIRMWARE_CACHE = "firmwares";
public static final String OTA_PACKAGE_CACHE = "otaPackages";
public static final String OTA_PACKAGE_DATA_CACHE = "otaPackagesData";
}

16
common/data/src/main/java/org/thingsboard/server/common/data/Device.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.NoXss;
@ -32,7 +32,7 @@ import java.io.IOException;
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId, HasFirmware {
public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId, HasOtaPackage {
private static final long serialVersionUID = 2807343040519543363L;
@ -49,8 +49,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
@JsonIgnore
private byte[] deviceDataBytes;
private FirmwareId firmwareId;
private FirmwareId softwareId;
private OtaPackageId firmwareId;
private OtaPackageId softwareId;
public Device() {
super();
@ -167,19 +167,19 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
return getName();
}
public FirmwareId getFirmwareId() {
public OtaPackageId getFirmwareId() {
return firmwareId;
}
public void setFirmwareId(FirmwareId firmwareId) {
public void setFirmwareId(OtaPackageId firmwareId) {
this.firmwareId = firmwareId;
}
public FirmwareId getSoftwareId() {
public OtaPackageId getSoftwareId() {
return softwareId;
}
public void setSoftwareId(FirmwareId softwareId) {
public void setSoftwareId(OtaPackageId softwareId) {
this.softwareId = softwareId;
}

8
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java

@ -23,7 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.NoXss;
@ -37,7 +37,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn
@Data
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId, HasFirmware {
public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId, HasOtaPackage {
private TenantId tenantId;
@NoXss
@ -60,9 +60,9 @@ public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements H
@NoXss
private String provisionDeviceKey;
private FirmwareId firmwareId;
private OtaPackageId firmwareId;
private FirmwareId softwareId;
private OtaPackageId softwareId;
public DeviceProfile() {
super();

2
common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java

@ -19,5 +19,5 @@ package org.thingsboard.server.common.data;
* @author Andrew Shvayka
*/
public enum EntityType {
TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, FIRMWARE, EDGE;
TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE, OTA_PACKAGE, EDGE;
}

8
common/data/src/main/java/org/thingsboard/server/common/data/HasFirmware.java → common/data/src/main/java/org/thingsboard/server/common/data/HasOtaPackage.java

@ -15,11 +15,11 @@
*/
package org.thingsboard.server.common.data;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
public interface HasFirmware {
public interface HasOtaPackage {
FirmwareId getFirmwareId();
OtaPackageId getFirmwareId();
FirmwareId getSoftwareId();
OtaPackageId getSoftwareId();
}

10
common/data/src/main/java/org/thingsboard/server/common/data/Firmware.java → common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java

@ -17,27 +17,27 @@ package org.thingsboard.server.common.data;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import java.nio.ByteBuffer;
@Data
@EqualsAndHashCode(callSuper = true)
public class Firmware extends FirmwareInfo {
public class OtaPackage extends OtaPackageInfo {
private static final long serialVersionUID = 3091601761339422546L;
private transient ByteBuffer data;
public Firmware() {
public OtaPackage() {
super();
}
public Firmware(FirmwareId id) {
public OtaPackage(OtaPackageId id) {
super(id);
}
public Firmware(Firmware firmware) {
public OtaPackage(OtaPackage firmware) {
super(firmware);
this.data = firmware.getData();
}

40
common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java → common/data/src/main/java/org/thingsboard/server/common/data/OtaPackageInfo.java

@ -19,22 +19,22 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId> implements HasName, HasTenantId {
public class OtaPackageInfo extends SearchTextBasedWithAdditionalInfo<OtaPackageId> implements HasName, HasTenantId {
private static final long serialVersionUID = 3168391583570815419L;
private TenantId tenantId;
private DeviceProfileId deviceProfileId;
private FirmwareType type;
private OtaPackageType type;
private String title;
private String version;
private boolean hasData;
@ -45,27 +45,27 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId>
private Long dataSize;
public FirmwareInfo() {
public OtaPackageInfo() {
super();
}
public FirmwareInfo(FirmwareId id) {
public OtaPackageInfo(OtaPackageId id) {
super(id);
}
public FirmwareInfo(FirmwareInfo firmwareInfo) {
super(firmwareInfo);
this.tenantId = firmwareInfo.getTenantId();
this.deviceProfileId = firmwareInfo.getDeviceProfileId();
this.type = firmwareInfo.getType();
this.title = firmwareInfo.getTitle();
this.version = firmwareInfo.getVersion();
this.hasData = firmwareInfo.isHasData();
this.fileName = firmwareInfo.getFileName();
this.contentType = firmwareInfo.getContentType();
this.checksumAlgorithm = firmwareInfo.getChecksumAlgorithm();
this.checksum = firmwareInfo.getChecksum();
this.dataSize = firmwareInfo.getDataSize();
public OtaPackageInfo(OtaPackageInfo otaPackageInfo) {
super(otaPackageInfo);
this.tenantId = otaPackageInfo.getTenantId();
this.deviceProfileId = otaPackageInfo.getDeviceProfileId();
this.type = otaPackageInfo.getType();
this.title = otaPackageInfo.getTitle();
this.version = otaPackageInfo.getVersion();
this.hasData = otaPackageInfo.isHasData();
this.fileName = otaPackageInfo.getFileName();
this.contentType = otaPackageInfo.getContentType();
this.checksumAlgorithm = otaPackageInfo.getChecksumAlgorithm();
this.checksum = otaPackageInfo.getChecksum();
this.dataSize = otaPackageInfo.getDataSize();
}
@Override

4
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java

@ -71,8 +71,8 @@ public class EntityIdFactory {
return new ApiUsageStateId(uuid);
case TB_RESOURCE:
return new TbResourceId(uuid);
case FIRMWARE:
return new FirmwareId(uuid);
case OTA_PACKAGE:
return new OtaPackageId(uuid);
case EDGE:
return new EdgeId(uuid);
}

10
common/data/src/main/java/org/thingsboard/server/common/data/id/FirmwareId.java → common/data/src/main/java/org/thingsboard/server/common/data/id/OtaPackageId.java

@ -22,23 +22,23 @@ import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
public class FirmwareId extends UUIDBased implements EntityId {
public class OtaPackageId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@JsonCreator
public FirmwareId(@JsonProperty("id") UUID id) {
public OtaPackageId(@JsonProperty("id") UUID id) {
super(id);
}
public static FirmwareId fromString(String firmwareId) {
return new FirmwareId(UUID.fromString(firmwareId));
public static OtaPackageId fromString(String firmwareId) {
return new OtaPackageId(UUID.fromString(firmwareId));
}
@JsonIgnore
@Override
public EntityType getEntityType() {
return EntityType.FIRMWARE;
return EntityType.OTA_PACKAGE;
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/firmware/ChecksumAlgorithm.java → common/data/src/main/java/org/thingsboard/server/common/data/ota/ChecksumAlgorithm.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.firmware;
package org.thingsboard.server.common.data.ota;
public enum ChecksumAlgorithm {
MD5,

6
common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKey.java → common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageKey.java

@ -13,18 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.firmware;
package org.thingsboard.server.common.data.ota;
import lombok.Getter;
public enum FirmwareKey {
public enum OtaPackageKey {
TITLE("title"), VERSION("version"), TS("ts"), STATE("state"), SIZE("size"), CHECKSUM("checksum"), CHECKSUM_ALGORITHM("checksum_algorithm");
@Getter
private final String value;
FirmwareKey(String value) {
OtaPackageKey(String value) {
this.value = value;
}
}

6
common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareType.java → common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageType.java

@ -13,18 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.firmware;
package org.thingsboard.server.common.data.ota;
import lombok.Getter;
public enum FirmwareType {
public enum OtaPackageType {
FIRMWARE("fw"), SOFTWARE("sw");
@Getter
private final String keyPrefix;
FirmwareType(String keyPrefix) {
OtaPackageType(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
}

4
common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareUpdateStatus.java → common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageUpdateStatus.java

@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.firmware;
package org.thingsboard.server.common.data.ota;
public enum FirmwareUpdateStatus {
public enum OtaPackageUpdateStatus {
QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
}

49
common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareUtil.java → common/data/src/main/java/org/thingsboard/server/common/data/ota/OtaPackageUtil.java

@ -13,21 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.firmware;
package org.thingsboard.server.common.data.ota;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.HasFirmware;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.HasOtaPackage;
import org.thingsboard.server.common.data.id.OtaPackageId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
import java.util.function.Supplier;
@Slf4j
public class FirmwareUtil {
public class OtaPackageUtil {
public static final List<String> ALL_FW_ATTRIBUTE_KEYS;
@ -35,19 +33,19 @@ public class FirmwareUtil {
static {
ALL_FW_ATTRIBUTE_KEYS = new ArrayList<>();
for (FirmwareKey key : FirmwareKey.values()) {
ALL_FW_ATTRIBUTE_KEYS.add(getAttributeKey(FIRMWARE, key));
for (OtaPackageKey key : OtaPackageKey.values()) {
ALL_FW_ATTRIBUTE_KEYS.add(getAttributeKey(OtaPackageType.FIRMWARE, key));
}
ALL_SW_ATTRIBUTE_KEYS = new ArrayList<>();
for (FirmwareKey key : FirmwareKey.values()) {
ALL_SW_ATTRIBUTE_KEYS.add(getAttributeKey(SOFTWARE, key));
for (OtaPackageKey key : OtaPackageKey.values()) {
ALL_SW_ATTRIBUTE_KEYS.add(getAttributeKey(OtaPackageType.SOFTWARE, key));
}
}
public static List<String> getAttributeKeys(FirmwareType firmwareType) {
public static List<String> getAttributeKeys(OtaPackageType firmwareType) {
switch (firmwareType) {
case FIRMWARE:
return ALL_FW_ATTRIBUTE_KEYS;
@ -57,35 +55,46 @@ public class FirmwareUtil {
return Collections.emptyList();
}
public static String getAttributeKey(FirmwareType type, FirmwareKey key) {
public static String getAttributeKey(OtaPackageType type, OtaPackageKey key) {
return type.getKeyPrefix() + "_" + key.getValue();
}
public static String getTargetTelemetryKey(FirmwareType type, FirmwareKey key) {
public static String getTargetTelemetryKey(OtaPackageType type, OtaPackageKey key) {
return getTelemetryKey("target_", type, key);
}
public static String getCurrentTelemetryKey(FirmwareType type, FirmwareKey key) {
public static String getCurrentTelemetryKey(OtaPackageType type, OtaPackageKey key) {
return getTelemetryKey("current_", type, key);
}
private static String getTelemetryKey(String prefix, FirmwareType type, FirmwareKey key) {
private static String getTelemetryKey(String prefix, OtaPackageType type, OtaPackageKey key) {
return prefix + type.getKeyPrefix() + "_" + key.getValue();
}
public static String getTelemetryKey(FirmwareType type, FirmwareKey key) {
public static String getTelemetryKey(OtaPackageType type, OtaPackageKey key) {
return type.getKeyPrefix() + "_" + key.getValue();
}
public static FirmwareId getFirmwareId(HasFirmware entity, FirmwareType firmwareType) {
switch (firmwareType) {
public static OtaPackageId getOtaPackageId(HasOtaPackage entity, OtaPackageType type) {
switch (type) {
case FIRMWARE:
return entity.getFirmwareId();
case SOFTWARE:
return entity.getSoftwareId();
default:
log.warn("Unsupported firmware type: [{}]", firmwareType);
log.warn("Unsupported ota package type: [{}]", type);
return null;
}
}
public static <T> T getByOtaPackageType(Supplier<T> firmwareSupplier, Supplier<T> softwareSupplier, OtaPackageType type) {
switch (type) {
case FIRMWARE:
return firmwareSupplier.get();
case SOFTWARE:
return softwareSupplier.get();
default:
throw new RuntimeException("Unsupported OtaPackage type: " + type);
}
}
}

2
common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaTopicConfigs.java

@ -38,7 +38,7 @@ public class TbKafkaTopicConfigs {
private String notificationsProperties;
@Value("${queue.kafka.topic-properties.js-executor}")
private String jsExecutorProperties;
@Value("${queue.kafka.topic-properties.fw-updates:}")
@Value("${queue.kafka.topic-properties.ota-updates:}")
private String fwUpdatesProperties;
@Getter

10
common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java

@ -187,14 +187,14 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getOtaPackageTopic());
}
@PreDestroy

12
common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -177,14 +177,14 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory {
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbAwsSqsConsumerTemplate<>(transportApiAdmin, sqsSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, coreSettings.getOtaPackageTopic());
}
@PreDestroy

8
common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java

@ -131,13 +131,13 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new InMemoryTbQueueConsumer<>(coreSettings.getFirmwareTopic());
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new InMemoryTbQueueConsumer<>(coreSettings.getOtaPackageTopic());
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new InMemoryTbQueueProducer<>(coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new InMemoryTbQueueProducer<>(coreSettings.getOtaPackageTopic());
}
@Override

22
common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -277,24 +277,24 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder();
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder();
consumerBuilder.settings(kafkaSettings);
consumerBuilder.topic(coreSettings.getFirmwareTopic());
consumerBuilder.clientId("monolith-fw-consumer-" + serviceInfoProvider.getServiceId());
consumerBuilder.groupId("monolith-fw-consumer");
consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
consumerBuilder.topic(coreSettings.getOtaPackageTopic());
consumerBuilder.clientId("monolith-ota-consumer-" + serviceInfoProvider.getServiceId());
consumerBuilder.groupId("monolith-ota-consumer");
consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
consumerBuilder.admin(fwUpdatesAdmin);
consumerBuilder.statsService(consumerStatsService);
return consumerBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("monolith-fw-producer-" + serviceInfoProvider.getServiceId());
requestBuilder.defaultTopic(coreSettings.getFirmwareTopic());
requestBuilder.clientId("monolith-ota-producer-" + serviceInfoProvider.getServiceId());
requestBuilder.defaultTopic(coreSettings.getOtaPackageTopic());
requestBuilder.admin(fwUpdatesAdmin);
return requestBuilder.build();
}

22
common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -245,24 +245,24 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory {
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder();
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> consumerBuilder = TbKafkaConsumerTemplate.builder();
consumerBuilder.settings(kafkaSettings);
consumerBuilder.topic(coreSettings.getFirmwareTopic());
consumerBuilder.clientId("tb-core-fw-consumer-" + serviceInfoProvider.getServiceId());
consumerBuilder.groupId("tb-core-fw-consumer");
consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
consumerBuilder.topic(coreSettings.getOtaPackageTopic());
consumerBuilder.clientId("tb-core-ota-consumer-" + serviceInfoProvider.getServiceId());
consumerBuilder.groupId("tb-core-ota-consumer");
consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
consumerBuilder.admin(fwUpdatesAdmin);
consumerBuilder.statsService(consumerStatsService);
return consumerBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> requestBuilder = TbKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("tb-core-fw-producer-" + serviceInfoProvider.getServiceId());
requestBuilder.defaultTopic(coreSettings.getFirmwareTopic());
requestBuilder.clientId("tb-core-ota-producer-" + serviceInfoProvider.getServiceId());
requestBuilder.defaultTopic(coreSettings.getOtaPackageTopic());
requestBuilder.admin(fwUpdatesAdmin);
return requestBuilder.build();
}

12
common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java

@ -22,9 +22,9 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest;
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.*;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -192,14 +192,14 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic());
}
@Override

12
common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -166,14 +166,14 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory {
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, coreSettings.getOtaPackageTopic());
}
@Override

12
common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java

@ -24,7 +24,7 @@ import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsRequest;
import org.thingsboard.server.gen.js.JsInvokeProtos.RemoteJsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -190,14 +190,14 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getOtaPackageTopic());
}
@Override

12
common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -172,14 +172,14 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory {
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, coreSettings.getOtaPackageTopic());
}
@Override

12
common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -189,14 +189,14 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getOtaPackageTopic());
}
@Override

12
common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java

@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
@ -172,14 +172,14 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory {
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer() {
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToFirmwareStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
public TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer() {
return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getOtaPackageTopic(),
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToOtaPackageStateServiceMsg.parseFrom(msg.getData()), msg.getHeaders()));
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer() {
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getFirmwareTopic());
public TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer() {
return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, coreSettings.getOtaPackageTopic());
}
@Override

6
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java

@ -16,7 +16,7 @@
package org.thingsboard.server.queue.provider;
import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
@ -91,14 +91,14 @@ public interface TbCoreQueueFactory extends TbUsageStatsClientQueueFactory {
*
* @return
*/
TbQueueConsumer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgConsumer();
TbQueueConsumer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgConsumer();
/**
* Used to consume messages about firmware update notifications by TB Core Service
*
* @return
*/
TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> createToFirmwareStateServiceMsgProducer();
TbQueueProducer<TbProtoQueueMsg<ToOtaPackageStateServiceMsg>> createToOtaPackageStateServiceMsgProducer();
/**
* Used to consume high priority messages by TB Core Service

4
common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.queue.provider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg;
@ -25,11 +24,12 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg;
import org.thingsboard.server.queue.TbQueueProducer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.util.TbCoreComponent;
import javax.annotation.PostConstruct;
@Service
@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'")
@TbCoreComponent
public class TbCoreQueueProducerProvider implements TbQueueProducerProvider {
private final TbCoreQueueFactory tbQueueProvider;

4
common/queue/src/main/java/org/thingsboard/server/queue/settings/TbQueueCoreSettings.java

@ -26,8 +26,8 @@ public class TbQueueCoreSettings {
@Value("${queue.core.topic}")
private String topic;
@Value("${queue.core.firmware.topic:tb_firmware}")
private String firmwareTopic;
@Value("${queue.core.ota.topic:tb_ota_package}")
private String otaPackageTopic;
@Value("${queue.core.usage-stats-topic:tb_usage_stats}")
private String usageStatsTopic;

18
common/queue/src/main/proto/queue.proto

@ -388,7 +388,7 @@ enum ResponseStatus {
FAILURE = 3;
}
message GetFirmwareRequestMsg {
message GetOtaPackageRequestMsg {
int64 deviceIdMSB = 1;
int64 deviceIdLSB = 2;
int64 tenantIdMSB = 3;
@ -396,10 +396,10 @@ message GetFirmwareRequestMsg {
string type = 5;
}
message GetFirmwareResponseMsg {
message GetOtaPackageResponseMsg {
ResponseStatus responseStatus = 1;
int64 firmwareIdMSB = 2;
int64 firmwareIdLSB = 3;
int64 otaPackageIdMSB = 2;
int64 otaPackageIdLSB = 3;
string type = 4;
string title = 5;
string version = 6;
@ -627,7 +627,7 @@ message TransportApiRequestMsg {
ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7;
ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8;
GetResourceRequestMsg resourceRequestMsg = 9;
GetFirmwareRequestMsg firmwareRequestMsg = 10;
GetOtaPackageRequestMsg otaPackageRequestMsg = 10;
GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11;
GetDeviceRequestMsg deviceRequestMsg = 12;
GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13;
@ -642,7 +642,7 @@ message TransportApiResponseMsg {
GetSnmpDevicesResponseMsg snmpDevicesResponseMsg = 5;
LwM2MResponseMsg lwM2MResponseMsg = 6;
GetResourceResponseMsg resourceResponseMsg = 7;
GetFirmwareResponseMsg firmwareResponseMsg = 8;
GetOtaPackageResponseMsg otaPackageResponseMsg = 8;
GetDeviceResponseMsg deviceResponseMsg = 9;
GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 10;
}
@ -710,13 +710,13 @@ message ToUsageStatsServiceMsg {
int64 customerIdLSB = 7;
}
message ToFirmwareStateServiceMsg {
message ToOtaPackageStateServiceMsg {
int64 ts = 1;
int64 tenantIdMSB = 2;
int64 tenantIdLSB = 3;
int64 deviceIdMSB = 4;
int64 deviceIdLSB = 5;
int64 firmwareIdMSB = 6;
int64 firmwareIdLSB = 7;
int64 otaPackageIdMSB = 6;
int64 otaPackageIdLSB = 7;
string type = 8;
}

22
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java

@ -44,7 +44,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@ -350,10 +350,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
new CoapNoOpCallback(exchange));
break;
case GET_FIRMWARE_REQUEST:
getFirmwareCallback(sessionInfo, exchange, FirmwareType.FIRMWARE);
getOtaPackageCallback(sessionInfo, exchange, OtaPackageType.FIRMWARE);
break;
case GET_SOFTWARE_REQUEST:
getFirmwareCallback(sessionInfo, exchange, FirmwareType.SOFTWARE);
getOtaPackageCallback(sessionInfo, exchange, OtaPackageType.SOFTWARE);
break;
}
} catch (AdaptorException e) {
@ -366,14 +366,14 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
return new UUID(sessionInfoProto.getSessionIdMSB(), sessionInfoProto.getSessionIdLSB());
}
private void getFirmwareCallback(TransportProtos.SessionInfoProto sessionInfo, CoapExchange exchange, FirmwareType firmwareType) {
TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
private void getOtaPackageCallback(TransportProtos.SessionInfoProto sessionInfo, CoapExchange exchange, OtaPackageType firmwareType) {
TransportProtos.GetOtaPackageRequestMsg requestMsg = TransportProtos.GetOtaPackageRequestMsg.newBuilder()
.setTenantIdMSB(sessionInfo.getTenantIdMSB())
.setTenantIdLSB(sessionInfo.getTenantIdLSB())
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setType(firmwareType.name()).build();
transportContext.getTransportService().process(sessionInfo, requestMsg, new FirmwareCallback(exchange));
transportContext.getTransportService().process(sessionInfo, requestMsg, new OtaPackageCallback(exchange));
}
private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) {
@ -470,25 +470,25 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
}
}
private class FirmwareCallback implements TransportServiceCallback<TransportProtos.GetFirmwareResponseMsg> {
private class OtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> {
private final CoapExchange exchange;
FirmwareCallback(CoapExchange exchange) {
OtaPackageCallback(CoapExchange exchange) {
this.exchange = exchange;
}
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg msg) {
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg msg) {
String title = exchange.getQueryParameter("title");
String version = exchange.getQueryParameter("version");
if (msg.getResponseStatus().equals(TransportProtos.ResponseStatus.SUCCESS)) {
if (msg.getTitle().equals(title) && msg.getVersion().equals(version)) {
String firmwareId = new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB()).toString();
String firmwareId = new UUID(msg.getOtaPackageIdMSB(), msg.getOtaPackageIdLSB()).toString();
String strChunkSize = exchange.getQueryParameter("size");
String strChunk = exchange.getQueryParameter("chunk");
int chunkSize = StringUtils.isEmpty(strChunkSize) ? 0 : Integer.parseInt(strChunkSize);
int chunk = StringUtils.isEmpty(strChunk) ? 0 : Integer.parseInt(strChunk);
exchange.respond(CoAP.ResponseCode.CONTENT, transportContext.getFirmwareDataCache().get(firmwareId, chunkSize, chunk));
exchange.respond(CoAP.ResponseCode.CONTENT, transportContext.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk));
} else {
exchange.respond(CoAP.ResponseCode.BAD_REQUEST);
}

32
common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java

@ -34,7 +34,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.TbTransportService;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.transport.SessionMsgListener;
@ -213,7 +213,7 @@ public class DeviceApiController implements TbTransportService {
@RequestParam(value = "version") String version,
@RequestParam(value = "size", required = false, defaultValue = "0") int size,
@RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) {
return getFirmwareCallback(deviceToken, title, version, size, chunk, FirmwareType.FIRMWARE);
return getOtaPackageCallback(deviceToken, title, version, size, chunk, OtaPackageType.FIRMWARE);
}
@RequestMapping(value = "/{deviceToken}/software", method = RequestMethod.GET)
@ -222,7 +222,7 @@ public class DeviceApiController implements TbTransportService {
@RequestParam(value = "version") String version,
@RequestParam(value = "size", required = false, defaultValue = "0") int size,
@RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) {
return getFirmwareCallback(deviceToken, title, version, size, chunk, FirmwareType.SOFTWARE);
return getOtaPackageCallback(deviceToken, title, version, size, chunk, OtaPackageType.SOFTWARE);
}
@RequestMapping(value = "/provision", method = RequestMethod.POST)
@ -233,17 +233,17 @@ public class DeviceApiController implements TbTransportService {
return responseWriter;
}
private DeferredResult<ResponseEntity> getFirmwareCallback(String deviceToken, String title, String version, int size, int chunk, FirmwareType firmwareType) {
private DeferredResult<ResponseEntity> getOtaPackageCallback(String deviceToken, String title, String version, int size, int chunk, OtaPackageType firmwareType) {
DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>();
transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(),
new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> {
TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
TransportProtos.GetOtaPackageRequestMsg requestMsg = TransportProtos.GetOtaPackageRequestMsg.newBuilder()
.setTenantIdMSB(sessionInfo.getTenantIdMSB())
.setTenantIdLSB(sessionInfo.getTenantIdLSB())
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setType(firmwareType.name()).build();
transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, size, chunk));
transportContext.getTransportService().process(sessionInfo, requestMsg, new GetOtaPackageCallback(responseWriter, title, version, size, chunk));
}));
return responseWriter;
}
@ -294,14 +294,14 @@ public class DeviceApiController implements TbTransportService {
}
}
private class GetFirmwareCallback implements TransportServiceCallback<TransportProtos.GetFirmwareResponseMsg> {
private class GetOtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> {
private final DeferredResult<ResponseEntity> responseWriter;
private final String title;
private final String version;
private final int chuckSize;
private final int chuck;
GetFirmwareCallback(DeferredResult<ResponseEntity> responseWriter, String title, String version, int chuckSize, int chuck) {
GetOtaPackageCallback(DeferredResult<ResponseEntity> responseWriter, String title, String version, int chuckSize, int chuck) {
this.responseWriter = responseWriter;
this.title = title;
this.version = version;
@ -310,17 +310,17 @@ public class DeviceApiController implements TbTransportService {
}
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg firmwareResponseMsg) {
if (!TransportProtos.ResponseStatus.SUCCESS.equals(firmwareResponseMsg.getResponseStatus())) {
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg otaPackageResponseMsg) {
if (!TransportProtos.ResponseStatus.SUCCESS.equals(otaPackageResponseMsg.getResponseStatus())) {
responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_FOUND));
} else if (title.equals(firmwareResponseMsg.getTitle()) && version.equals(firmwareResponseMsg.getVersion())) {
String firmwareId = new UUID(firmwareResponseMsg.getFirmwareIdMSB(), firmwareResponseMsg.getFirmwareIdLSB()).toString();
ByteArrayResource resource = new ByteArrayResource(transportContext.getFirmwareDataCache().get(firmwareId, chuckSize, chuck));
} else if (title.equals(otaPackageResponseMsg.getTitle()) && version.equals(otaPackageResponseMsg.getVersion())) {
String otaPackageId = new UUID(otaPackageResponseMsg.getOtaPackageIdMSB(), otaPackageResponseMsg.getOtaPackageIdLSB()).toString();
ByteArrayResource resource = new ByteArrayResource(transportContext.getOtaPackageDataCache().get(otaPackageId, chuckSize, chuck));
ResponseEntity<ByteArrayResource> response = ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + firmwareResponseMsg.getFileName())
.header("x-filename", firmwareResponseMsg.getFileName())
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackageResponseMsg.getFileName())
.header("x-filename", otaPackageResponseMsg.getFileName())
.contentLength(resource.contentLength())
.contentType(parseMediaType(firmwareResponseMsg.getContentType()))
.contentType(parseMediaType(otaPackageResponseMsg.getContentType()))
.body(resource);
responseWriter.setResult(response);
} else {

159
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java

@ -39,13 +39,13 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cache.firmware.FirmwareDataCache;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.firmware.FirmwareKey;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.FirmwareUtil;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
@ -87,8 +87,8 @@ import java.util.stream.Collectors;
import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;
import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED;
@ -114,6 +114,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getAckCallback;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.isFwSwWords;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.setValidTypeOper;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey;
@ -131,7 +132,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
private final TransportService transportService;
private final LwM2mTransportContext context;
public final LwM2MTransportServerConfig config;
public final FirmwareDataCache firmwareDataCache;
public final OtaPackageDataCache otaPackageDataCache;
public final LwM2mTransportServerHelper helper;
private final LwM2MJsonAdaptor adaptor;
private final TbLwM2MDtlsSessionStore sessionStore;
@ -142,14 +143,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,
LwM2mClientContext clientContext,
@Lazy LwM2mTransportRequest lwM2mTransportRequest,
FirmwareDataCache firmwareDataCache,
OtaPackageDataCache otaPackageDataCache,
LwM2mTransportContext context, LwM2MJsonAdaptor adaptor, TbLwM2MDtlsSessionStore sessionStore) {
this.transportService = transportService;
this.config = config;
this.helper = helper;
this.clientContext = clientContext;
this.lwM2mTransportRequest = lwM2mTransportRequest;
this.firmwareDataCache = firmwareDataCache;
this.otaPackageDataCache = otaPackageDataCache;
this.context = context;
this.adaptor = adaptor;
this.rpcSubscriptions = new ConcurrentHashMap<>();
@ -195,8 +196,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
.setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().build())
.build();
transportService.process(msg, null);
this.getInfoFirmwareUpdate(lwM2MClient);
this.getInfoSoftwareUpdate(lwM2MClient);
this.getInfoFirmwareUpdate(lwM2MClient, null);
this.getInfoSoftwareUpdate(lwM2MClient, null);
this.initLwM2mFromClientValue(registration, lwM2MClient);
this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId());
} else {
@ -246,7 +247,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param observations - !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect
*/
public void unReg(Registration registration, Collection<Observation> observations) {
log.error("Client unRegistration -> test", new RuntimeException());
unRegistrationExecutor.submit(() -> {
try {
this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId());
@ -285,7 +285,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
@Override
public void setCancelObservationsAll(Registration registration) {
if (registration != null) {
lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL_ALL,
this.lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL_ALL,
null, null, this.config.getTimeout(), null);
}
}
@ -334,7 +334,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
READ, pathIdVer, value);
this.sendLogsToThingsboard(msg, registration.getId());
rpcRequest.setValueMsg(String.format("%s", value));
this.sentRpcRequest(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
this.sentRpcResponse(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
}
/**
@ -351,22 +351,22 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
@Override
public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo);
if (msg.getSharedUpdatedCount() > 0) {
if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) {
log.warn ("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList());
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
log.warn("12) Shared AttributeUpdate start pathName [{}], pathIdVer [{}], valueNew [{}]", pathName, pathIdVer, valueNew);
if ((FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName)
if ((OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())))
|| (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.TITLE).equals(pathName)
|| (OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentTitle())))) {
this.getInfoFirmwareUpdate(lwM2MClient);
} else if ((FirmwareUtil.getAttributeKey(FirmwareType.SOFTWARE, FirmwareKey.VERSION).equals(pathName)
this.getInfoFirmwareUpdate(lwM2MClient, null);
} else if ((OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentVersion())))
|| (FirmwareUtil.getAttributeKey(FirmwareType.SOFTWARE, FirmwareKey.TITLE).equals(pathName)
|| (OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE).equals(pathName)
&& (!valueNew.equals(lwM2MClient.getSwUpdate().getCurrentTitle())))) {
this.getInfoSoftwareUpdate(lwM2MClient);
this.getInfoSoftwareUpdate(lwM2MClient, null);
}
if (pathIdVer != null) {
ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.config
@ -379,7 +379,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
LOG_LW2M_ERROR, pathIdVer, valueNew);
this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
}
} else {
} else if (!isFwSwWords(pathName)) {
log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew);
String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated",
LOG_LW2M_ERROR, pathName, valueNew);
@ -387,16 +387,19 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
});
} else if (msg.getSharedDeletedCount() > 0) {
} else if (msg.getSharedDeletedCount() > 0 && lwM2MClient != null) {
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())) {
if (OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())) {
lwM2MClient.getFwUpdate().setCurrentVersion((String) valueNew);
}
});
log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
}
else if (lwM2MClient == null) {
log.error ("OnAttributeUpdate, lwM2MClient is null");
}
}
/**
@ -443,10 +446,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) {
// #1
this.checkRpcRequestTimeout();
log.warn ("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
String bodyParams = StringUtils.trimToNull(toDeviceRpcRequestMsg.getParams()) != null ? toDeviceRpcRequestMsg.getParams() : "null";
LwM2mTypeOper lwM2mTypeOper = setValidTypeOper(toDeviceRpcRequestMsg.getMethodName());
UUID requestUUID = new UUID(toDeviceRpcRequestMsg.getRequestIdMSB(), toDeviceRpcRequestMsg.getRequestIdLSB());
log.warn("4) RPC-OK finish to [{}], keys: [{}]", requestUUID, this.rpcSubscriptions.keySet());
if (!this.rpcSubscriptions.containsKey(requestUUID)) {
this.rpcSubscriptions.put(requestUUID, toDeviceRpcRequestMsg.getExpirationTime());
Lwm2mClientRpcRequest lwm2mClientRpcRequest = null;
@ -480,7 +483,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
rpcSubscriptionsToRemove.forEach(rpcSubscriptions::remove);
}
public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {
public void sentRpcResponse(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {
rpcRequest.setResponseCode(requestCode);
if (LOG_LW2M_ERROR.equals(typeMsg)) {
rpcRequest.setInfoMsg(null);
@ -503,6 +506,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
@Override
public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, SessionInfoProto sessionInfo) {
log.warn ("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
transportService.process(sessionInfo, toDeviceResponse, null);
}
@ -647,7 +651,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* set setClient_fw_info... = value
**/
if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getFwUpdate().initReadValue(this, this.lwM2mTransportRequest, path);
lwM2MClient.getFwUpdate().initReadValue(this, this.lwM2mTransportRequest, path);
}
if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
lwM2MClient.getSwUpdate().initReadValue(this, this.lwM2mTransportRequest, path);
@ -883,10 +887,16 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*/
private Object getResourceValueFormatKv(LwM2mClient lwM2MClient, String pathIdVer) {
LwM2mResource resourceValue = this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
if (resourceValue != null) {
ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
}
else {
return null;
}
}
/**
@ -1229,7 +1239,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {
try {
List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList();
this.updateAttributeFromThingsboard(tsKvProtos, sessionInfo);
} catch (Exception e) {
log.error("", e);
@ -1248,22 +1257,28 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*/
public void updateAttributeFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo);
tsKvProtos.forEach(tsKvProto -> {
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
if (pathIdVer != null) {
// #1.1
if (lwM2MClient.getDelayedRequests().containsKey(pathIdVer) && tsKvProto.getTs() > lwM2MClient.getDelayedRequests().get(pathIdVer).getTs()) {
lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
} else if (!lwM2MClient.getDelayedRequests().containsKey(pathIdVer)) {
lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
if (lwM2MClient != null) {
log.warn("1) UpdateAttributeFromThingsboard, tsKvProtos [{}]", tsKvProtos);
tsKvProtos.forEach(tsKvProto -> {
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
if (pathIdVer != null) {
// #1.1
if (lwM2MClient.getDelayedRequests().containsKey(pathIdVer) && tsKvProto.getTs() > lwM2MClient.getDelayedRequests().get(pathIdVer).getTs()) {
lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
} else if (!lwM2MClient.getDelayedRequests().containsKey(pathIdVer)) {
lwM2MClient.getDelayedRequests().put(pathIdVer, tsKvProto);
}
}
}
});
// #2.1
lwM2MClient.getDelayedRequests().forEach((pathIdVer, tsKvProto) -> {
this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
});
});
// #2.1
lwM2MClient.getDelayedRequests().forEach((pathIdVer, tsKvProto) -> {
this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
});
}
else {
log.error("UpdateAttributeFromThingsboard, lwM2MClient is null");
}
}
/**
@ -1342,23 +1357,30 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
}
public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) {
public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) {
if (lwM2MClient.getRegistration().getSupportedVersion(FW_ID) != null) {
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
DefaultLwM2MTransportMsgHandler serviceImpl = this;
transportService.process(sessionInfo, createFirmwareRequestMsg(sessionInfo, FirmwareType.FIRMWARE.name()),
DefaultLwM2MTransportMsgHandler handler = this;
this.transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.FIRMWARE.name()),
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
&& response.getType().equals(FirmwareType.FIRMWARE.name())) {
&& response.getType().equals(OtaPackageType.FIRMWARE.name())) {
log.warn ("7) firmware start with ver: [{}]", response.getVersion());
lwM2MClient.getFwUpdate().setRpcRequest(rpcRequest);
lwM2MClient.getFwUpdate().setCurrentVersion(response.getVersion());
lwM2MClient.getFwUpdate().setCurrentTitle(response.getTitle());
lwM2MClient.getFwUpdate().setCurrentId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
lwM2MClient.getFwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
lwM2MClient.getFwUpdate().setCurrentId(new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB())).getId());
if (rpcRequest == null) {
lwM2MClient.getFwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
}
else {
lwM2MClient.getFwUpdate().writeFwSwWare(handler, lwM2mTransportRequest);
}
} else {
log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
log.trace("OtaPackage [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
}
}
@ -1371,21 +1393,28 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
}
public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient) {
public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) {
if (lwM2MClient.getRegistration().getSupportedVersion(SW_ID) != null) {
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
DefaultLwM2MTransportMsgHandler serviceImpl = this;
transportService.process(sessionInfo, createFirmwareRequestMsg(sessionInfo, FirmwareType.SOFTWARE.name()),
DefaultLwM2MTransportMsgHandler handler = this;
transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.SOFTWARE.name()),
new TransportServiceCallback<>() {
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
&& response.getType().equals(FirmwareType.SOFTWARE.name())) {
&& response.getType().equals(OtaPackageType.SOFTWARE.name())) {
lwM2MClient.getSwUpdate().setRpcRequest(rpcRequest);
lwM2MClient.getSwUpdate().setCurrentVersion(response.getVersion());
lwM2MClient.getSwUpdate().setCurrentTitle(response.getTitle());
lwM2MClient.getSwUpdate().setCurrentId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId());
lwM2MClient.getSwUpdate().setCurrentId(new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB())).getId());
lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
if (rpcRequest == null) {
lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
}
else {
lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest);
}
} else {
log.trace("Software [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
}
@ -1400,8 +1429,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
}
private TransportProtos.GetFirmwareRequestMsg createFirmwareRequestMsg(SessionInfoProto sessionInfo, String nameFwSW) {
return TransportProtos.GetFirmwareRequestMsg.newBuilder()
private TransportProtos.GetOtaPackageRequestMsg createOtaPackageRequestMsg(SessionInfoProto sessionInfo, String nameFwSW) {
return TransportProtos.GetOtaPackageRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setTenantIdMSB(sessionInfo.getTenantIdMSB())

98
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mNetworkConfig.java

@ -23,26 +23,26 @@ public class LwM2mNetworkConfig {
NetworkConfig coapConfig = new NetworkConfig();
coapConfig.setInt(NetworkConfig.Keys.COAP_PORT,serverPortNoSec);
coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT,serverSecurePort);
/*
Example:Property for large packet:
#NetworkConfig config = new NetworkConfig();
#config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32);
#config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32);
#config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048);
#config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3);
#config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000);
/**
Example:Property for large packet:
#NetworkConfig config = new NetworkConfig();
#config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32);
#config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32);
#config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048);
#config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3);
#config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000);
*/
/*
Property to indicate if the response should always include the Block2 option \
when client request early blockwise negociation but the response can be sent on one packet.
- value of false indicate that the server will respond without block2 option if no further blocks are required.
- value of true indicate that the server will response with block2 option event if no further blocks are required.
CoAP client will try to use block mode
or adapt the block size when receiving a 4.13 Entity too large response code
/**
Property to indicate if the response should always include the Block2 option \
when client request early blockwise negociation but the response can be sent on one packet.
- value of false indicate that the server will respond without block2 option if no further blocks are required.
- value of true indicate that the server will response with block2 option event if no further blocks are required.
CoAP client will try to use block mode
or adapt the block size when receiving a 4.13 Entity too large response code
*/
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true);
/*
/**
Property to indicate if the response should always include the Block2 option \
when client request early blockwise negociation but the response can be sent on one packet.
- value of false indicate that the server will respond without block2 option if no further blocks are required.
@ -51,44 +51,44 @@ public class LwM2mNetworkConfig {
coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true);
coapConfig.setInt(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, 300000);
/*
!!! REQUEST_ENTITY_TOO_LARGE CODE=4.13
The maximum size of a resource body (in bytes) that will be accepted
as the payload of a POST/PUT or the response to a GET request in a
transparent> blockwise transfer.
This option serves as a safeguard against excessive memory
consumption when many resources contain large bodies that cannot be
transferred in a single CoAP message. This option has no impact on
*manually* managed blockwise transfers in which the blocks are handled individually.
Note that this option does not prevent local clients or resource
implementations from sending large bodies as part of a request or response to a peer.
The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192
A value of {@code 0} turns off transparent handling of blockwise transfers altogether.
/**
!!! REQUEST_ENTITY_TOO_LARGE CODE=4.13
The maximum size of a resource body (in bytes) that will be accepted
as the payload of a POST/PUT or the response to a GET request in a
transparent> blockwise transfer.
This option serves as a safeguard against excessive memory
consumption when many resources contain large bodies that cannot be
transferred in a single CoAP message. This option has no impact on
*manually* managed blockwise transfers in which the blocks are handled individually.
Note that this option does not prevent local clients or resource
implementations from sending large bodies as part of a request or response to a peer.
The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192
A value of {@code 0} turns off transparent handling of blockwise transfers altogether.
*/
coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024);
/*
The default DTLS response matcher.
Supported values are STRICT, RELAXED, or PRINCIPAL.
The default value is STRICT.
Create new instance of udp endpoint context matcher.
Params:
checkAddress
true with address check, (STRICT, UDP)
- false, without
/**
The default DTLS response matcher.
Supported values are STRICT, RELAXED, or PRINCIPAL.
The default value is STRICT.
Create new instance of udp endpoint context matcher.
Params:
checkAddress
true with address check, (STRICT, UDP)
- false, without
*/
coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "STRICT");
/*
https://tools.ietf.org/html/rfc7959#section-2.9.3
The block size (number of bytes) to use when doing a blockwise transfer. \
This value serves as the upper limit for block size in blockwise transfers
/**
https://tools.ietf.org/html/rfc7959#section-2.9.3
The block size (number of bytes) to use when doing a blockwise transfer. \
This value serves as the upper limit for block size in blockwise transfers
*/
coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024);
/*
The maximum payload size (in bytes) that can be transferred in a
single message, i.e. without requiring a blockwise transfer.
NB: this value MUST be adapted to the maximum message size supported by the transport layer.
In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol
DEFAULT_VALUE = 1024
/**
The maximum payload size (in bytes) that can be transferred in a
single message, i.e. without requiring a blockwise transfer.
NB: this value MUST be adapted to the maximum message size supported by the transport layer.
In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol
DEFAULT_VALUE = 1024
*/
coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024);
@ -96,4 +96,4 @@ public class LwM2mNetworkConfig {
return coapConfig;
}
}
}

152
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java

@ -71,8 +71,8 @@ import java.util.stream.Collectors;
import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST;
import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.FAILED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getContentFormatByResourceModelType;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEFAULT_TIMEOUT;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_ID;
@ -82,10 +82,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_ALL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL_ALL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
@ -134,7 +132,7 @@ public class LwM2mTransportRequest {
ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT;
LwM2mClient lwM2MClient = this.lwM2mClientContext.getOrRegister(registration);
LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null;
if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) {
if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) {
if (lwM2MClient.isValidObjectVersion(targetIdVer)) {
timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
DownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target,
@ -153,47 +151,66 @@ public class LwM2mTransportRequest {
} else if (WRITE_UPDATE.name().equals(typeOper.name())) {
if (lwm2mClientRpcRequest != null) {
String errorMsg = String.format("Path %s params is not valid", targetIdVer);
handler.sentRpcRequest(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
handler.sentRpcResponse(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
}
} else if (WRITE_REPLACE.name().equals(typeOper.name()) || EXECUTE.name().equals(typeOper.name())) {
if (lwm2mClientRpcRequest != null) {
String errorMsg = String.format("Path %s object model is absent", targetIdVer);
handler.sentRpcRequest(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
handler.sentRpcResponse(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
}
} else if (!OBSERVE_CANCEL.name().equals(typeOper.name())) {
log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer);
if (lwm2mClientRpcRequest != null) {
ResourceModel resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());
String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null";
this.handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
this.handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
}
}
} else if (lwm2mClientRpcRequest != null) {
String errorMsg = String.format("Path %s not found in object version", targetIdVer);
this.handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
this.handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
}
} else if (OBSERVE_READ_ALL.name().equals(typeOper.name()) || DISCOVER_ALL.name().equals(typeOper.name())) {
Set<String> paths;
if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
} else {
assert registration != null;
Link[] objectLinks = registration.getSortedObjectLinks();
paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet());
}
String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,
typeOper.name(), paths);
this.handler.sendLogsToThingsboard(msg, registration.getId());
if (lwm2mClientRpcRequest != null) {
String valueMsg = String.format("Paths - %s", paths);
this.handler.sentRpcRequest(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
} else {
switch (typeOper) {
case OBSERVE_READ_ALL:
case DISCOVER_ALL:
Set<String> paths;
if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
} else {
assert registration != null;
Link[] objectLinks = registration.getSortedObjectLinks();
paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet());
}
String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,
typeOper.name(), paths);
this.handler.sendLogsToThingsboard(msg, registration.getId());
if (lwm2mClientRpcRequest != null) {
String valueMsg = String.format("Paths - %s", paths);
this.handler.sentRpcResponse(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
}
break;
case OBSERVE_CANCEL:
case OBSERVE_CANCEL_ALL:
int observeCancelCnt = 0;
String observeCancelMsg = null;
if (OBSERVE_CANCEL.name().equals(typeOper)) {
observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration, target);
observeCancelMsg = String.format("%s: type operation %s paths: %s count: %d", LOG_LW2M_INFO,
OBSERVE_CANCEL.name(), target, observeCancelCnt);
} else {
observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration);
observeCancelMsg = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO,
OBSERVE_CANCEL.name(), observeCancelCnt);
}
this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest);
break;
// lwm2mClientRpcRequest != null
case FW_UPDATE:
this.handler.getInfoFirmwareUpdate(lwM2MClient, lwm2mClientRpcRequest);
break;
}
} else if (OBSERVE_CANCEL_ALL.name().equals(typeOper.name())) {
int observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration);
String observeCancelMsgAll = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO,
OBSERVE_CANCEL.name(), observeCancelCnt);
this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsgAll, lwm2mClientRpcRequest);
}
} catch (Exception e) {
String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR,
@ -201,7 +218,7 @@ public class LwM2mTransportRequest {
handler.sendLogsToThingsboard(msg, registration.getId());
if (lwm2mClientRpcRequest != null) {
String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage());
handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
}
}
}
@ -234,17 +251,6 @@ public class LwM2mTransportRequest {
request = new ObserveRequest(contentFormat, resultIds.getObjectId());
}
break;
case OBSERVE_CANCEL:
/*
lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());
At server side this will not remove the observation from the observation store, to do it you need to use
{@code ObservationService#cancelObservation()}
*/
int observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration, target);
String observeCancelMsg = String.format("%s: type operation %s paths: %s count: %d", LOG_LW2M_INFO,
OBSERVE_CANCEL.name(), target, observeCancelCnt);
this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsg, rpcRequest);
break;
case EXECUTE:
ResourceModel resourceModelExecute = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());
if (resourceModelExecute != null) {
@ -343,7 +349,7 @@ public class LwM2mTransportRequest {
}
/** Not Found */
if (rpcRequest != null) {
handler.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR);
handler.sentRpcResponse(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR);
}
/** Not Found
set setClient_fw_info... = empty
@ -385,7 +391,7 @@ public class LwM2mTransportRequest {
handler.sendLogsToThingsboard(msg, registration.getId());
log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString());
if (rpcRequest != null) {
handler.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR);
handler.sentRpcResponse(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR);
}
});
}
@ -431,7 +437,7 @@ public class LwM2mTransportRequest {
log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString());
if (rpcRequest != null) {
String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value);
handler.sentRpcRequest(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
handler.sentRpcResponse(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
}
return null;
}
@ -462,44 +468,48 @@ public class LwM2mTransportRequest {
if (response instanceof ReadResponse) {
handler.onUpdateValueAfterReadResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest);
} else if (response instanceof DeleteResponse) {
log.warn("[{}] Path [{}] DeleteResponse 5_Send", pathIdVer, response);
log.warn("11) [{}] Path [{}] DeleteResponse", pathIdVer, response);
if (rpcRequest != null) {
rpcRequest.setInfoMsg(null);
handler.sentRpcResponse(rpcRequest, response.getCode().getName(), null, null);
}
} else if (response instanceof DiscoverResponse) {
String discoverValue = Link.serialize(((DiscoverResponse)response).getObjectLinks());
String discoverValue = Link.serialize(((DiscoverResponse) response).getObjectLinks());
msgLog = String.format("%s: type operation: %s path: %s value: %s",
LOG_LW2M_INFO, DISCOVER.name(), request.getPath().toString(), discoverValue);
handler.sendLogsToThingsboard(msgLog, registration.getId());
log.warn("DiscoverResponse: [{}]", (DiscoverResponse) response);
if (rpcRequest != null) {
handler.sentRpcRequest(rpcRequest, response.getCode().getName(), discoverValue, LOG_LW2M_VALUE);
handler.sentRpcResponse(rpcRequest, response.getCode().getName(), discoverValue, LOG_LW2M_VALUE);
}
} else if (response instanceof ExecuteResponse) {
log.warn("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response);
msgLog = String.format("%s: type operation: %s path: %s",
LOG_LW2M_INFO, EXECUTE.name(), request.getPath().toString());
log.warn("9) [{}] ", msgLog);
handler.sendLogsToThingsboard(msgLog, registration.getId());
if (rpcRequest != null) {
msgLog = String.format("Start %s path: %S. Preparation finished: %s", EXECUTE.name(), path, rpcRequest.getInfoMsg());
rpcRequest.setInfoMsg(msgLog);
handler.sentRpcResponse(rpcRequest, response.getCode().getName(), path, LOG_LW2M_INFO);
}
} else if (response instanceof WriteAttributesResponse) {
msgLog = String.format("%s: type operation: %s path: %s value: %s",
LOG_LW2M_INFO, WRITE_ATTRIBUTES.name(), request.getPath().toString(), ((WriteAttributesRequest) request).getAttributes().toString());
handler.sendLogsToThingsboard(msgLog, registration.getId());
log.warn("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response);
log.warn("12) [{}] Path [{}] WriteAttributesResponse", pathIdVer, response);
if (rpcRequest != null) {
handler.sentRpcRequest(rpcRequest, response.getCode().getName(), response.toString(), LOG_LW2M_VALUE);
handler.sentRpcResponse(rpcRequest, response.getCode().getName(), response.toString(), LOG_LW2M_VALUE);
}
} else if (response instanceof WriteResponse) {
log.warn("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response);
this.infoWriteResponse(registration, response, request);
msgLog = String.format("Type operation: Write path: %s", pathIdVer);
log.warn("10) [{}] response: [{}]", msgLog, response);
this.infoWriteResponse(registration, response, request, rpcRequest);
handler.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request);
}
if (rpcRequest != null) {
if (response instanceof ExecuteResponse
|| response instanceof WriteAttributesResponse
|| response instanceof DeleteResponse) {
rpcRequest.setInfoMsg(null);
handler.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null);
} else if (response instanceof WriteResponse) {
handler.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO);
}
}
}
private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request) {
private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
try {
LwM2mNode node = ((WriteRequest) request).getNode();
String msg = null;
@ -517,12 +527,12 @@ public class LwM2mTransportRequest {
if (singleResource.getType() == ResourceModel.Type.STRING) {
valueLength = ((String) singleResource.getValue()).length();
value = ((String) singleResource.getValue())
.substring(Math.min(valueLength, config.getLogMaxLength()));
.substring(Math.min(valueLength, config.getLogMaxLength())).trim();
} else {
valueLength = ((byte[]) singleResource.getValue()).length;
value = new String(Arrays.copyOf(((byte[]) singleResource.getValue()),
Math.min(valueLength, config.getLogMaxLength())));
Math.min(valueLength, config.getLogMaxLength()))).trim();
}
value = valueLength > config.getLogMaxLength() ? value + "..." : value;
msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path: %s length: %s value: %s",
@ -538,6 +548,12 @@ public class LwM2mTransportRequest {
handler.sendLogsToThingsboard(msg, registration.getId());
if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
this.afterWriteSuccessFwSwUpdate(registration, request);
if (rpcRequest != null) {
rpcRequest.setInfoMsg(msg);
}
}
else if (rpcRequest != null) {
handler.sentRpcResponse(rpcRequest, response.getCode().getName(), msg, LOG_LW2M_INFO);
}
}
} catch (Exception e) {
@ -558,7 +574,7 @@ public class LwM2mTransportRequest {
}
if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) {
lwM2MClient.getSwUpdate().setStateUpdate(DOWNLOADED.name());
lwM2MClient.getSwUpdate().sendLogs(this.handler,WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
lwM2MClient.getSwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
}
}
@ -592,7 +608,7 @@ public class LwM2mTransportRequest {
log.warn("[{}]", observeCancelMsg);
if (rpcRequest != null) {
rpcRequest.setInfoMsg(String.format("Count: %d", observeCancelCnt));
handler.sentRpcRequest(rpcRequest, CONTENT.name(), null, LOG_LW2M_INFO);
handler.sentRpcResponse(rpcRequest, CONTENT.name(), null, LOG_LW2M_INFO);
}
}
}

11
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java

@ -53,6 +53,8 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
@ -64,6 +66,13 @@ public class LwM2mTransportServerHelper {
private final LwM2mTransportContext context;
private final LwM2MJsonAdaptor adaptor;
private final AtomicInteger atomicTs = new AtomicInteger(0);
public long getTS() {
int addTs = atomicTs.getAndIncrement() >= 1000 ? atomicTs.getAndSet(0) : atomicTs.get();
return TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()) * 1000L + addTs;
}
/**
* send to Thingsboard Attribute || Telemetry
@ -96,7 +105,7 @@ public class LwM2mTransportServerHelper {
public void sendParametersOnThingsboardTelemetry(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
PostTelemetryMsg.Builder request = PostTelemetryMsg.newBuilder();
TransportProtos.TsKvListProto.Builder builder = TransportProtos.TsKvListProto.newBuilder();
builder.setTs(System.currentTimeMillis());
builder.setTs(this.getTS());
builder.addAllKv(result);
request.addTsKvList(builder.build());
PostTelemetryMsg postTelemetryMsg = request.build();

43
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java

@ -43,7 +43,10 @@ import org.eclipse.leshan.server.registration.Registration;
import org.nustaq.serialization.FSTConfiguration;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
@ -74,12 +77,12 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.OBJLNK;
import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
import static org.eclipse.leshan.core.model.ResourceModel.Type.TIME;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.DOWNLOADING;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.FAILED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATED;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.VERIFIED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
@ -136,7 +139,7 @@ public class LwM2mTransportUtil {
public static final String ERROR_KEY = "error";
public static final String METHOD_KEY = "methodName";
// FirmWare
// Firmware
public static final String FW_UPDATE = "Firmware update";
public static final Integer FW_ID = 5;
// Package W
@ -152,7 +155,7 @@ public class LwM2mTransportUtil {
// Update E
public static final String FW_UPDATE_ID = "/5/0/2";
// SoftWare
// Software
public static final String SW_UPDATE = "Software update";
public static final Integer SW_ID = 9;
// Package W
@ -226,11 +229,12 @@ public class LwM2mTransportUtil {
*/
WRITE_UPDATE(9, "WriteUpdate"),
WRITE_ATTRIBUTES(10, "WriteAttributes"),
DELETE(11, "Delete");
DELETE(11, "Delete"),
// only for RPC
FW_UPDATE(12,"FirmwareUpdate");
// FW_READ_INFO(12, "FirmwareReadInfo"),
// FW_UPDATE(13, "FirmwareUpdate"),
// SW_READ_INFO(15, "SoftwareReadInfo"),
// SW_UPDATE(16, "SoftwareUpdate"),
// SW_UNINSTALL(18, "SoftwareUninstall");
@ -351,7 +355,7 @@ public class LwM2mTransportUtil {
* FirmwareUpdateStatus {
* DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
*/
public static FirmwareUpdateStatus EqualsFwSateToFirmwareUpdateStatus(StateFw stateFw, UpdateResultFw updateResultFw) {
public static OtaPackageUpdateStatus EqualsFwSateToFirmwareUpdateStatus(StateFw stateFw, UpdateResultFw updateResultFw) {
switch (updateResultFw) {
case INITIAL:
switch (stateFw) {
@ -497,7 +501,7 @@ public class LwM2mTransportUtil {
* FirmwareUpdateStatus {
* DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED
*/
public static FirmwareUpdateStatus EqualsSwSateToFirmwareUpdateStatus(UpdateStateSw updateStateSw, UpdateResultSw updateResultSw) {
public static OtaPackageUpdateStatus EqualsSwSateToFirmwareUpdateStatus(UpdateStateSw updateStateSw, UpdateResultSw updateResultSw) {
switch (updateResultSw) {
case INITIAL:
switch (updateStateSw) {
@ -927,4 +931,17 @@ public class LwM2mTransportUtil {
return null;
}
}
public static boolean isFwSwWords (String pathName) {
return OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.VERSION).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.TITLE).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.FIRMWARE, OtaPackageKey.SIZE).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.VERSION).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.TITLE).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.CHECKSUM_ALGORITHM).equals(pathName)
|| OtaPackageUtil.getAttributeKey(OtaPackageType.SOFTWARE, OtaPackageKey.SIZE).equals(pathName);
}
}

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java

@ -31,7 +31,7 @@ import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
@ -120,8 +120,8 @@ public class LwM2mClient implements Cloneable {
this.init = false;
this.queuedRequests = new ConcurrentLinkedQueue<>();
this.fwUpdate = new LwM2mFwSwUpdate(this, FirmwareType.FIRMWARE);
this.swUpdate = new LwM2mFwSwUpdate(this, FirmwareType.SOFTWARE);
this.fwUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.FIRMWARE);
this.swUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.SOFTWARE);
if (this.credentials != null && this.credentials.hasDeviceInfo()) {
this.session = createSession(nodeId, sessionId, credentials);
this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());

10
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -83,11 +83,17 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
@Override
public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) {
return lwM2mClientsByEndpoint.values().stream().filter(c ->
LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c ->
(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()))
.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB())))
).findAny().get();
if (lwM2mClient == null) {
log.warn("Device TimeOut? lwM2mClient is null.");
log.warn("SessionInfo input [{}], lwM2mClientsByEndpoint size: [{}]", sessionInfo, lwM2mClientsByEndpoint.values().size());
log.error("", new RuntimeException());
}
return lwM2mClient;
}
@Override
@ -116,7 +122,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
securityInfo.getDeviceProfile().getUuidId() : null;
// TODO: for tests bug.
if (profileUuid== null) {
log.warn("input parameters toClientProfile if the result is null: [{}]", securityInfo.getDeviceProfile());
log.trace("input parameters toClientProfile if the result is null: [{}]", securityInfo.getDeviceProfile());
}
LwM2mClient client;
if (securityInfo.getSecurityInfo() != null) {

89
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java

@ -20,8 +20,8 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.leshan.core.request.ContentFormat;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportRequest;
@ -32,11 +32,12 @@ import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
import static org.thingsboard.server.common.data.firmware.FirmwareKey.STATE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE;
import static org.thingsboard.server.common.data.firmware.FirmwareUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.firmware.FirmwareUtil.getAttributeKey;
import static org.thingsboard.server.common.data.ota.OtaPackageKey.STATE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.ota.OtaPackageUtil.getAttributeKey;
import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_NAME_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_PACKAGE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
@ -97,14 +98,17 @@ public class LwM2mFwSwUpdate {
@Getter
@Setter
private volatile boolean infoFwSwUpdate = false;
private final FirmwareType type;
private final OtaPackageType type;
@Getter
LwM2mClient lwM2MClient;
@Getter
@Setter
private final List<String> pendingInfoRequestsStart;
@Getter
@Setter
private volatile Lwm2mClientRpcRequest rpcRequest;
public LwM2mFwSwUpdate(LwM2mClient lwM2MClient, FirmwareType type) {
public LwM2mFwSwUpdate(LwM2mClient lwM2MClient, OtaPackageType type) {
this.lwM2MClient = lwM2MClient;
this.pendingInfoRequestsStart = new CopyOnWriteArrayList<>();
this.type = type;
@ -139,7 +143,7 @@ public class LwM2mFwSwUpdate {
}
if (this.pendingInfoRequestsStart.size() == 0) {
this.infoFwSwUpdate = false;
if (!FirmwareUpdateStatus.DOWNLOADING.name().equals(this.stateUpdate)) {
if (!OtaPackageUpdateStatus.DOWNLOADING.name().equals(this.stateUpdate)) {
boolean conditionalStart = this.type.equals(FIRMWARE) ? this.conditionalFwUpdateStart() :
this.conditionalSwUpdateStart();
if (conditionalStart) {
@ -153,16 +157,30 @@ public class LwM2mFwSwUpdate {
* Send FsSw to Lwm2mClient:
* before operation Write: fw_state = DOWNLOADING
*/
private void writeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
this.stateUpdate = FirmwareUpdateStatus.DOWNLOADING.name();
// this.observeStateUpdate();
this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
int chunkSize = 0;
int chunk = 0;
byte[] firmwareChunk = handler.firmwareDataCache.get(this.currentId.toString(), chunkSize, chunk);
String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration());
request.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
firmwareChunk, handler.config.getTimeout(), null);
public void writeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
if (this.currentId != null) {
this.stateUpdate = OtaPackageUpdateStatus.DOWNLOADING.name();
this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
int chunkSize = 0;
int chunk = 0;
byte[] firmwareChunk = handler.otaPackageDataCache.get(this.currentId.toString(), chunkSize, chunk);
String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration());
String fwMsg = String.format("%s: Start type operation %s paths: %s", LOG_LW2M_INFO,
LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE.name(), FW_PACKAGE_ID);
handler.sendLogsToThingsboard(fwMsg, lwM2MClient.getRegistration().getId());
log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer);
request.sendAllRequest(this.lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
firmwareChunk, handler.config.getTimeout(), this.rpcRequest);
}
else {
String msgError = "FirmWareId is null.";
log.warn("6) [{}]", msgError);
if (this.rpcRequest != null) {
handler.sentRpcResponse(this.rpcRequest, CONTENT.name(), msgError, LOG_LW2M_ERROR);
}
log.error (msgError);
this.sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);
}
}
public void sendLogs(DefaultLwM2MTransportMsgHandler handler, String typeOper, String typeInfo, String msgError) {
@ -185,17 +203,16 @@ public class LwM2mFwSwUpdate {
this.setStateUpdate(UPDATING.name());
this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
request.sendAllRequest(this.lwM2MClient.getRegistration(), this.pathInstallId, EXECUTE, ContentFormat.TLV.getName(),
null, 0, null);
null, 0, this.rpcRequest);
}
/**
* Firmware start:
* -- Если Update Result -errors (более 1) - Это означает что пред. апдейт не прошел.
* - Запускаем апдейт в независимости от состяния прошивки и ее версии.
* -- Если Update Result - не errors (менее или равно 1) и ver не пустой - Это означает что пред. апдейт прошел.
* -- Если Update Result - не errors и ver пустой - Это означает что апдейта еще не было.
* - Проверяем поменялась ли версия и запускаем новый апдейт.
* -- If the result of the update - errors (more than 1) - This means that the previous. the update failed.
* - We launch the update regardless of the state of the firmware and its version.
* -- If the result of the update is not errors (equal to 1 or 0) and ver is not empty - This means that before the update has passed.
* -- If the result of the update is not errors and is empty - This means that there has not been an update yet.
* - Check if the version has changed and launch a new update.
*/
private boolean conditionalFwUpdateStart() {
Long updateResultFw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
@ -241,12 +258,12 @@ public class LwM2mFwSwUpdate {
/**
* Software start
* -- Если Update Result -errors (равно и более 50) - Это означает что пред. апдейт не прошел.
* * - Запускаем апдейт в независимости от состяния прошивки и ее версии.
* -- Если Update Result - не errors (менее 50) и ver не пустой - Это означает что пред. апдейт прошел.
* -- Если Update Result - не errors и ver пустой - Это означает что апдейта еще не было или пред. апдейт UnInstall
* -- Если Update Result - не errors и ver не пустой - Это означает что пред. апдейт UnInstall
* - Проверяем поменялась ли версия и запускаем новый апдейт.
* - If Update Result -errors (equal or more than 50) - This means that the previous. the update failed.
* * - We launch the update regardless of the state of the firmware and its version.
* - If Update Result is not errors (less than 50) and ver is not empty - This means that before. the update has passed.
* - If Update Result is not errors and ver is empty - This means that there was no update yet or before. UnInstall update
* - If Update Result is not errors and ver is not empty - This means that before unInstall update
* * - Check if the version has changed and launch a new update.
*/
private boolean conditionalSwUpdateStart() {
Long updateResultSw = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
@ -288,10 +305,10 @@ public class LwM2mFwSwUpdate {
LwM2mTransportUtil.UpdateResultSw.fromUpdateResultSwByCode(updateResult.intValue()).type;
String key = splitCamelCaseString((String) this.lwM2MClient.getResourceNameByRezId(null, this.pathResultId));
if (success) {
this.stateUpdate = FirmwareUpdateStatus.UPDATED.name();
this.stateUpdate = OtaPackageUpdateStatus.UPDATED.name();
this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
} else {
this.stateUpdate = FirmwareUpdateStatus.FAILED.name();
this.stateUpdate = OtaPackageUpdateStatus.FAILED.name();
this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_ERROR, value);
}
handler.helper.sendParametersOnThingsboardTelemetry(
@ -348,7 +365,7 @@ public class LwM2mFwSwUpdate {
this.pathResultId, this.lwM2MClient.getRegistration()));
this.pendingInfoRequestsStart.forEach(pathIdVer -> {
request.sendAllRequest(this.lwM2MClient.getRegistration(), pathIdVer, OBSERVE, ContentFormat.TLV.getName(),
null, 0, null);
null, 0, this.rpcRequest);
});
}

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/Lwm2mClientRpcRequest.java

@ -39,6 +39,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.K
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_ALL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
@ -140,7 +141,8 @@ public class Lwm2mClientRpcRequest {
if (this.getTargetIdVer() == null
&& !(OBSERVE_READ_ALL == this.getTypeOper()
|| DISCOVER_ALL == this.getTypeOper()
|| OBSERVE_CANCEL == this.getTypeOper())) {
|| OBSERVE_CANCEL == this.getTypeOper()
|| FW_UPDATE == this.getTypeOper())) {
this.setErrorMsg(TARGET_ID_VER_KEY + " and " +
KEY_NAME_KEY + " is null or bad format");
}

15
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java

@ -214,9 +214,9 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
// Add or update expiration
addOrUpdateExpiration(connection, updatedRegistration);
// Update secondary index :
// If registration is already associated to this address we don't care as we only want to keep the most
// recent binding.
/** Update secondary index :
* If registration is already associated to this address we don't care as we only want to keep the most
* recent binding. */
byte[] addr_idx = toRegAddrKey(updatedRegistration.getSocketAddress());
connection.set(addr_idx, updatedRegistration.getEndpoint().getBytes(UTF_8));
if (!r.getSocketAddress().equals(updatedRegistration.getSocketAddress())) {
@ -337,23 +337,24 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
}
}
//TODO: JedisCluster didn't implement Transaction, maybe should use some advanced key creation strategies
private void removeAddrIndex(RedisConnection connection, Registration registration) {
// Watch the key to remove.
byte[] regAddrKey = toRegAddrKey(registration.getSocketAddress());
connection.watch(regAddrKey);
// connection.watch(regAddrKey);
byte[] epFromAddr = connection.get(regAddrKey);
// Delete the key if needed.
if (Arrays.equals(epFromAddr, registration.getEndpoint().getBytes(UTF_8))) {
// Try to delete the key
connection.multi();
// connection.multi();
connection.del(regAddrKey);
connection.exec();
// connection.exec();
// if transaction failed this is not an issue as the socket address is probably reused and we don't neeed to
// delete it anymore.
} else {
// the key must not be deleted.
connection.unwatch();
// connection.unwatch();
}
}

3
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java

@ -43,6 +43,9 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
@Override
public Object convertValue(Object value, Type currentType, Type expectedType, LwM2mPath resourcePath)
throws CodecException {
if (value == null) {
return null;
}
if (expectedType == null) {
/** unknown resource, trusted value */
return value;

58
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java

@ -47,8 +47,8 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
import org.thingsboard.server.common.transport.SessionMsgListener;
@ -126,8 +126,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
private volatile InetSocketAddress address;
private volatile GatewaySessionHandler gatewaySessionHandler;
private final ConcurrentHashMap<String, String> fwSessions;
private final ConcurrentHashMap<String, Integer> fwChunkSizes;
private final ConcurrentHashMap<String, String> otaPackSessions;
private final ConcurrentHashMap<String, Integer> chunkSizes;
MqttTransportHandler(MqttTransportContext context, SslHandler sslHandler) {
this.sessionId = UUID.randomUUID();
@ -137,8 +137,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
this.sslHandler = sslHandler;
this.mqttQoSMap = new ConcurrentHashMap<>();
this.deviceSessionCtx = new DeviceSessionCtx(sessionId, mqttQoSMap, context);
this.fwSessions = new ConcurrentHashMap<>();
this.fwChunkSizes = new ConcurrentHashMap<>();
this.otaPackSessions = new ConcurrentHashMap<>();
this.chunkSizes = new ConcurrentHashMap<>();
}
@Override
@ -320,9 +320,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg);
transportService.process(deviceSessionCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(ctx, msgId, claimDeviceMsg));
} else if ((fwMatcher = FW_REQUEST_PATTERN.matcher(topicName)).find()) {
getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.FIRMWARE);
getOtaPackageCallback(ctx, mqttMsg, msgId, fwMatcher, OtaPackageType.FIRMWARE);
} else if ((fwMatcher = SW_REQUEST_PATTERN.matcher(topicName)).find()) {
getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.SOFTWARE);
getOtaPackageCallback(ctx, mqttMsg, msgId, fwMatcher, OtaPackageType.SOFTWARE);
} else {
transportService.reportActivity(deviceSessionCtx.getSessionInfo());
ack(ctx, msgId);
@ -334,38 +334,38 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
}
private void getFirmwareCallback(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, int msgId, Matcher fwMatcher, FirmwareType type) {
private void getOtaPackageCallback(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, int msgId, Matcher fwMatcher, OtaPackageType type) {
String payload = mqttMsg.content().toString(UTF8);
int chunkSize = StringUtils.isNotEmpty(payload) ? Integer.parseInt(payload) : 0;
String requestId = fwMatcher.group("requestId");
int chunk = Integer.parseInt(fwMatcher.group("chunk"));
if (chunkSize > 0) {
this.fwChunkSizes.put(requestId, chunkSize);
this.chunkSizes.put(requestId, chunkSize);
} else {
chunkSize = fwChunkSizes.getOrDefault(requestId, 0);
chunkSize = chunkSizes.getOrDefault(requestId, 0);
}
if (chunkSize > context.getMaxPayloadSize()) {
sendFirmwareError(ctx, PAYLOAD_TOO_LARGE);
sendOtaPackageError(ctx, PAYLOAD_TOO_LARGE);
return;
}
String firmwareId = fwSessions.get(requestId);
String otaPackageId = otaPackSessions.get(requestId);
if (firmwareId != null) {
sendFirmware(ctx, mqttMsg.variableHeader().packetId(), firmwareId, requestId, chunkSize, chunk, type);
if (otaPackageId != null) {
sendOtaPackage(ctx, mqttMsg.variableHeader().packetId(), otaPackageId, requestId, chunkSize, chunk, type);
} else {
TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo();
TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
TransportProtos.GetOtaPackageRequestMsg getOtaPackageRequestMsg = TransportProtos.GetOtaPackageRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
.setDeviceIdLSB(sessionInfo.getDeviceIdLSB())
.setTenantIdMSB(sessionInfo.getTenantIdMSB())
.setTenantIdLSB(sessionInfo.getTenantIdLSB())
.setType(type.name())
.build();
transportService.process(deviceSessionCtx.getSessionInfo(), getFirmwareRequestMsg,
new FirmwareCallback(ctx, msgId, getFirmwareRequestMsg, requestId, chunkSize, chunk));
transportService.process(deviceSessionCtx.getSessionInfo(), getOtaPackageRequestMsg,
new OtaPackageCallback(ctx, msgId, getOtaPackageRequestMsg, requestId, chunkSize, chunk));
}
}
@ -425,15 +425,15 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
}
private class FirmwareCallback implements TransportServiceCallback<TransportProtos.GetFirmwareResponseMsg> {
private class OtaPackageCallback implements TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> {
private final ChannelHandlerContext ctx;
private final int msgId;
private final TransportProtos.GetFirmwareRequestMsg msg;
private final TransportProtos.GetOtaPackageRequestMsg msg;
private final String requestId;
private final int chunkSize;
private final int chunk;
FirmwareCallback(ChannelHandlerContext ctx, int msgId, TransportProtos.GetFirmwareRequestMsg msg, String requestId, int chunkSize, int chunk) {
OtaPackageCallback(ChannelHandlerContext ctx, int msgId, TransportProtos.GetOtaPackageRequestMsg msg, String requestId, int chunkSize, int chunk) {
this.ctx = ctx;
this.msgId = msgId;
this.msg = msg;
@ -443,13 +443,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
@Override
public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) {
public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) {
FirmwareId firmwareId = new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB()));
fwSessions.put(requestId, firmwareId.toString());
sendFirmware(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, FirmwareType.valueOf(response.getType()));
OtaPackageId firmwareId = new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB()));
otaPackSessions.put(requestId, firmwareId.toString());
sendOtaPackage(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, OtaPackageType.valueOf(response.getType()));
} else {
sendFirmwareError(ctx, response.getResponseStatus().toString());
sendOtaPackageError(ctx, response.getResponseStatus().toString());
}
}
@ -460,11 +460,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
}
private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, FirmwareType type) {
private void sendOtaPackage(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, OtaPackageType type) {
log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId);
ack(ctx, msgId);
try {
byte[] firmwareChunk = context.getFirmwareDataCache().get(firmwareId, chunkSize, chunk);
byte[] firmwareChunk = context.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk);
deviceSessionCtx.getPayloadAdaptor()
.convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk, type)
.ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
@ -473,7 +473,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
}
}
private void sendFirmwareError(ChannelHandlerContext ctx, String error) {
private void sendOtaPackageError(ChannelHandlerContext ctx, String error) {
log.warn("[{}] {}", sessionId, error);
deviceSessionCtx.getChannel().writeAndFlush(deviceSessionCtx
.getPayloadAdaptor()

4
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java

@ -30,7 +30,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -155,7 +155,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor {
}
@Override
public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) {
public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) {
return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_SOFTWARE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk));
}

4
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java

@ -23,7 +23,7 @@ import io.netty.handler.codec.mqtt.MqttMessage;
import io.netty.handler.codec.mqtt.MqttMessageType;
import io.netty.handler.codec.mqtt.MqttPublishMessage;
import io.netty.handler.codec.mqtt.MqttPublishVariableHeader;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
@ -78,7 +78,7 @@ public interface MqttTransportAdaptor {
Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException;
Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException;
Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException;
default MqttPublishMessage createMqttPublishMsg(MqttDeviceAwareSessionContext ctx, String topic, byte[] payloadInBytes) {
MqttFixedHeader mqttFixedHeader =

4
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java

@ -28,7 +28,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.common.transport.adaptor.ProtoConverter;
@ -168,7 +168,7 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor {
}
@Override
public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException {
public Optional<MqttMessage> convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, OtaPackageType firmwareType) throws AdaptorException {
return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_SOFTWARE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk));
}

5
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java

@ -21,14 +21,13 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cache.firmware.FirmwareDataCache;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.scheduler.SchedulerComponent;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by ashvayka on 15.10.18.
@ -53,7 +52,7 @@ public abstract class TransportContext {
@Getter
@Autowired
private FirmwareDataCache firmwareDataCache;
private OtaPackageDataCache otaPackageDataCache;
@Autowired
private TransportResourceCache transportResourceCache;

6
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportService.java

@ -29,8 +29,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetOtaPackageRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetOtaPackageResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.GetResourceResponseMsg;
@ -115,7 +115,7 @@ public interface TransportService {
void process(TransportToDeviceActorMsg msg, TransportServiceCallback<Void> callback);
void process(SessionInfoProto sessionInfoProto, GetFirmwareRequestMsg msg, TransportServiceCallback<GetFirmwareResponseMsg> callback);
void process(SessionInfoProto sessionInfoProto, GetOtaPackageRequestMsg msg, TransportServiceCallback<GetOtaPackageResponseMsg> callback);
SessionMetaData registerAsyncSession(SessionInfoProto sessionInfo, SessionMsgListener listener);

6
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -614,13 +614,13 @@ public class DefaultTransportService implements TransportService {
}
@Override
public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.GetFirmwareRequestMsg msg, TransportServiceCallback<TransportProtos.GetFirmwareResponseMsg> callback) {
public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.GetOtaPackageRequestMsg msg, TransportServiceCallback<TransportProtos.GetOtaPackageResponseMsg> callback) {
if (checkLimits(sessionInfo, msg, callback)) {
TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg =
new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setFirmwareRequestMsg(msg).build());
new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setOtaPackageRequestMsg(msg).build());
AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), response -> {
callback.onSuccess(response.getValue().getFirmwareResponseMsg());
callback.onSuccess(response.getValue().getOtaPackageResponseMsg());
}, callback::onError, transportCallbackExecutor);
}
}

8
dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java

@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
@ -81,9 +82,12 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao {
*/
PageData<Device> findDevicesByTenantIdAndType(UUID tenantId, String type, PageLink pageLink);
PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink);
PageData<Device> findDevicesByTenantIdAndTypeAndEmptyOtaPackage(UUID tenantId,
UUID deviceProfileId,
OtaPackageType type,
PageLink pageLink);
PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(UUID tenantId, String type, PageLink pageLink);
Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(UUID tenantId, UUID deviceProfileId, OtaPackageType otaPackageType);
/**
* Find device infos by tenantId, type and page link.

16
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -43,7 +43,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
@ -57,7 +57,7 @@ import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfilePr
import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
@ -66,7 +66,7 @@ import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@ -119,7 +119,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
private CacheManager cacheManager;
@Autowired
private FirmwareService firmwareService;
private OtaPackageService otaPackageService;
@Autowired
private RuleChainService ruleChainService;
@ -427,11 +427,11 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
}
if (deviceProfile.getFirmwareId() != null) {
Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId());
OtaPackage firmware = otaPackageService.findOtaPackageById(tenantId, deviceProfile.getFirmwareId());
if (firmware == null) {
throw new DataValidationException("Can't assign non-existent firmware!");
}
if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
if (!firmware.getType().equals(OtaPackageType.FIRMWARE)) {
throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
}
if (firmware.getData() == null) {
@ -443,11 +443,11 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
}
if (deviceProfile.getSoftwareId() != null) {
Firmware software = firmwareService.findFirmwareById(tenantId, deviceProfile.getSoftwareId());
OtaPackage software = otaPackageService.findOtaPackageById(tenantId, deviceProfile.getSoftwareId());
if (software == null) {
throw new DataValidationException("Can't assign non-existent software!");
}
if (!software.getType().equals(FirmwareType.SOFTWARE)) {
if (!software.getType().equals(OtaPackageType.SOFTWARE)) {
throw new DataValidationException("Can't assign software with type: " + software.getType());
}
if (software.getData() == null) {

52
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -32,6 +32,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo;
@ -40,7 +41,7 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
@ -53,13 +54,13 @@ import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfig
import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration;
import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
@ -75,12 +76,11 @@ import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.common.util.JacksonUtil;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -138,7 +138,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
private TbTenantProfileCache tenantProfileCache;
@Autowired
private FirmwareService firmwareService;
private OtaPackageService otaPackageService;
@Override
public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) {
@ -200,11 +200,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
Device savedDevice = this.saveDeviceWithoutCredentials(device);
deviceCredentials.setDeviceId(savedDevice.getId());
if (device.getId() == null) {
deviceCredentials = deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
}
else {
deviceCredentials.setId(deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), savedDevice.getId()).getId());
deviceCredentials = deviceCredentialsService.updateDeviceCredentials(device.getTenantId(), deviceCredentials);
deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
} else {
DeviceCredentials foundDeviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), savedDevice.getId());
if (foundDeviceCredentials == null) {
deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
} else {
deviceCredentialsService.updateDeviceCredentials(device.getTenantId(), deviceCredentials);
}
}
return savedDevice;
}
@ -359,21 +362,24 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
}
@Override
public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndTypeAndEmptyFirmware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyOtaPackage(TenantId tenantId,
DeviceProfileId deviceProfileId,
OtaPackageType type,
PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndTypeAndEmptyOtaPackage, tenantId [{}], deviceProfileId [{}], type [{}], pageLink [{}]",
tenantId, deviceProfileId, type, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validateString(type, "Incorrect type " + type);
validateId(tenantId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId);
validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId.getId(), type, pageLink);
return deviceDao.findDevicesByTenantIdAndTypeAndEmptyOtaPackage(tenantId.getId(), deviceProfileId.getId(), type, pageLink);
}
@Override
public PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink) {
log.trace("Executing findDevicesByTenantIdAndTypeAndEmptySoftware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink);
public Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType type) {
log.trace("Executing countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage, tenantId [{}], deviceProfileId [{}], type [{}]", tenantId, deviceProfileId, type);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validateString(type, "Incorrect type " + type);
validatePageLink(pageLink);
return deviceDao.findDevicesByTenantIdAndTypeAndEmptySoftware(tenantId.getId(), type, pageLink);
validateId(tenantId, INCORRECT_DEVICE_PROFILE_ID + deviceProfileId);
return deviceDao.countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(tenantId.getId(), deviceProfileId.getId(), type);
}
@Override
@ -703,11 +709,11 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
.ifPresent(DeviceTransportConfiguration::validate);
if (device.getFirmwareId() != null) {
Firmware firmware = firmwareService.findFirmwareById(tenantId, device.getFirmwareId());
OtaPackage firmware = otaPackageService.findOtaPackageById(tenantId, device.getFirmwareId());
if (firmware == null) {
throw new DataValidationException("Can't assign non-existent firmware!");
}
if (!firmware.getType().equals(FirmwareType.FIRMWARE)) {
if (!firmware.getType().equals(OtaPackageType.FIRMWARE)) {
throw new DataValidationException("Can't assign firmware with type: " + firmware.getType());
}
if (firmware.getData() == null) {
@ -719,11 +725,11 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
}
if (device.getSoftwareId() != null) {
Firmware software = firmwareService.findFirmwareById(tenantId, device.getSoftwareId());
OtaPackage software = otaPackageService.findOtaPackageById(tenantId, device.getSoftwareId());
if (software == null) {
throw new DataValidationException("Can't assign non-existent software!");
}
if (!software.getType().equals(FirmwareType.SOFTWARE)) {
if (!software.getType().equals(OtaPackageType.SOFTWARE)) {
throw new DataValidationException("Can't assign software with type: " + software.getType());
}
if (software.getData() == null) {

12
dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java

@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
@ -49,7 +49,7 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
@ -102,7 +102,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
private ResourceService resourceService;
@Autowired
private FirmwareService firmwareService;
private OtaPackageService otaPackageService;
@Override
public void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
@ -167,8 +167,8 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
case TB_RESOURCE:
hasName = resourceService.findResourceInfoByIdAsync(tenantId, new TbResourceId(entityId.getId()));
break;
case FIRMWARE:
hasName = firmwareService.findFirmwareInfoByIdAsync(tenantId, new FirmwareId(entityId.getId()));
case OTA_PACKAGE:
hasName = otaPackageService.findOtaPackageInfoByIdAsync(tenantId, new OtaPackageId(entityId.getId()));
break;
default:
throw new IllegalStateException("Not Implemented!");
@ -192,7 +192,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
case DEVICE_PROFILE:
case API_USAGE_STATE:
case TB_RESOURCE:
case FIRMWARE:
case OTA_PACKAGE:
break;
case CUSTOMER:
hasCustomerId = () -> new CustomerId(entityId.getId());

379
dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java

@ -1,379 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.firmware;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.firmware.FirmwareDataCache;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.device.DeviceProfileDao;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.tenant.TenantDao;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
@Service
@Slf4j
@RequiredArgsConstructor
public class BaseFirmwareService implements FirmwareService {
public static final String INCORRECT_FIRMWARE_ID = "Incorrect firmwareId ";
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
private final TenantDao tenantDao;
private final DeviceProfileDao deviceProfileDao;
private final FirmwareDao firmwareDao;
private final FirmwareInfoDao firmwareInfoDao;
private final CacheManager cacheManager;
private final FirmwareDataCache firmwareDataCache;
@Override
public FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo) {
log.trace("Executing saveFirmwareInfo [{}]", firmwareInfo);
firmwareInfoValidator.validate(firmwareInfo, FirmwareInfo::getTenantId);
try {
FirmwareId firmwareId = firmwareInfo.getId();
if (firmwareId != null) {
Cache cache = cacheManager.getCache(FIRMWARE_CACHE);
cache.evict(toFirmwareInfoKey(firmwareId));
firmwareDataCache.evict(firmwareId.toString());
}
return firmwareInfoDao.save(firmwareInfo.getTenantId(), firmwareInfo);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("firmware_tenant_title_version_unq_key")) {
throw new DataValidationException("Firmware with such title and version already exists!");
} else {
throw t;
}
}
}
@Override
public Firmware saveFirmware(Firmware firmware) {
log.trace("Executing saveFirmware [{}]", firmware);
firmwareValidator.validate(firmware, FirmwareInfo::getTenantId);
try {
FirmwareId firmwareId = firmware.getId();
if (firmwareId != null) {
Cache cache = cacheManager.getCache(FIRMWARE_CACHE);
cache.evict(toFirmwareInfoKey(firmwareId));
firmwareDataCache.evict(firmwareId.toString());
}
return firmwareDao.save(firmware.getTenantId(), firmware);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("firmware_tenant_title_version_unq_key")) {
throw new DataValidationException("Firmware with such title and version already exists!");
} else {
throw t;
}
}
}
@Override
public String generateChecksum(ChecksumAlgorithm checksumAlgorithm, ByteBuffer data) {
if (data == null || !data.hasArray() || data.array().length == 0) {
throw new DataValidationException("Firmware data should be specified!");
}
return getHashFunction(checksumAlgorithm).hashBytes(data.array()).toString();
}
private HashFunction getHashFunction(ChecksumAlgorithm checksumAlgorithm) {
switch (checksumAlgorithm) {
case MD5:
return Hashing.md5();
case SHA256:
return Hashing.sha256();
case SHA384:
return Hashing.sha384();
case SHA512:
return Hashing.sha512();
case CRC32:
return Hashing.crc32();
case MURMUR3_32:
return Hashing.murmur3_32();
case MURMUR3_128:
return Hashing.murmur3_128();
default:
throw new DataValidationException("Unknown checksum algorithm!");
}
}
@Override
public Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId) {
log.trace("Executing findFirmwareById [{}]", firmwareId);
validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId);
return firmwareDao.findById(tenantId, firmwareId.getId());
}
@Override
@Cacheable(cacheNames = FIRMWARE_CACHE, key = "{#firmwareId}")
public FirmwareInfo findFirmwareInfoById(TenantId tenantId, FirmwareId firmwareId) {
log.trace("Executing findFirmwareInfoById [{}]", firmwareId);
validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId);
return firmwareInfoDao.findById(tenantId, firmwareId.getId());
}
@Override
public ListenableFuture<FirmwareInfo> findFirmwareInfoByIdAsync(TenantId tenantId, FirmwareId firmwareId) {
log.trace("Executing findFirmwareInfoByIdAsync [{}]", firmwareId);
validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId);
return firmwareInfoDao.findByIdAsync(tenantId, firmwareId.getId());
}
@Override
public PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findTenantFirmwaresByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validatePageLink(pageLink);
return firmwareInfoDao.findFirmwareInfoByTenantId(tenantId, pageLink);
}
@Override
public PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink) {
log.trace("Executing findTenantFirmwaresByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validatePageLink(pageLink);
return firmwareInfoDao.findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, firmwareType, hasData, pageLink);
}
@Override
public void deleteFirmware(TenantId tenantId, FirmwareId firmwareId) {
log.trace("Executing deleteFirmware [{}]", firmwareId);
validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId);
try {
Cache cache = cacheManager.getCache(FIRMWARE_CACHE);
cache.evict(toFirmwareInfoKey(firmwareId));
firmwareDataCache.evict(firmwareId.toString());
firmwareDao.removeById(tenantId, firmwareId.getId());
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device")) {
throw new DataValidationException("The firmware referenced by the devices cannot be deleted!");
} else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device_profile")) {
throw new DataValidationException("The firmware referenced by the device profile cannot be deleted!");
} else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_software_device")) {
throw new DataValidationException("The software referenced by the devices cannot be deleted!");
} else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_software_device_profile")) {
throw new DataValidationException("The software referenced by the device profile cannot be deleted!");
} else {
throw t;
}
}
}
@Override
public void deleteFirmwaresByTenantId(TenantId tenantId) {
log.trace("Executing deleteFirmwaresByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
tenantFirmwareRemover.removeEntities(tenantId, tenantId);
}
private DataValidator<FirmwareInfo> firmwareInfoValidator = new DataValidator<>() {
@Override
protected void validateDataImpl(TenantId tenantId, FirmwareInfo firmwareInfo) {
validateImpl(firmwareInfo);
}
@Override
protected void validateUpdate(TenantId tenantId, FirmwareInfo firmware) {
FirmwareInfo firmwareOld = firmwareInfoDao.findById(tenantId, firmware.getUuidId());
validateUpdateDeviceProfile(firmware, firmwareOld);
BaseFirmwareService.validateUpdate(firmware, firmwareOld);
}
};
private DataValidator<Firmware> firmwareValidator = new DataValidator<>() {
@Override
protected void validateDataImpl(TenantId tenantId, Firmware firmware) {
validateImpl(firmware);
if (StringUtils.isEmpty(firmware.getFileName())) {
throw new DataValidationException("Firmware file name should be specified!");
}
if (StringUtils.isEmpty(firmware.getContentType())) {
throw new DataValidationException("Firmware content type should be specified!");
}
if (firmware.getChecksumAlgorithm() == null) {
throw new DataValidationException("Firmware checksum algorithm should be specified!");
}
if (StringUtils.isEmpty(firmware.getChecksum())) {
throw new DataValidationException("Firmware checksum should be specified!");
}
String currentChecksum;
currentChecksum = generateChecksum(firmware.getChecksumAlgorithm(), firmware.getData());
if (!currentChecksum.equals(firmware.getChecksum())) {
throw new DataValidationException("Wrong firmware file!");
}
}
@Override
protected void validateUpdate(TenantId tenantId, Firmware firmware) {
Firmware firmwareOld = firmwareDao.findById(tenantId, firmware.getUuidId());
validateUpdateDeviceProfile(firmware, firmwareOld);
BaseFirmwareService.validateUpdate(firmware, firmwareOld);
if (firmwareOld.getData() != null && !firmwareOld.getData().equals(firmware.getData())) {
throw new DataValidationException("Updating firmware data is prohibited!");
}
}
};
private void validateUpdateDeviceProfile(FirmwareInfo firmware, FirmwareInfo firmwareOld) {
if (firmwareOld.getDeviceProfileId() != null && !firmwareOld.getDeviceProfileId().equals(firmware.getDeviceProfileId())) {
if (firmwareInfoDao.isFirmwareUsed(firmwareOld.getId(), firmware.getType(), firmwareOld.getDeviceProfileId())) {
throw new DataValidationException("Can`t update deviceProfileId because firmware is already in use!");
}
}
}
private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) {
if (!firmwareOld.getType().equals(firmware.getType())) {
throw new DataValidationException("Updating type is prohibited!");
}
if (!firmwareOld.getTitle().equals(firmware.getTitle())) {
throw new DataValidationException("Updating firmware title is prohibited!");
}
if (!firmwareOld.getVersion().equals(firmware.getVersion())) {
throw new DataValidationException("Updating firmware version is prohibited!");
}
if (firmwareOld.getFileName() != null && !firmwareOld.getFileName().equals(firmware.getFileName())) {
throw new DataValidationException("Updating firmware file name is prohibited!");
}
if (firmwareOld.getContentType() != null && !firmwareOld.getContentType().equals(firmware.getContentType())) {
throw new DataValidationException("Updating firmware content type is prohibited!");
}
if (firmwareOld.getChecksumAlgorithm() != null && !firmwareOld.getChecksumAlgorithm().equals(firmware.getChecksumAlgorithm())) {
throw new DataValidationException("Updating firmware content type is prohibited!");
}
if (firmwareOld.getChecksum() != null && !firmwareOld.getChecksum().equals(firmware.getChecksum())) {
throw new DataValidationException("Updating firmware content type is prohibited!");
}
if (firmwareOld.getDataSize() != null && !firmwareOld.getDataSize().equals(firmware.getDataSize())) {
throw new DataValidationException("Updating firmware data size is prohibited!");
}
}
private void validateImpl(FirmwareInfo firmwareInfo) {
if (firmwareInfo.getTenantId() == null) {
throw new DataValidationException("Firmware should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(firmwareInfo.getTenantId(), firmwareInfo.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Firmware is referencing to non-existent tenant!");
}
}
if (firmwareInfo.getDeviceProfileId() != null) {
DeviceProfile deviceProfile = deviceProfileDao.findById(firmwareInfo.getTenantId(), firmwareInfo.getDeviceProfileId().getId());
if (deviceProfile == null) {
throw new DataValidationException("Firmware is referencing to non-existent device profile!");
}
}
if (firmwareInfo.getType() == null) {
throw new DataValidationException("Type should be specified!");
}
if (StringUtils.isEmpty(firmwareInfo.getTitle())) {
throw new DataValidationException("Firmware title should be specified!");
}
if (StringUtils.isEmpty(firmwareInfo.getVersion())) {
throw new DataValidationException("Firmware version should be specified!");
}
}
private PaginatedRemover<TenantId, FirmwareInfo> tenantFirmwareRemover =
new PaginatedRemover<>() {
@Override
protected PageData<FirmwareInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return firmwareInfoDao.findFirmwareInfoByTenantId(id, pageLink);
}
@Override
protected void removeEntity(TenantId tenantId, FirmwareInfo entity) {
deleteFirmware(tenantId, entity.getId());
}
};
protected Optional<ConstraintViolationException> extractConstraintViolationException(Exception t) {
if (t instanceof ConstraintViolationException) {
return Optional.of((ConstraintViolationException) t);
} else if (t.getCause() instanceof ConstraintViolationException) {
return Optional.of((ConstraintViolationException) (t.getCause()));
} else {
return Optional.empty();
}
}
private static List<FirmwareId> toFirmwareInfoKey(FirmwareId firmwareId) {
return Collections.singletonList(firmwareId);
}
}

31
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -479,22 +479,21 @@ public class ModelConstants {
public static final String RESOURCE_DATA_COLUMN = "data";
/**
* Firmware constants.
*/
public static final String FIRMWARE_TABLE_NAME = "firmware";
public static final String FIRMWARE_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
public static final String FIRMWARE_DEVICE_PROFILE_ID_COLUMN = "device_profile_id";
public static final String FIRMWARE_TYPE_COLUMN = "type";
public static final String FIRMWARE_TITLE_COLUMN = TITLE_PROPERTY;
public static final String FIRMWARE_VERSION_COLUMN = "version";
public static final String FIRMWARE_FILE_NAME_COLUMN = "file_name";
public static final String FIRMWARE_CONTENT_TYPE_COLUMN = "content_type";
public static final String FIRMWARE_CHECKSUM_ALGORITHM_COLUMN = "checksum_algorithm";
public static final String FIRMWARE_CHECKSUM_COLUMN = "checksum";
public static final String FIRMWARE_DATA_COLUMN = "data";
public static final String FIRMWARE_DATA_SIZE_COLUMN = "data_size";
public static final String FIRMWARE_ADDITIONAL_INFO_COLUMN = ADDITIONAL_INFO_PROPERTY;
public static final String FIRMWARE_HAS_DATA_PROPERTY = "has_data";
* Ota Package constants.
*/
public static final String OTA_PACKAGE_TABLE_NAME = "ota_package";
public static final String OTA_PACKAGE_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
public static final String OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN = "device_profile_id";
public static final String OTA_PACKAGE_TYPE_COLUMN = "type";
public static final String OTA_PACKAGE_TILE_COLUMN = TITLE_PROPERTY;
public static final String OTA_PACKAGE_VERSION_COLUMN = "version";
public static final String OTA_PACKAGE_FILE_NAME_COLUMN = "file_name";
public static final String OTA_PACKAGE_CONTENT_TYPE_COLUMN = "content_type";
public static final String OTA_PACKAGE_CHECKSUM_ALGORITHM_COLUMN = "checksum_algorithm";
public static final String OTA_PACKAGE_CHECKSUM_COLUMN = "checksum";
public static final String OTA_PACKAGE_DATA_COLUMN = "data";
public static final String OTA_PACKAGE_DATA_SIZE_COLUMN = "data_size";
public static final String OTA_PACKAGE_ADDITIONAL_INFO_COLUMN = ADDITIONAL_INFO_PROPERTY;
/**
* Edge constants.

6
dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java

@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
@ -154,10 +154,10 @@ public abstract class AbstractDeviceEntity<T extends Device> extends BaseSqlEnti
device.setDeviceProfileId(new DeviceProfileId(deviceProfileId));
}
if (firmwareId != null) {
device.setFirmwareId(new FirmwareId(firmwareId));
device.setFirmwareId(new OtaPackageId(firmwareId));
}
if (softwareId != null) {
device.setSoftwareId(new FirmwareId(softwareId));
device.setSoftwareId(new OtaPackageId(softwareId));
}
device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class));
device.setName(name);

6
dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java

@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
@ -178,11 +178,11 @@ public final class DeviceProfileEntity extends BaseSqlEntity<DeviceProfile> impl
deviceProfile.setProvisionDeviceKey(provisionDeviceKey);
if (firmwareId != null) {
deviceProfile.setFirmwareId(new FirmwareId(firmwareId));
deviceProfile.setFirmwareId(new OtaPackageId(firmwareId));
}
if (softwareId != null) {
deviceProfile.setSoftwareId(new FirmwareId(softwareId));
deviceProfile.setSoftwareId(new OtaPackageId(softwareId));
}
return deviceProfile;

70
dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java → dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java

@ -20,11 +20,11 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
@ -40,75 +40,75 @@ import javax.persistence.Table;
import java.nio.ByteBuffer;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ALGORITHM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DEVICE_PROFILE_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_CHECKSUM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_CONTENT_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DATA_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DATA_SIZE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_FILE_NAME_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TENANT_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TILE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_VERSION_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = FIRMWARE_TABLE_NAME)
public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTextEntity<Firmware> {
@Table(name = OTA_PACKAGE_TABLE_NAME)
public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements SearchTextEntity<OtaPackage> {
@Column(name = FIRMWARE_TENANT_ID_COLUMN)
@Column(name = OTA_PACKAGE_TENANT_ID_COLUMN)
private UUID tenantId;
@Column(name = FIRMWARE_DEVICE_PROFILE_ID_COLUMN)
@Column(name = OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN)
private UUID deviceProfileId;
@Enumerated(EnumType.STRING)
@Column(name = FIRMWARE_TYPE_COLUMN)
private FirmwareType type;
@Column(name = OTA_PACKAGE_TYPE_COLUMN)
private OtaPackageType type;
@Column(name = FIRMWARE_TITLE_COLUMN)
@Column(name = OTA_PACKAGE_TILE_COLUMN)
private String title;
@Column(name = FIRMWARE_VERSION_COLUMN)
@Column(name = OTA_PACKAGE_VERSION_COLUMN)
private String version;
@Column(name = FIRMWARE_FILE_NAME_COLUMN)
@Column(name = OTA_PACKAGE_FILE_NAME_COLUMN)
private String fileName;
@Column(name = FIRMWARE_CONTENT_TYPE_COLUMN)
@Column(name = OTA_PACKAGE_CONTENT_TYPE_COLUMN)
private String contentType;
@Enumerated(EnumType.STRING)
@Column(name = FIRMWARE_CHECKSUM_ALGORITHM_COLUMN)
@Column(name = OTA_PACKAGE_CHECKSUM_ALGORITHM_COLUMN)
private ChecksumAlgorithm checksumAlgorithm;
@Column(name = FIRMWARE_CHECKSUM_COLUMN)
@Column(name = OTA_PACKAGE_CHECKSUM_COLUMN)
private String checksum;
@Lob
@Column(name = FIRMWARE_DATA_COLUMN, columnDefinition = "BINARY")
@Column(name = OTA_PACKAGE_DATA_COLUMN, columnDefinition = "BINARY")
private byte[] data;
@Column(name = FIRMWARE_DATA_SIZE_COLUMN)
@Column(name = OTA_PACKAGE_DATA_SIZE_COLUMN)
private Long dataSize;
@Type(type = "json")
@Column(name = ModelConstants.FIRMWARE_ADDITIONAL_INFO_COLUMN)
@Column(name = ModelConstants.OTA_PACKAGE_ADDITIONAL_INFO_COLUMN)
private JsonNode additionalInfo;
@Column(name = SEARCH_TEXT_PROPERTY)
private String searchText;
public FirmwareEntity() {
public OtaPackageEntity() {
super();
}
public FirmwareEntity(Firmware firmware) {
public OtaPackageEntity(OtaPackage firmware) {
this.createdTime = firmware.getCreatedTime();
this.setUuid(firmware.getUuidId());
this.tenantId = firmware.getTenantId().getId();
@ -138,8 +138,8 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
}
@Override
public Firmware toData() {
Firmware firmware = new Firmware(new FirmwareId(id));
public OtaPackage toData() {
OtaPackage firmware = new OtaPackage(new OtaPackageId(id));
firmware.setCreatedTime(createdTime);
firmware.setTenantId(new TenantId(tenantId));
if (deviceProfileId != null) {

72
dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java → dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageInfoEntity.java

@ -21,11 +21,11 @@ import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.ModelConstants;
@ -40,60 +40,60 @@ import javax.persistence.Table;
import javax.persistence.Transient;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ALGORITHM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_SIZE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DEVICE_PROFILE_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_CHECKSUM_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_CONTENT_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DATA_SIZE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_FILE_NAME_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TENANT_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TILE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_VERSION_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = FIRMWARE_TABLE_NAME)
public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements SearchTextEntity<FirmwareInfo> {
@Table(name = OTA_PACKAGE_TABLE_NAME)
public class OtaPackageInfoEntity extends BaseSqlEntity<OtaPackageInfo> implements SearchTextEntity<OtaPackageInfo> {
@Column(name = FIRMWARE_TENANT_ID_COLUMN)
@Column(name = OTA_PACKAGE_TENANT_ID_COLUMN)
private UUID tenantId;
@Column(name = FIRMWARE_DEVICE_PROFILE_ID_COLUMN)
@Column(name = OTA_PACKAGE_DEVICE_PROFILE_ID_COLUMN)
private UUID deviceProfileId;
@Enumerated(EnumType.STRING)
@Column(name = FIRMWARE_TYPE_COLUMN)
private FirmwareType type;
@Column(name = OTA_PACKAGE_TYPE_COLUMN)
private OtaPackageType type;
@Column(name = FIRMWARE_TITLE_COLUMN)
@Column(name = OTA_PACKAGE_TILE_COLUMN)
private String title;
@Column(name = FIRMWARE_VERSION_COLUMN)
@Column(name = OTA_PACKAGE_VERSION_COLUMN)
private String version;
@Column(name = FIRMWARE_FILE_NAME_COLUMN)
@Column(name = OTA_PACKAGE_FILE_NAME_COLUMN)
private String fileName;
@Column(name = FIRMWARE_CONTENT_TYPE_COLUMN)
@Column(name = OTA_PACKAGE_CONTENT_TYPE_COLUMN)
private String contentType;
@Enumerated(EnumType.STRING)
@Column(name = FIRMWARE_CHECKSUM_ALGORITHM_COLUMN)
@Column(name = OTA_PACKAGE_CHECKSUM_ALGORITHM_COLUMN)
private ChecksumAlgorithm checksumAlgorithm;
@Column(name = FIRMWARE_CHECKSUM_COLUMN)
@Column(name = OTA_PACKAGE_CHECKSUM_COLUMN)
private String checksum;
@Column(name = FIRMWARE_DATA_SIZE_COLUMN)
@Column(name = OTA_PACKAGE_DATA_SIZE_COLUMN)
private Long dataSize;
@Type(type = "json")
@Column(name = ModelConstants.FIRMWARE_ADDITIONAL_INFO_COLUMN)
@Column(name = ModelConstants.OTA_PACKAGE_ADDITIONAL_INFO_COLUMN)
private JsonNode additionalInfo;
@Column(name = SEARCH_TEXT_PROPERTY)
@ -102,11 +102,11 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
@Transient
private boolean hasData;
public FirmwareInfoEntity() {
public OtaPackageInfoEntity() {
super();
}
public FirmwareInfoEntity(FirmwareInfo firmware) {
public OtaPackageInfoEntity(OtaPackageInfo firmware) {
this.createdTime = firmware.getCreatedTime();
this.setUuid(firmware.getUuidId());
this.tenantId = firmware.getTenantId().getId();
@ -124,9 +124,9 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
this.additionalInfo = firmware.getAdditionalInfo();
}
public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, UUID deviceProfileId, FirmwareType type, String title, String version,
String fileName, String contentType, ChecksumAlgorithm checksumAlgorithm, String checksum, Long dataSize,
Object additionalInfo, boolean hasData) {
public OtaPackageInfoEntity(UUID id, long createdTime, UUID tenantId, UUID deviceProfileId, OtaPackageType type, String title, String version,
String fileName, String contentType, ChecksumAlgorithm checksumAlgorithm, String checksum, Long dataSize,
Object additionalInfo, boolean hasData) {
this.id = id;
this.createdTime = createdTime;
this.tenantId = tenantId;
@ -154,8 +154,8 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
}
@Override
public FirmwareInfo toData() {
FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id));
public OtaPackageInfo toData() {
OtaPackageInfo firmware = new OtaPackageInfo(new OtaPackageId(id));
firmware.setCreatedTime(createdTime);
firmware.setTenantId(new TenantId(tenantId));
if (deviceProfileId != null) {

366
dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java

@ -0,0 +1,366 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.ota;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.device.DeviceProfileDao;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.tenant.TenantDao;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_CACHE;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
@Service
@Slf4j
@RequiredArgsConstructor
public class BaseOtaPackageService implements OtaPackageService {
public static final String INCORRECT_OTA_PACKAGE_ID = "Incorrect otaPackageId ";
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
private final TenantDao tenantDao;
private final DeviceProfileDao deviceProfileDao;
private final OtaPackageDao otaPackageDao;
private final OtaPackageInfoDao otaPackageInfoDao;
private final CacheManager cacheManager;
private final OtaPackageDataCache otaPackageDataCache;
@Override
public OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo) {
log.trace("Executing saveOtaPackageInfo [{}]", otaPackageInfo);
otaPackageInfoValidator.validate(otaPackageInfo, OtaPackageInfo::getTenantId);
try {
OtaPackageId otaPackageId = otaPackageInfo.getId();
if (otaPackageId != null) {
Cache cache = cacheManager.getCache(OTA_PACKAGE_CACHE);
cache.evict(toOtaPackageInfoKey(otaPackageId));
otaPackageDataCache.evict(otaPackageId.toString());
}
return otaPackageInfoDao.save(otaPackageInfo.getTenantId(), otaPackageInfo);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("ota_package_tenant_title_version_unq_key")) {
throw new DataValidationException("OtaPackage with such title and version already exists!");
} else {
throw t;
}
}
}
@Override
public OtaPackage saveOtaPackage(OtaPackage otaPackage) {
log.trace("Executing saveOtaPackage [{}]", otaPackage);
otaPackageValidator.validate(otaPackage, OtaPackageInfo::getTenantId);
try {
OtaPackageId otaPackageId = otaPackage.getId();
if (otaPackageId != null) {
Cache cache = cacheManager.getCache(OTA_PACKAGE_CACHE);
cache.evict(toOtaPackageInfoKey(otaPackageId));
otaPackageDataCache.evict(otaPackageId.toString());
}
return otaPackageDao.save(otaPackage.getTenantId(), otaPackage);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("ota_package_tenant_title_version_unq_key")) {
throw new DataValidationException("OtaPackage with such title and version already exists!");
} else {
throw t;
}
}
}
@Override
public String generateChecksum(ChecksumAlgorithm checksumAlgorithm, ByteBuffer data) {
if (data == null || !data.hasArray() || data.array().length == 0) {
throw new DataValidationException("OtaPackage data should be specified!");
}
return getHashFunction(checksumAlgorithm).hashBytes(data.array()).toString();
}
private HashFunction getHashFunction(ChecksumAlgorithm checksumAlgorithm) {
switch (checksumAlgorithm) {
case MD5:
return Hashing.md5();
case SHA256:
return Hashing.sha256();
case SHA384:
return Hashing.sha384();
case SHA512:
return Hashing.sha512();
case CRC32:
return Hashing.crc32();
case MURMUR3_32:
return Hashing.murmur3_32();
case MURMUR3_128:
return Hashing.murmur3_128();
default:
throw new DataValidationException("Unknown checksum algorithm!");
}
}
@Override
public OtaPackage findOtaPackageById(TenantId tenantId, OtaPackageId otaPackageId) {
log.trace("Executing findOtaPackageById [{}]", otaPackageId);
validateId(otaPackageId, INCORRECT_OTA_PACKAGE_ID + otaPackageId);
return otaPackageDao.findById(tenantId, otaPackageId.getId());
}
@Override
@Cacheable(cacheNames = OTA_PACKAGE_CACHE, key = "{#otaPackageId}")
public OtaPackageInfo findOtaPackageInfoById(TenantId tenantId, OtaPackageId otaPackageId) {
log.trace("Executing findOtaPackageInfoById [{}]", otaPackageId);
validateId(otaPackageId, INCORRECT_OTA_PACKAGE_ID + otaPackageId);
return otaPackageInfoDao.findById(tenantId, otaPackageId.getId());
}
@Override
public ListenableFuture<OtaPackageInfo> findOtaPackageInfoByIdAsync(TenantId tenantId, OtaPackageId otaPackageId) {
log.trace("Executing findOtaPackageInfoByIdAsync [{}]", otaPackageId);
validateId(otaPackageId, INCORRECT_OTA_PACKAGE_ID + otaPackageId);
return otaPackageInfoDao.findByIdAsync(tenantId, otaPackageId.getId());
}
@Override
public PageData<OtaPackageInfo> findTenantOtaPackagesByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findTenantOtaPackagesByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validatePageLink(pageLink);
return otaPackageInfoDao.findOtaPackageInfoByTenantId(tenantId, pageLink);
}
@Override
public PageData<OtaPackageInfo> findTenantOtaPackagesByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType otaPackageType, boolean hasData, PageLink pageLink) {
log.trace("Executing findTenantOtaPackagesByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
validatePageLink(pageLink);
return otaPackageInfoDao.findOtaPackageInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, otaPackageType, hasData, pageLink);
}
@Override
public void deleteOtaPackage(TenantId tenantId, OtaPackageId otaPackageId) {
log.trace("Executing deleteOtaPackage [{}]", otaPackageId);
validateId(otaPackageId, INCORRECT_OTA_PACKAGE_ID + otaPackageId);
try {
Cache cache = cacheManager.getCache(OTA_PACKAGE_CACHE);
cache.evict(toOtaPackageInfoKey(otaPackageId));
otaPackageDataCache.evict(otaPackageId.toString());
otaPackageDao.removeById(tenantId, otaPackageId.getId());
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device")) {
throw new DataValidationException("The otaPackage referenced by the devices cannot be deleted!");
} else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_firmware_device_profile")) {
throw new DataValidationException("The otaPackage referenced by the device profile cannot be deleted!");
} else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_software_device")) {
throw new DataValidationException("The software referenced by the devices cannot be deleted!");
} else if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("fk_software_device_profile")) {
throw new DataValidationException("The software referenced by the device profile cannot be deleted!");
} else {
throw t;
}
}
}
@Override
public void deleteOtaPackagesByTenantId(TenantId tenantId) {
log.trace("Executing deleteOtaPackagesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
tenantOtaPackageRemover.removeEntities(tenantId, tenantId);
}
private DataValidator<OtaPackageInfo> otaPackageInfoValidator = new DataValidator<>() {
@Override
protected void validateDataImpl(TenantId tenantId, OtaPackageInfo otaPackageInfo) {
validateImpl(otaPackageInfo);
}
@Override
protected void validateUpdate(TenantId tenantId, OtaPackageInfo otaPackage) {
OtaPackageInfo otaPackageOld = otaPackageInfoDao.findById(tenantId, otaPackage.getUuidId());
BaseOtaPackageService.validateUpdate(otaPackage, otaPackageOld);
}
};
private DataValidator<OtaPackage> otaPackageValidator = new DataValidator<>() {
@Override
protected void validateDataImpl(TenantId tenantId, OtaPackage otaPackage) {
validateImpl(otaPackage);
if (StringUtils.isEmpty(otaPackage.getFileName())) {
throw new DataValidationException("OtaPackage file name should be specified!");
}
if (StringUtils.isEmpty(otaPackage.getContentType())) {
throw new DataValidationException("OtaPackage content type should be specified!");
}
if (otaPackage.getChecksumAlgorithm() == null) {
throw new DataValidationException("OtaPackage checksum algorithm should be specified!");
}
if (StringUtils.isEmpty(otaPackage.getChecksum())) {
throw new DataValidationException("OtaPackage checksum should be specified!");
}
String currentChecksum;
currentChecksum = generateChecksum(otaPackage.getChecksumAlgorithm(), otaPackage.getData());
if (!currentChecksum.equals(otaPackage.getChecksum())) {
throw new DataValidationException("Wrong otaPackage file!");
}
}
@Override
protected void validateUpdate(TenantId tenantId, OtaPackage otaPackage) {
OtaPackage otaPackageOld = otaPackageDao.findById(tenantId, otaPackage.getUuidId());
BaseOtaPackageService.validateUpdate(otaPackage, otaPackageOld);
if (otaPackageOld.getData() != null && !otaPackageOld.getData().equals(otaPackage.getData())) {
throw new DataValidationException("Updating otaPackage data is prohibited!");
}
}
};
private static void validateUpdate(OtaPackageInfo otaPackage, OtaPackageInfo otaPackageOld) {
if (!otaPackageOld.getType().equals(otaPackage.getType())) {
throw new DataValidationException("Updating type is prohibited!");
}
if (!otaPackageOld.getTitle().equals(otaPackage.getTitle())) {
throw new DataValidationException("Updating otaPackage title is prohibited!");
}
if (!otaPackageOld.getVersion().equals(otaPackage.getVersion())) {
throw new DataValidationException("Updating otaPackage version is prohibited!");
}
if (!otaPackageOld.getDeviceProfileId().equals(otaPackage.getDeviceProfileId())) {
throw new DataValidationException("Updating otaPackage deviceProfile is prohibited!");
}
if (otaPackageOld.getFileName() != null && !otaPackageOld.getFileName().equals(otaPackage.getFileName())) {
throw new DataValidationException("Updating otaPackage file name is prohibited!");
}
if (otaPackageOld.getContentType() != null && !otaPackageOld.getContentType().equals(otaPackage.getContentType())) {
throw new DataValidationException("Updating otaPackage content type is prohibited!");
}
if (otaPackageOld.getChecksumAlgorithm() != null && !otaPackageOld.getChecksumAlgorithm().equals(otaPackage.getChecksumAlgorithm())) {
throw new DataValidationException("Updating otaPackage content type is prohibited!");
}
if (otaPackageOld.getChecksum() != null && !otaPackageOld.getChecksum().equals(otaPackage.getChecksum())) {
throw new DataValidationException("Updating otaPackage content type is prohibited!");
}
if (otaPackageOld.getDataSize() != null && !otaPackageOld.getDataSize().equals(otaPackage.getDataSize())) {
throw new DataValidationException("Updating otaPackage data size is prohibited!");
}
}
private void validateImpl(OtaPackageInfo otaPackageInfo) {
if (otaPackageInfo.getTenantId() == null) {
throw new DataValidationException("OtaPackage should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(otaPackageInfo.getTenantId(), otaPackageInfo.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("OtaPackage is referencing to non-existent tenant!");
}
}
if (otaPackageInfo.getDeviceProfileId() != null) {
DeviceProfile deviceProfile = deviceProfileDao.findById(otaPackageInfo.getTenantId(), otaPackageInfo.getDeviceProfileId().getId());
if (deviceProfile == null) {
throw new DataValidationException("OtaPackage is referencing to non-existent device profile!");
}
}
if (otaPackageInfo.getType() == null) {
throw new DataValidationException("Type should be specified!");
}
if (StringUtils.isEmpty(otaPackageInfo.getTitle())) {
throw new DataValidationException("OtaPackage title should be specified!");
}
if (StringUtils.isEmpty(otaPackageInfo.getVersion())) {
throw new DataValidationException("OtaPackage version should be specified!");
}
}
private PaginatedRemover<TenantId, OtaPackageInfo> tenantOtaPackageRemover =
new PaginatedRemover<>() {
@Override
protected PageData<OtaPackageInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return otaPackageInfoDao.findOtaPackageInfoByTenantId(id, pageLink);
}
@Override
protected void removeEntity(TenantId tenantId, OtaPackageInfo entity) {
deleteOtaPackage(tenantId, entity.getId());
}
};
protected Optional<ConstraintViolationException> extractConstraintViolationException(Exception t) {
if (t instanceof ConstraintViolationException) {
return Optional.of((ConstraintViolationException) t);
} else if (t.getCause() instanceof ConstraintViolationException) {
return Optional.of((ConstraintViolationException) (t.getCause()));
} else {
return Optional.empty();
}
}
private static List<OtaPackageId> toOtaPackageInfoKey(OtaPackageId otaPackageId) {
return Collections.singletonList(otaPackageId);
}
}

6
dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareDao.java → dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageDao.java

@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.firmware;
package org.thingsboard.server.dao.ota;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.dao.Dao;
public interface FirmwareDao extends Dao<Firmware> {
public interface OtaPackageDao extends Dao<OtaPackage> {
}

18
dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java → dao/src/main/java/org/thingsboard/server/dao/ota/OtaPackageInfoDao.java

@ -13,25 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.firmware;
package org.thingsboard.server.dao.ota;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import java.util.UUID;
public interface OtaPackageInfoDao extends Dao<OtaPackageInfo> {
public interface FirmwareInfoDao extends Dao<FirmwareInfo> {
PageData<OtaPackageInfo> findOtaPackageInfoByTenantId(TenantId tenantId, PageLink pageLink);
PageData<FirmwareInfo> findFirmwareInfoByTenantId(TenantId tenantId, PageLink pageLink);
PageData<OtaPackageInfo> findOtaPackageInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType otaPackageType, boolean hasData, PageLink pageLink);
PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink);
boolean isFirmwareUsed(FirmwareId firmwareId, FirmwareType type, DeviceProfileId deviceProfileId);
boolean isOtaPackageUsed(OtaPackageId otaPackageId, OtaPackageType otaPackageType, DeviceProfileId deviceProfileId);
}

20
dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java

@ -96,23 +96,35 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
Pageable pageable);
@Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
"AND d.type = :type " +
"AND d.deviceProfileId = :deviceProfileId " +
"AND d.firmwareId = null " +
"AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))")
Page<DeviceEntity> findByTenantIdAndTypeAndFirmwareIdIsNull(@Param("tenantId") UUID tenantId,
@Param("type") String type,
@Param("deviceProfileId") UUID deviceProfileId,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT d FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
"AND d.type = :type " +
"AND d.deviceProfileId = :deviceProfileId " +
"AND d.softwareId = null " +
"AND LOWER(d.searchText) LIKE LOWER(CONCAT(:textSearch, '%'))")
Page<DeviceEntity> findByTenantIdAndTypeAndSoftwareIdIsNull(@Param("tenantId") UUID tenantId,
@Param("type") String type,
@Param("deviceProfileId") UUID deviceProfileId,
@Param("textSearch") String textSearch,
Pageable pageable);
@Query("SELECT count(*) FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
"AND d.deviceProfileId = :deviceProfileId " +
"AND d.firmwareId = null")
Long countByTenantIdAndDeviceProfileIdAndFirmwareIdIsNull(@Param("tenantId") UUID tenantId,
@Param("deviceProfileId") UUID deviceProfileId);
@Query("SELECT count(*) FROM DeviceEntity d WHERE d.tenantId = :tenantId " +
"AND d.deviceProfileId = :deviceProfileId " +
"AND d.softwareId = null")
Long countByTenantIdAndDeviceProfileIdAndSoftwareIdIsNull(@Param("tenantId") UUID tenantId,
@Param("deviceProfileId") UUID deviceProfileId);
@Query("SELECT new org.thingsboard.server.dao.model.sql.DeviceInfoEntity(d, c.title, c.additionalInfo, p.name) " +
"FROM DeviceEntity d " +
"LEFT JOIN CustomerEntity c on c.id = d.customerId " +

36
dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java

@ -18,6 +18,8 @@ package org.thingsboard.server.dao.sql.device;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@ -27,6 +29,8 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
@ -155,23 +159,27 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
}
@Override
public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink) {
return DaoUtil.toPageData(
deviceRepository.findByTenantIdAndTypeAndFirmwareIdIsNull(
tenantId,
type,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink)));
public PageData<Device> findDevicesByTenantIdAndTypeAndEmptyOtaPackage(UUID tenantId,
UUID deviceProfileId,
OtaPackageType type,
PageLink pageLink) {
Pageable pageable = DaoUtil.toPageable(pageLink);
String searchText = Objects.toString(pageLink.getTextSearch(), "");
Page<DeviceEntity> page = OtaPackageUtil.getByOtaPackageType(
() -> deviceRepository.findByTenantIdAndTypeAndFirmwareIdIsNull(tenantId, deviceProfileId, searchText, pageable),
() -> deviceRepository.findByTenantIdAndTypeAndSoftwareIdIsNull(tenantId, deviceProfileId, searchText, pageable),
type
);
return DaoUtil.toPageData(page);
}
@Override
public PageData<Device> findDevicesByTenantIdAndTypeAndEmptySoftware(UUID tenantId, String type, PageLink pageLink) {
return DaoUtil.toPageData(
deviceRepository.findByTenantIdAndTypeAndSoftwareIdIsNull(
tenantId,
type,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink)));
public Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(UUID tenantId, UUID deviceProfileId, OtaPackageType type) {
return OtaPackageUtil.getByOtaPackageType(
() -> deviceRepository.countByTenantIdAndDeviceProfileIdAndFirmwareIdIsNull(tenantId, deviceProfileId),
() -> deviceRepository.countByTenantIdAndDeviceProfileIdAndSoftwareIdIsNull(tenantId, deviceProfileId),
type
);
}
@Override

60
dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java

@ -1,60 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.firmware;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.dao.model.sql.FirmwareInfoEntity;
import java.util.UUID;
public interface FirmwareInfoRepository extends CrudRepository<FirmwareInfoEntity, UUID> {
@Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " +
"f.tenantId = :tenantId " +
"AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<FirmwareInfoEntity> findAllByTenantId(@Param("tenantId") UUID tenantId,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE " +
"f.tenantId = :tenantId " +
"AND f.deviceProfileId = :deviceProfileId " +
"AND f.type = :type " +
"AND ((f.data IS NOT NULL AND :hasData = true) OR (f.data IS NULL AND :hasData = false ))" +
"AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<FirmwareInfoEntity> findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData(@Param("tenantId") UUID tenantId,
@Param("deviceProfileId") UUID deviceProfileId,
@Param("type") FirmwareType type,
@Param("hasData") boolean hasData,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM FirmwareEntity f WHERE f.id = :id")
FirmwareInfoEntity findFirmwareInfoById(@Param("id") UUID id);
@Query(value = "SELECT exists(SELECT * " +
"FROM device_profile AS dp " +
"LEFT JOIN device AS d ON dp.id = d.device_profile_id " +
"WHERE dp.id = :deviceProfileId AND " +
"(('FIRMWARE' = :type AND (dp.firmware_id = :firmwareId OR d.firmware_id = :firmwareId)) " +
"OR ('SOFTWARE' = :type AND (dp.software_id = :firmwareId or d.software_id = :firmwareId))))", nativeQuery = true)
boolean isFirmwareUsed(@Param("firmwareId") UUID firmwareId, @Param("deviceProfileId") UUID deviceProfileId, @Param("type") String type);
}

94
dao/src/main/java/org/thingsboard/server/dao/sql/firmware/JpaFirmwareInfoDao.java

@ -1,94 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.firmware;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.FirmwareInfo;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.FirmwareId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.firmware.FirmwareInfoDao;
import org.thingsboard.server.dao.model.sql.FirmwareInfoEntity;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.Objects;
import java.util.UUID;
@Slf4j
@Component
public class JpaFirmwareInfoDao extends JpaAbstractSearchTextDao<FirmwareInfoEntity, FirmwareInfo> implements FirmwareInfoDao {
@Autowired
private FirmwareInfoRepository firmwareInfoRepository;
@Override
protected Class<FirmwareInfoEntity> getEntityClass() {
return FirmwareInfoEntity.class;
}
@Override
protected CrudRepository<FirmwareInfoEntity, UUID> getCrudRepository() {
return firmwareInfoRepository;
}
@Override
public FirmwareInfo findById(TenantId tenantId, UUID id) {
return DaoUtil.getData(firmwareInfoRepository.findFirmwareInfoById(id));
}
@Override
public FirmwareInfo save(TenantId tenantId, FirmwareInfo firmwareInfo) {
FirmwareInfo savedFirmware = super.save(tenantId, firmwareInfo);
if (firmwareInfo.getId() == null) {
return savedFirmware;
} else {
return findById(tenantId, savedFirmware.getId().getId());
}
}
@Override
public PageData<FirmwareInfo> findFirmwareInfoByTenantId(TenantId tenantId, PageLink pageLink) {
return DaoUtil.toPageData(firmwareInfoRepository
.findAllByTenantId(
tenantId.getId(),
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<FirmwareInfo> findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink) {
return DaoUtil.toPageData(firmwareInfoRepository
.findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData(
tenantId.getId(),
deviceProfileId.getId(),
firmwareType,
hasData,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink)));
}
@Override
public boolean isFirmwareUsed(FirmwareId firmwareId, FirmwareType type, DeviceProfileId deviceProfileId) {
return firmwareInfoRepository.isFirmwareUsed(firmwareId.getId(), deviceProfileId.getId(), type.name());
}
}

20
dao/src/main/java/org/thingsboard/server/dao/sql/firmware/JpaFirmwareDao.java → dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageDao.java

@ -13,34 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.firmware;
package org.thingsboard.server.dao.sql.ota;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.dao.firmware.FirmwareDao;
import org.thingsboard.server.dao.model.sql.FirmwareEntity;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.dao.ota.OtaPackageDao;
import org.thingsboard.server.dao.model.sql.OtaPackageEntity;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.UUID;
@Slf4j
@Component
public class JpaFirmwareDao extends JpaAbstractSearchTextDao<FirmwareEntity, Firmware> implements FirmwareDao {
public class JpaOtaPackageDao extends JpaAbstractSearchTextDao<OtaPackageEntity, OtaPackage> implements OtaPackageDao {
@Autowired
private FirmwareRepository firmwareRepository;
private OtaPackageRepository otaPackageRepository;
@Override
protected Class<FirmwareEntity> getEntityClass() {
return FirmwareEntity.class;
protected Class<OtaPackageEntity> getEntityClass() {
return OtaPackageEntity.class;
}
@Override
protected CrudRepository<FirmwareEntity, UUID> getCrudRepository() {
return firmwareRepository;
protected CrudRepository<OtaPackageEntity, UUID> getCrudRepository() {
return otaPackageRepository;
}
}

94
dao/src/main/java/org/thingsboard/server/dao/sql/ota/JpaOtaPackageInfoDao.java

@ -0,0 +1,94 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.ota;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.ota.OtaPackageInfoDao;
import org.thingsboard.server.dao.model.sql.OtaPackageInfoEntity;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.Objects;
import java.util.UUID;
@Slf4j
@Component
public class JpaOtaPackageInfoDao extends JpaAbstractSearchTextDao<OtaPackageInfoEntity, OtaPackageInfo> implements OtaPackageInfoDao {
@Autowired
private OtaPackageInfoRepository otaPackageInfoRepository;
@Override
protected Class<OtaPackageInfoEntity> getEntityClass() {
return OtaPackageInfoEntity.class;
}
@Override
protected CrudRepository<OtaPackageInfoEntity, UUID> getCrudRepository() {
return otaPackageInfoRepository;
}
@Override
public OtaPackageInfo findById(TenantId tenantId, UUID id) {
return DaoUtil.getData(otaPackageInfoRepository.findOtaPackageInfoById(id));
}
@Override
public OtaPackageInfo save(TenantId tenantId, OtaPackageInfo otaPackageInfo) {
OtaPackageInfo savedOtaPackage = super.save(tenantId, otaPackageInfo);
if (otaPackageInfo.getId() == null) {
return savedOtaPackage;
} else {
return findById(tenantId, savedOtaPackage.getId().getId());
}
}
@Override
public PageData<OtaPackageInfo> findOtaPackageInfoByTenantId(TenantId tenantId, PageLink pageLink) {
return DaoUtil.toPageData(otaPackageInfoRepository
.findAllByTenantId(
tenantId.getId(),
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<OtaPackageInfo> findOtaPackageInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, OtaPackageType otaPackageType, boolean hasData, PageLink pageLink) {
return DaoUtil.toPageData(otaPackageInfoRepository
.findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData(
tenantId.getId(),
deviceProfileId.getId(),
otaPackageType,
hasData,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink)));
}
@Override
public boolean isOtaPackageUsed(OtaPackageId otaPackageId, OtaPackageType otaPackageType, DeviceProfileId deviceProfileId) {
return otaPackageInfoRepository.isOtaPackageUsed(otaPackageId.getId(), deviceProfileId.getId(), otaPackageType.name());
}
}

60
dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageInfoRepository.java

@ -0,0 +1,60 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.ota;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.dao.model.sql.OtaPackageInfoEntity;
import java.util.UUID;
public interface OtaPackageInfoRepository extends CrudRepository<OtaPackageInfoEntity, UUID> {
@Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM OtaPackageEntity f WHERE " +
"f.tenantId = :tenantId " +
"AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<OtaPackageInfoEntity> findAllByTenantId(@Param("tenantId") UUID tenantId,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM OtaPackageEntity f WHERE " +
"f.tenantId = :tenantId " +
"AND f.deviceProfileId = :deviceProfileId " +
"AND f.type = :type " +
"AND ((f.data IS NOT NULL AND :hasData = true) OR (f.data IS NULL AND :hasData = false ))" +
"AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<OtaPackageInfoEntity> findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData(@Param("tenantId") UUID tenantId,
@Param("deviceProfileId") UUID deviceProfileId,
@Param("type") OtaPackageType type,
@Param("hasData") boolean hasData,
@Param("searchText") String searchText,
Pageable pageable);
@Query("SELECT new OtaPackageInfoEntity(f.id, f.createdTime, f.tenantId, f.deviceProfileId, f.type, f.title, f.version, f.fileName, f.contentType, f.checksumAlgorithm, f.checksum, f.dataSize, f.additionalInfo, f.data IS NOT NULL) FROM OtaPackageEntity f WHERE f.id = :id")
OtaPackageInfoEntity findOtaPackageInfoById(@Param("id") UUID id);
@Query(value = "SELECT exists(SELECT * " +
"FROM device_profile AS dp " +
"LEFT JOIN device AS d ON dp.id = d.device_profile_id " +
"WHERE dp.id = :deviceProfileId AND " +
"(('FIRMWARE' = :type AND (dp.firmware_id = :otaPackageId OR d.firmware_id = :otaPackageId)) " +
"OR ('SOFTWARE' = :type AND (dp.software_id = :otaPackageId or d.software_id = :otaPackageId))))", nativeQuery = true)
boolean isOtaPackageUsed(@Param("otaPackageId") UUID otaPackageId, @Param("deviceProfileId") UUID deviceProfileId, @Param("type") String type);
}

6
dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareRepository.java → dao/src/main/java/org/thingsboard/server/dao/sql/ota/OtaPackageRepository.java

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.firmware;
package org.thingsboard.server.dao.sql.ota;
import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.FirmwareEntity;
import org.thingsboard.server.dao.model.sql.OtaPackageEntity;
import java.util.UUID;
public interface FirmwareRepository extends CrudRepository<FirmwareEntity, UUID> {
public interface OtaPackageRepository extends CrudRepository<OtaPackageEntity, UUID> {
}

6
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

@ -35,7 +35,7 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DataValidator;
@ -94,7 +94,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
private ResourceService resourceService;
@Autowired
private FirmwareService firmwareService;
private OtaPackageService otaPackageService;
@Override
public Tenant findTenantById(TenantId tenantId) {
@ -150,7 +150,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
ruleChainService.deleteRuleChainsByTenantId(tenantId);
apiUsageStateService.deleteApiUsageStateByTenantId(tenantId);
resourceService.deleteResourcesByTenantId(tenantId);
firmwareService.deleteFirmwaresByTenantId(tenantId);
otaPackageService.deleteOtaPackagesByTenantId(tenantId);
tenantDao.removeById(tenantId, tenantId.getId());
deleteEntityRelations(tenantId, tenantId);
}

14
dao/src/main/resources/sql/schema-entities-hsql.sql

@ -160,8 +160,8 @@ CREATE TABLE IF NOT EXISTS rule_node_state (
CONSTRAINT fk_rule_node_state_node_id FOREIGN KEY (rule_node_id) REFERENCES rule_node(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS firmware (
id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
CREATE TABLE IF NOT EXISTS ota_package (
id uuid NOT NULL CONSTRAINT ota_package_pkey PRIMARY KEY,
created_time bigint NOT NULL,
tenant_id uuid NOT NULL,
device_profile_id uuid ,
@ -176,7 +176,7 @@ CREATE TABLE IF NOT EXISTS firmware (
data_size bigint,
additional_info varchar,
search_text varchar(255),
CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
CONSTRAINT ota_package_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
);
CREATE TABLE IF NOT EXISTS device_profile (
@ -202,8 +202,8 @@ CREATE TABLE IF NOT EXISTS device_profile (
CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key),
CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id),
CONSTRAINT fk_default_dashboard_device_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id),
CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id),
CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id)
CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES ota_package(id),
CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES ota_package(id)
);
CREATE TABLE IF NOT EXISTS device (
@ -222,8 +222,8 @@ CREATE TABLE IF NOT EXISTS device (
software_id uuid,
CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id),
CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id),
CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES firmware(id)
CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES ota_package(id),
CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES ota_package(id)
);
CREATE TABLE IF NOT EXISTS device_credentials (

14
dao/src/main/resources/sql/schema-entities.sql

@ -178,8 +178,8 @@ CREATE TABLE IF NOT EXISTS rule_node_state (
CONSTRAINT fk_rule_node_state_node_id FOREIGN KEY (rule_node_id) REFERENCES rule_node(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS firmware (
id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY,
CREATE TABLE IF NOT EXISTS ota_package (
id uuid NOT NULL CONSTRAINT ota_package_pkey PRIMARY KEY,
created_time bigint NOT NULL,
tenant_id uuid NOT NULL,
device_profile_id uuid ,
@ -194,7 +194,7 @@ CREATE TABLE IF NOT EXISTS firmware (
data_size bigint,
additional_info varchar,
search_text varchar(255),
CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
CONSTRAINT ota_package_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
-- CONSTRAINT fk_device_profile_firmware FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) ON DELETE CASCADE
);
@ -221,8 +221,8 @@ CREATE TABLE IF NOT EXISTS device_profile (
CONSTRAINT device_provision_key_unq_key UNIQUE (provision_device_key),
CONSTRAINT fk_default_rule_chain_device_profile FOREIGN KEY (default_rule_chain_id) REFERENCES rule_chain(id),
CONSTRAINT fk_default_dashboard_device_profile FOREIGN KEY (default_dashboard_id) REFERENCES dashboard(id),
CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(id),
CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES firmware(id)
CONSTRAINT fk_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES ota_package(id),
CONSTRAINT fk_software_device_profile FOREIGN KEY (software_id) REFERENCES ota_package(id)
);
-- We will use one-to-many relation in the first release and extend this feature in case of user requests
@ -250,8 +250,8 @@ CREATE TABLE IF NOT EXISTS device (
software_id uuid,
CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name),
CONSTRAINT fk_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id),
CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id),
CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES firmware(id)
CONSTRAINT fk_firmware_device FOREIGN KEY (firmware_id) REFERENCES ota_package(id),
CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES ota_package(id)
);
CREATE TABLE IF NOT EXISTS device_credentials (

4
dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java

@ -54,7 +54,7 @@ import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.firmware.FirmwareService;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
@ -160,7 +160,7 @@ public abstract class AbstractServiceTest {
@Autowired
protected FirmwareService firmwareService;
protected OtaPackageService otaPackageService;
public class IdComparator<D extends HasId> implements Comparator<D> {
@Override

11
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java

@ -28,10 +28,9 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.firmware.FirmwareType;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
@ -45,7 +44,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
@ -99,7 +98,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
Assert.assertEquals(deviceProfile.isDefault(), savedDeviceProfile.isDefault());
Assert.assertEquals(deviceProfile.getDefaultRuleChainId(), savedDeviceProfile.getDefaultRuleChainId());
Firmware firmware = new Firmware();
OtaPackage firmware = new OtaPackage();
firmware.setTenantId(tenantId);
firmware.setDeviceProfileId(savedDeviceProfile.getId());
firmware.setType(FIRMWARE);
@ -110,7 +109,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
firmware.setChecksumAlgorithm(ChecksumAlgorithm.SHA256);
firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
firmware.setData(ByteBuffer.wrap(new byte[]{1}));
Firmware savedFirmware = firmwareService.saveFirmware(firmware);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
deviceProfile.setFirmwareId(savedFirmware.getId());

14
dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java

@ -28,10 +28,10 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Firmware;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.firmware.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
@ -46,7 +46,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
@ -189,7 +189,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
Assert.assertEquals(20, deviceCredentials.getCredentialsId().length());
Firmware firmware = new Firmware();
OtaPackage firmware = new OtaPackage();
firmware.setTenantId(tenantId);
firmware.setDeviceProfileId(device.getDeviceProfileId());
firmware.setType(FIRMWARE);
@ -200,7 +200,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
firmware.setChecksumAlgorithm(ChecksumAlgorithm.SHA256);
firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
firmware.setData(ByteBuffer.wrap(new byte[]{1}));
Firmware savedFirmware = firmwareService.saveFirmware(firmware);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
savedDevice.setFirmwareId(savedFirmware.getId());
@ -223,7 +223,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
DeviceProfile savedProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
Assert.assertNotNull(savedProfile);
Firmware firmware = new Firmware();
OtaPackage firmware = new OtaPackage();
firmware.setTenantId(tenantId);
firmware.setDeviceProfileId(savedProfile.getId());
firmware.setType(FIRMWARE);
@ -234,7 +234,7 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
firmware.setChecksumAlgorithm(ChecksumAlgorithm.SHA256);
firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
firmware.setData(ByteBuffer.wrap(new byte[]{1}));
Firmware savedFirmware = firmwareService.saveFirmware(firmware);
OtaPackage savedFirmware = otaPackageService.saveOtaPackage(firmware);
savedDevice.setFirmwareId(savedFirmware.getId());

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save