From 83e31f42631f21cb3ac5ef99059d6922dce84b5e Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 28 Apr 2021 12:44:57 +0300 Subject: [PATCH 1/7] added firmware type --- .../main/data/upgrade/3.2.2/schema_update.sql | 1 + .../firmware/DefaultFirmwareStateService.java | 46 ++++++++++++++----- .../server/common/data/DataConstants.java | 26 +++++++++-- .../server/common/data/FirmwareInfo.java | 2 + .../server/common/data/FirmwareType.java | 5 ++ common/queue/src/main/proto/queue.proto | 9 ++-- .../server/dao/model/ModelConstants.java | 1 + .../server/dao/model/sql/FirmwareEntity.java | 10 ++++ .../dao/model/sql/FirmwareInfoEntity.java | 12 ++++- .../sql/firmware/FirmwareInfoRepository.java | 4 +- .../resources/sql/schema-entities-hsql.sql | 1 + .../main/resources/sql/schema-entities.sql | 1 + 12 files changed, 95 insertions(+), 23 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/FirmwareType.java diff --git a/application/src/main/data/upgrade/3.2.2/schema_update.sql b/application/src/main/data/upgrade/3.2.2/schema_update.sql index e1a2952f64..27c91a93fe 100644 --- a/application/src/main/data/upgrade/3.2.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.2.2/schema_update.sql @@ -63,6 +63,7 @@ CREATE TABLE IF NOT EXISTS firmware ( id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, created_time bigint NOT NULL, tenant_id uuid NOT NULL, + type varchar(32) NOT NULL, title varchar(255) NOT NULL, version varchar(255) NOT NULL, file_name varchar(255), diff --git a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java index 6e0e3fd246..e0aef22eab 100644 --- a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java @@ -22,7 +22,6 @@ import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; 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.Firmware; import org.thingsboard.server.common.data.FirmwareInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.FirmwareId; @@ -35,7 +34,6 @@ import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; @@ -59,6 +57,11 @@ import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_SIZE; import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_TITLE; import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION; +import static org.thingsboard.server.common.data.DataConstants.SOFTWARE_CHECKSUM; +import static org.thingsboard.server.common.data.DataConstants.SOFTWARE_CHECKSUM_ALGORITHM; +import static org.thingsboard.server.common.data.DataConstants.SOFTWARE_SIZE; +import static org.thingsboard.server.common.data.DataConstants.SOFTWARE_TITLE; +import static org.thingsboard.server.common.data.DataConstants.SOFTWARE_VERSION; @Slf4j @Service @@ -185,9 +188,18 @@ public class DefaultFirmwareStateService implements FirmwareStateService { fwStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null); List telemetry = new ArrayList<>(); - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_TITLE, firmware.getTitle()))); - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_VERSION, firmware.getVersion()))); - telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.QUEUED.name()))); + switch (firmware.getType()) { + case FIRMWARE: + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_TITLE, firmware.getTitle()))); + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_VERSION, firmware.getVersion()))); + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.QUEUED.name()))); + break; + case SOFTWARE: + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_SOFTWARE_TITLE, firmware.getTitle()))); + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_SOFTWARE_VERSION, firmware.getVersion()))); + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.SOFTWARE_STATE, FirmwareUpdateStatus.QUEUED.name()))); + break; + } telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() { @Override @@ -223,12 +235,23 @@ public class DefaultFirmwareStateService implements FirmwareStateService { List attributes = new ArrayList<>(); - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_TITLE, firmware.getTitle()))); - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_VERSION, firmware.getVersion()))); + switch (firmware.getType()) { + case SOFTWARE: + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_TITLE, firmware.getTitle()))); + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_VERSION, firmware.getVersion()))); + attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(DataConstants.FIRMWARE_SIZE, firmware.getDataSize()))); + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm()))); + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM, firmware.getChecksum()))); + break; + case FIRMWARE: + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(SOFTWARE_TITLE, firmware.getTitle()))); + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(SOFTWARE_VERSION, firmware.getVersion()))); + attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(SOFTWARE_SIZE, firmware.getDataSize()))); + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(SOFTWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm()))); + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(SOFTWARE_CHECKSUM, firmware.getChecksum()))); + break; + } - attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(FIRMWARE_SIZE, firmware.getDataSize()))); - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm()))); - attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM, firmware.getChecksum()))); telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { @@ -244,7 +267,8 @@ public class DefaultFirmwareStateService implements FirmwareStateService { private void remove(Device device) { telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, - Arrays.asList(FIRMWARE_TITLE, FIRMWARE_VERSION, FIRMWARE_SIZE, FIRMWARE_CHECKSUM_ALGORITHM, FIRMWARE_CHECKSUM), + Arrays.asList(FIRMWARE_TITLE, FIRMWARE_VERSION, FIRMWARE_SIZE, FIRMWARE_CHECKSUM_ALGORITHM, FIRMWARE_CHECKSUM, + SOFTWARE_TITLE, SOFTWARE_VERSION, SOFTWARE_SIZE, SOFTWARE_CHECKSUM_ALGORITHM, SOFTWARE_CHECKSUM), new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java index d53e992db8..d9a8d70d28 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java @@ -93,21 +93,37 @@ public class DataConstants { public static final String USERNAME = "username"; public static final String PASSWORD = "password"; + public static final String EDGE_MSG_SOURCE = "edge"; + public static final String MSG_SOURCE_KEY = "source"; + //firmware //telemetry - public static final String CURRENT_FIRMWARE_TITLE = "cur_fw_title"; - public static final String CURRENT_FIRMWARE_VERSION = "cur_fw_version"; + public static final String CURRENT_FIRMWARE_TITLE = "current_fw_title"; + public static final String CURRENT_FIRMWARE_VERSION = "current_fw_version"; public static final String TARGET_FIRMWARE_TITLE = "target_fw_title"; public static final String TARGET_FIRMWARE_VERSION = "target_fw_version"; public static final String FIRMWARE_STATE = "fw_state"; //attributes - //telemetry public static final String FIRMWARE_TITLE = "fw_title"; public static final String FIRMWARE_VERSION = "fw_version"; public static final String FIRMWARE_SIZE = "fw_size"; public static final String FIRMWARE_CHECKSUM = "fw_checksum"; public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm"; - public static final String EDGE_MSG_SOURCE = "edge"; - public static final String MSG_SOURCE_KEY = "source"; + + //software + //telemetry + public static final String CURRENT_SOFTWARE_TITLE = "current_sw_title"; + public static final String CURRENT_SOFTWARE_VERSION = "current_sw_version"; + public static final String TARGET_SOFTWARE_TITLE = "target_sw_title"; + public static final String TARGET_SOFTWARE_VERSION = "target_sw_version"; + public static final String SOFTWARE_STATE = "sw_state"; + + //attributes + public static final String SOFTWARE_TITLE = "sw_title"; + public static final String SOFTWARE_VERSION = "sw_version"; + public static final String SOFTWARE_SIZE = "sw_size"; + public static final String SOFTWARE_CHECKSUM = "sw_checksum"; + public static final String SOFTWARE_CHECKSUM_ALGORITHM = "sw_checksum_algorithm"; + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java index 3a26763c4f..56fa319466 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java @@ -29,6 +29,7 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo private static final long serialVersionUID = 3168391583570815419L; private TenantId tenantId; + private FirmwareType type; private String title; private String version; private boolean hasData; @@ -50,6 +51,7 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo public FirmwareInfo(FirmwareInfo firmwareInfo) { super(firmwareInfo); this.tenantId = firmwareInfo.getTenantId(); + this.type = firmwareInfo.getType(); this.title = firmwareInfo.getTitle(); this.version = firmwareInfo.getVersion(); this.hasData = firmwareInfo.isHasData(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareType.java b/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareType.java new file mode 100644 index 0000000000..be7afe9da2 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareType.java @@ -0,0 +1,5 @@ +package org.thingsboard.server.common.data; + +public enum FirmwareType { + FIRMWARE, SOFTWARE +} diff --git a/common/queue/src/main/proto/queue.proto b/common/queue/src/main/proto/queue.proto index 77826ea807..c1857e8933 100644 --- a/common/queue/src/main/proto/queue.proto +++ b/common/queue/src/main/proto/queue.proto @@ -363,10 +363,11 @@ message GetFirmwareResponseMsg { ResponseStatus responseStatus = 1; int64 firmwareIdMSB = 2; int64 firmwareIdLSB = 3; - string title = 4; - string version = 5; - string contentType = 6; - string fileName = 7; + string type = 4; + string title = 5; + string version = 6; + string contentType = 7; + string fileName = 8; } //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level. diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index ae3b974054..260c8aa743 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -476,6 +476,7 @@ public class ModelConstants { */ public static final String FIRMWARE_TABLE_NAME = "firmware"; public static final String FIRMWARE_TENANT_ID_COLUMN = TENANT_ID_COLUMN; + 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"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java index ccfa0229bd..267a7319ec 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java @@ -21,6 +21,7 @@ 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.FirmwareType; import org.thingsboard.server.common.data.id.FirmwareId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -30,6 +31,8 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.Table; import java.nio.ByteBuffer; import java.util.UUID; @@ -43,6 +46,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME 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.SEARCH_TEXT_PROPERTY; @@ -56,6 +60,10 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex @Column(name = FIRMWARE_TENANT_ID_COLUMN) private UUID tenantId; + @Enumerated(EnumType.STRING) + @Column(name = FIRMWARE_TYPE_COLUMN) + private FirmwareType type; + @Column(name = FIRMWARE_TITLE_COLUMN) private String title; @@ -95,6 +103,7 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex this.createdTime = firmware.getCreatedTime(); this.setUuid(firmware.getUuidId()); this.tenantId = firmware.getTenantId().getId(); + this.type = firmware.getType(); this.title = firmware.getTitle(); this.version = firmware.getVersion(); this.fileName = firmware.getFileName(); @@ -121,6 +130,7 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex Firmware firmware = new Firmware(new FirmwareId(id)); firmware.setCreatedTime(createdTime); firmware.setTenantId(new TenantId(tenantId)); + firmware.setType(type); firmware.setTitle(title); firmware.setVersion(version); firmware.setFileName(fileName); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java index 3549291e4b..f7f5c6329d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java @@ -22,6 +22,7 @@ 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.FirmwareType; import org.thingsboard.server.common.data.id.FirmwareId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; @@ -31,6 +32,8 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.Table; import javax.persistence.Transient; import java.util.UUID; @@ -45,6 +48,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_HAS_DATA_ 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.SEARCH_TEXT_PROPERTY; @@ -58,6 +62,10 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S @Column(name = FIRMWARE_TENANT_ID_COLUMN) private UUID tenantId; + @Enumerated(EnumType.STRING) + @Column(name = FIRMWARE_TYPE_COLUMN) + private FirmwareType type; + @Column(name = FIRMWARE_TITLE_COLUMN) private String title; @@ -107,12 +115,13 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S this.additionalInfo = firmware.getAdditionalInfo(); } - public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, String title, String version, + public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, String type, String title, String version, String fileName, String contentType, String checksumAlgorithm, String checksum, Long dataSize, Object additionalInfo, boolean hasData) { this.id = id; this.createdTime = createdTime; this.tenantId = tenantId; + this.type = FirmwareType.valueOf(type); this.title = title; this.version = version; this.fileName = fileName; @@ -139,6 +148,7 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id)); firmware.setCreatedTime(createdTime); firmware.setTenantId(new TenantId(tenantId)); + firmware.setType(type); firmware.setTitle(title); firmware.setVersion(version); firmware.setFileName(fileName); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java index 5601019c13..458cecf63d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java @@ -25,14 +25,14 @@ import org.thingsboard.server.dao.model.sql.FirmwareInfoEntity; import java.util.UUID; public interface FirmwareInfoRepository extends CrudRepository { - @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, 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 " + + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, 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 findAllByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); - @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, 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 " + + @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, 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.data IS NOT NULL AND :hasData = true) OR (f.data IS NULL AND :hasData = false ))" + "AND LOWER(f.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index 6dffac26b0..d9bc1003dc 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -162,6 +162,7 @@ CREATE TABLE IF NOT EXISTS firmware ( id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, created_time bigint NOT NULL, tenant_id uuid NOT NULL, + type varchar(32) NOT NULL, title varchar(255) NOT NULL, version varchar(255) NOT NULL, file_name varchar(255), diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 7d7a18abc6..0de1bfab7b 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -180,6 +180,7 @@ CREATE TABLE IF NOT EXISTS firmware ( id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, created_time bigint NOT NULL, tenant_id uuid NOT NULL, + type varchar(32) NOT NULL, title varchar(255) NOT NULL, version varchar(255) NOT NULL, file_name varchar(255), From f264aa43302dd70f9dfd39cd8475939889a117de Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 29 Apr 2021 10:02:51 +0300 Subject: [PATCH 2/7] fixed firmware tests and validation --- .../server/controller/FirmwareController.java | 15 +- .../firmware/DefaultFirmwareStateService.java | 16 +- .../transport/DefaultTransportApiService.java | 1 + .../BaseFirmwareControllerTest.java | 30 ++- .../controller/ControllerSqlTestSuite.java | 2 +- .../server/dao/firmware/FirmwareService.java | 4 +- .../server/common/data/Device.java | 12 ++ .../server/common/data/DeviceProfile.java | 4 + .../server/common/data/FirmwareInfo.java | 3 + .../dao/device/DeviceProfileServiceImpl.java | 10 + .../server/dao/device/DeviceServiceImpl.java | 16 ++ .../dao/firmware/BaseFirmwareService.java | 92 +++++---- .../server/dao/firmware/FirmwareInfoDao.java | 4 +- .../server/dao/model/ModelConstants.java | 3 + .../dao/model/sql/AbstractDeviceEntity.java | 16 +- .../dao/model/sql/DeviceProfileEntity.java | 18 +- .../server/dao/model/sql/FirmwareEntity.java | 7 + .../dao/model/sql/FirmwareInfoEntity.java | 13 +- .../sql/firmware/FirmwareInfoRepository.java | 19 +- .../dao/sql/firmware/JpaFirmwareInfoDao.java | 8 +- .../resources/sql/schema-entities-hsql.sql | 9 +- .../main/resources/sql/schema-entities.sql | 10 +- .../service/BaseDeviceProfileServiceTest.java | 5 + .../dao/service/BaseDeviceServiceTest.java | 43 ++++ .../dao/service/BaseFirmwareServiceTest.java | 185 ++++++++++++++++-- 25 files changed, 456 insertions(+), 89 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/FirmwareController.java b/application/src/main/java/org/thingsboard/server/controller/FirmwareController.java index 9c08967c8e..9b3caf7a79 100644 --- a/application/src/main/java/org/thingsboard/server/controller/FirmwareController.java +++ b/application/src/main/java/org/thingsboard/server/controller/FirmwareController.java @@ -35,6 +35,8 @@ 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.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; @@ -133,6 +135,8 @@ public class FirmwareController extends BaseController { 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()); @@ -175,17 +179,22 @@ public class FirmwareController extends BaseController { } @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/firmwares/{hasData}", method = RequestMethod.GET) + @RequestMapping(value = "/firmwares/{deviceProfileId}/{type}/{hasData}", method = RequestMethod.GET) @ResponseBody - public PageData getFirmwares(@PathVariable("hasData") boolean hasData, + public PageData 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.findTenantFirmwaresByTenantIdAndHasData(getTenantId(), hasData, pageLink)); + return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(getTenantId(), + new DeviceProfileId(toUUID(strDeviceProfileId)), FirmwareType.valueOf(strType), hasData, pageLink)); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java index 8638805d81..c4ad9feceb 100644 --- a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java @@ -16,7 +16,6 @@ package org.thingsboard.server.service.firmware; import com.google.common.util.concurrent.FutureCallback; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; @@ -45,6 +44,7 @@ import org.thingsboard.server.dao.firmware.FirmwareService; import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.provider.TbCoreQueueFactory; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.queue.TbClusterService; @@ -71,7 +71,6 @@ import static org.thingsboard.server.common.data.firmware.FirmwareKeyUtil.getTel @Slf4j @Service @TbCoreComponent -@RequiredArgsConstructor public class DefaultFirmwareStateService implements FirmwareStateService { private final TbClusterService tbClusterService; @@ -81,6 +80,19 @@ public class DefaultFirmwareStateService implements FirmwareStateService { private final RuleEngineTelemetryService telemetryService; private final TbQueueProducer> fwStateMsgProducer; + public DefaultFirmwareStateService(TbClusterService tbClusterService, FirmwareService firmwareService, + DeviceService deviceService, + DeviceProfileService deviceProfileService, + RuleEngineTelemetryService telemetryService, + TbCoreQueueFactory coreQueueFactory) { + this.tbClusterService = tbClusterService; + this.firmwareService = firmwareService; + this.deviceService = deviceService; + this.deviceProfileService = deviceProfileService; + this.telemetryService = telemetryService; + this.fwStateMsgProducer = coreQueueFactory.createToFirmwareStateServiceMsgProducer(); + } + @Override public void update(Device device, Device oldDevice) { FirmwareId newFirmwareId = device.getFirmwareId(); diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 025122a01b..463af51862 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -480,6 +480,7 @@ public class DefaultTransportApiService implements TransportApiService { 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()); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseFirmwareControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseFirmwareControllerTest.java index 425a21e1a2..ec36be13a5 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseFirmwareControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseFirmwareControllerTest.java @@ -24,10 +24,13 @@ import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; 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.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; import org.thingsboard.server.common.data.security.Authority; @@ -38,6 +41,7 @@ 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; public abstract class BaseFirmwareControllerTest extends AbstractControllerTest { @@ -53,6 +57,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest private Tenant savedTenant; private User tenantAdmin; + private DeviceProfileId deviceProfileId; @Before public void beforeTest() throws Exception { @@ -71,6 +76,11 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest tenantAdmin.setLastName("Downs"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); + + DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); + DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); + Assert.assertNotNull(savedDeviceProfile); + deviceProfileId = savedDeviceProfile.getId(); } @After @@ -84,6 +94,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @Test public void testSaveFirmware() throws Exception { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); @@ -107,6 +119,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @Test public void testSaveFirmwareData() throws Exception { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); @@ -137,6 +151,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @Test public void testUpdateFirmwareFromDifferentTenant() throws Exception { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); @@ -150,6 +166,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @Test public void testFindFirmwareInfoById() throws Exception { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); @@ -163,6 +181,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @Test public void testFindFirmwareById() throws Exception { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); @@ -180,6 +200,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest @Test public void testDeleteFirmware() throws Exception { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); @@ -197,6 +219,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest List firmwares = new ArrayList<>(); for (int i = 0; i < 165; i++) { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION + i); @@ -238,6 +262,8 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest for (int i = 0; i < 165; i++) { FirmwareInfo firmwareInfo = new FirmwareInfo(); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION + i); @@ -257,7 +283,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest PageLink pageLink = new PageLink(24); PageData pageData; do { - pageData = doGetTypedWithPageLink("/api/firmwares/true?", + pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/true?", new TypeReference<>() { }, pageLink); loadedFirmwaresWithData.addAll(pageData.getData()); @@ -269,7 +295,7 @@ public abstract class BaseFirmwareControllerTest extends AbstractControllerTest List loadedFirmwaresWithoutData = new ArrayList<>(); pageLink = new PageLink(24); do { - pageData = doGetTypedWithPageLink("/api/firmwares/false?", + pageData = doGetTypedWithPageLink("/api/firmwares/" + deviceProfileId.toString() + "/FIRMWARE/false?", new TypeReference<>() { }, pageLink); loadedFirmwaresWithoutData.addAll(pageData.getData()); diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java index 653f6978f6..85b058f597 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -29,7 +29,7 @@ import java.util.Arrays; // "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", // "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest", - "org.thingsboard.server.controller.sql.*Test", + "org.thingsboard.server.controller.sql.FirmwareControllerSqlTest", }) public class ControllerSqlTestSuite { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/firmware/FirmwareService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/firmware/FirmwareService.java index 907638eabb..980f8303f2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/firmware/FirmwareService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/firmware/FirmwareService.java @@ -18,6 +18,8 @@ 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.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; @@ -37,7 +39,7 @@ public interface FirmwareService { PageData findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink); - PageData findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink); + PageData findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink); void deleteFirmware(TenantId tenantId, FirmwareId firmwareId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index 5282435c0a..b48fc114cb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -50,6 +50,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen private byte[] deviceDataBytes; private FirmwareId firmwareId; + private FirmwareId softwareId; public Device() { super(); @@ -69,6 +70,7 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.deviceProfileId = device.getDeviceProfileId(); this.setDeviceData(device.getDeviceData()); this.firmwareId = device.getFirmwareId(); + this.softwareId = device.getSoftwareId(); } public Device updateDevice(Device device) { @@ -79,6 +81,8 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.label = device.getLabel(); this.deviceProfileId = device.getDeviceProfileId(); this.setDeviceData(device.getDeviceData()); + this.setFirmwareId(device.getFirmwareId()); + this.setSoftwareId(device.getSoftwareId()); return this; } @@ -171,6 +175,14 @@ public class Device extends SearchTextBasedWithAdditionalInfo implemen this.firmwareId = firmwareId; } + public FirmwareId getSoftwareId() { + return softwareId; + } + + public void setSoftwareId(FirmwareId softwareId) { + this.softwareId = softwareId; + } + @Override public String toString() { StringBuilder builder = new StringBuilder(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 660d9dec93..c3a2e5ecee 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -59,6 +59,8 @@ public class DeviceProfile extends SearchTextBased implements H private FirmwareId firmwareId; + private FirmwareId softwareId; + public DeviceProfile() { super(); } @@ -77,6 +79,8 @@ public class DeviceProfile extends SearchTextBased implements H this.defaultQueueName = deviceProfile.getDefaultQueueName(); this.setProfileData(deviceProfile.getProfileData()); this.provisionDeviceKey = deviceProfile.getProvisionDeviceKey(); + this.firmwareId = deviceProfile.getFirmwareId(); + this.softwareId = deviceProfile.getSoftwareId(); } @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java index aee81bcde8..9b00e9b256 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/FirmwareInfo.java @@ -20,6 +20,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; 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; @@ -31,6 +32,7 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo private static final long serialVersionUID = 3168391583570815419L; private TenantId tenantId; + private DeviceProfileId deviceProfileId; private FirmwareType type; private String title; private String version; @@ -53,6 +55,7 @@ public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo 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(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 7833c80ed5..020fd7c524 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -409,6 +409,16 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D throw new DataValidationException("Can't assign firmware with empty data!"); } } + + if (deviceProfile.getSoftwareId() != null) { + Firmware software = firmwareService.findFirmwareById(tenantId, deviceProfile.getSoftwareId()); + if (software == null) { + throw new DataValidationException("Can't assign non-existent software!"); + } + if (software.getData() == null) { + throw new DataValidationException("Can't assign software with empty data!"); + } + } } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 73dadef589..dd9b46b62f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -686,6 +686,22 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe if (firmware.getData() == null) { throw new DataValidationException("Can't assign firmware with empty data!"); } + if (!firmware.getDeviceProfileId().equals(device.getDeviceProfileId())) { + throw new DataValidationException("Can't assign firmware with different deviceProfile!"); + } + } + + if (device.getSoftwareId() != null) { + Firmware software = firmwareService.findFirmwareById(tenantId, device.getSoftwareId()); + if (software == null) { + throw new DataValidationException("Can't assign non-existent software!"); + } + if (software.getData() == null) { + throw new DataValidationException("Can't assign software with empty data!"); + } + if (!software.getDeviceProfileId().equals(device.getDeviceProfileId())) { + throw new DataValidationException("Can't assign firmware with different deviceProfile!"); + } } } }; diff --git a/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java b/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java index 5876947440..207d629bbe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java @@ -27,13 +27,17 @@ 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.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; @@ -56,6 +60,7 @@ public class BaseFirmwareService implements FirmwareService { 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; @@ -124,7 +129,8 @@ public class BaseFirmwareService implements FirmwareService { public ListenableFuture findFirmwareInfoByIdAsync(TenantId tenantId, FirmwareId firmwareId) { log.trace("Executing findFirmwareInfoByIdAsync [{}]", firmwareId); validateId(firmwareId, INCORRECT_FIRMWARE_ID + firmwareId); - return firmwareInfoDao.findByIdAsync(tenantId, firmwareId.getId()); } + return firmwareInfoDao.findByIdAsync(tenantId, firmwareId.getId()); + } @Override public PageData findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink) { @@ -135,11 +141,11 @@ public class BaseFirmwareService implements FirmwareService { } @Override - public PageData findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink) { + public PageData 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.findFirmwareInfoByTenantIdAndHasData(tenantId, hasData, pageLink); + return firmwareInfoDao.findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, firmwareType, hasData, pageLink); } @Override @@ -157,6 +163,10 @@ public class BaseFirmwareService implements FirmwareService { 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; } @@ -173,23 +183,8 @@ public class BaseFirmwareService implements FirmwareService { private DataValidator firmwareInfoValidator = new DataValidator<>() { @Override - protected void validateDataImpl(TenantId tenantId, FirmwareInfo firmware) { - if (firmware.getTenantId() == null) { - throw new DataValidationException("Firmware should be assigned to tenant!"); - } else { - Tenant tenant = tenantDao.findById(firmware.getTenantId(), firmware.getTenantId().getId()); - if (tenant == null) { - throw new DataValidationException("Firmware is referencing to non-existent tenant!"); - } - } - - if (StringUtils.isEmpty(firmware.getTitle())) { - throw new DataValidationException("Firmware title should be specified!"); - } - - if (StringUtils.isEmpty(firmware.getVersion())) { - throw new DataValidationException("Firmware version should be specified!"); - } + protected void validateDataImpl(TenantId tenantId, FirmwareInfo firmwareInfo) { + validateImpl(firmwareInfo); } @Override @@ -204,22 +199,7 @@ public class BaseFirmwareService implements FirmwareService { @Override protected void validateDataImpl(TenantId tenantId, Firmware firmware) { - if (firmware.getTenantId() == null) { - throw new DataValidationException("Firmware should be assigned to tenant!"); - } else { - Tenant tenant = tenantDao.findById(firmware.getTenantId(), firmware.getTenantId().getId()); - if (tenant == null) { - throw new DataValidationException("Firmware is referencing to non-existent tenant!"); - } - } - - if (StringUtils.isEmpty(firmware.getTitle())) { - throw new DataValidationException("Firmware title should be specified!"); - } - - if (StringUtils.isEmpty(firmware.getVersion())) { - throw new DataValidationException("Firmware version should be specified!"); - } + validateImpl(firmware); if (StringUtils.isEmpty(firmware.getFileName())) { throw new DataValidationException("Firmware file name should be specified!"); @@ -276,6 +256,14 @@ public class BaseFirmwareService implements FirmwareService { }; private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) { + if (!firmwareOld.getDeviceProfileId().equals(firmware.getDeviceProfileId())) { + throw new DataValidationException("Updating firmware deviceProfile is prohibited!"); + } + + 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!"); } @@ -305,6 +293,38 @@ public class BaseFirmwareService implements FirmwareService { } } + 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) { + throw new DataValidationException("Firmware should be assigned to deviceProfile!"); + } else { + 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 tenantFirmwareRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java index a2af06ad9a..32ca8dc528 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java @@ -16,6 +16,8 @@ package org.thingsboard.server.dao.firmware; 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.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -27,6 +29,6 @@ public interface FirmwareInfoDao extends Dao { PageData findFirmwareInfoByTenantId(TenantId tenantId, PageLink pageLink); - PageData findFirmwareInfoByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink); + PageData findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 260c8aa743..bc0afe630d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -154,6 +154,7 @@ public class ModelConstants { public static final String DEVICE_DEVICE_PROFILE_ID_PROPERTY = "device_profile_id"; public static final String DEVICE_DEVICE_DATA_PROPERTY = "device_data"; public static final String DEVICE_FIRMWARE_ID_PROPERTY = "firmware_id"; + public static final String DEVICE_SOFTWARE_ID_PROPERTY = "software_id"; public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text"; public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text"; @@ -178,6 +179,7 @@ public class ModelConstants { public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name"; public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key"; public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id"; + public static final String DEVICE_PROFILE_SOFTWARE_ID_PROPERTY = "software_id"; /** * Cassandra entityView constants. @@ -476,6 +478,7 @@ public class ModelConstants { */ 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"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java index 8dee576611..5b9d49a036 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java @@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.hibernate.annotations.TypeDefs; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.data.DeviceData; import org.thingsboard.server.common.data.id.CustomerId; @@ -32,7 +33,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import org.thingsboard.server.dao.util.mapping.JsonStringType; @@ -43,8 +43,8 @@ import java.util.UUID; @Data @EqualsAndHashCode(callSuper = true) @TypeDefs({ - @TypeDef(name = "json", typeClass = JsonStringType.class), - @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) + @TypeDef(name = "json", typeClass = JsonStringType.class), + @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) }) @MappedSuperclass public abstract class AbstractDeviceEntity extends BaseSqlEntity implements SearchTextEntity { @@ -77,6 +77,9 @@ public abstract class AbstractDeviceEntity extends BaseSqlEnti @Column(name = ModelConstants.DEVICE_FIRMWARE_ID_PROPERTY, columnDefinition = "uuid") private UUID firmwareId; + @Column(name = ModelConstants.DEVICE_SOFTWARE_ID_PROPERTY, columnDefinition = "uuid") + private UUID softwareId; + @Type(type = "jsonb") @Column(name = ModelConstants.DEVICE_DEVICE_DATA_PROPERTY, columnDefinition = "jsonb") private JsonNode deviceData; @@ -102,6 +105,9 @@ public abstract class AbstractDeviceEntity extends BaseSqlEnti if (device.getFirmwareId() != null) { this.firmwareId = device.getFirmwareId().getId(); } + if (device.getSoftwareId() != null) { + this.firmwareId = device.getSoftwareId().getId(); + } this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class); this.name = device.getName(); this.type = device.getType(); @@ -122,6 +128,7 @@ public abstract class AbstractDeviceEntity extends BaseSqlEnti this.searchText = deviceEntity.getSearchText(); this.additionalInfo = deviceEntity.getAdditionalInfo(); this.firmwareId = deviceEntity.getFirmwareId(); + this.softwareId = deviceEntity.getSoftwareId(); } @Override @@ -149,6 +156,9 @@ public abstract class AbstractDeviceEntity extends BaseSqlEnti if (firmwareId != null) { device.setFirmwareId(new FirmwareId(firmwareId)); } + if (softwareId != null) { + device.setSoftwareId(new FirmwareId(softwareId)); + } device.setDeviceData(JacksonUtil.convertValue(deviceData, DeviceData.class)); device.setName(name); device.setType(type); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java index e437c87fdd..e4c32a44f0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java @@ -21,9 +21,10 @@ import lombok.Data; 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.DeviceProfile; -import org.thingsboard.server.common.data.DeviceProfileType; 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.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -33,7 +34,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import javax.persistence.Column; @@ -87,12 +87,15 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl @Column(name = ModelConstants.DEVICE_PROFILE_PROFILE_DATA_PROPERTY, columnDefinition = "jsonb") private JsonNode profileData; - @Column(name=ModelConstants.DEVICE_PROFILE_PROVISION_DEVICE_KEY) + @Column(name = ModelConstants.DEVICE_PROFILE_PROVISION_DEVICE_KEY) private String provisionDeviceKey; - @Column(name=ModelConstants.DEVICE_PROFILE_FIRMWARE_ID_PROPERTY) + @Column(name = ModelConstants.DEVICE_PROFILE_FIRMWARE_ID_PROPERTY) private UUID firmwareId; + @Column(name = ModelConstants.DEVICE_PROFILE_SOFTWARE_ID_PROPERTY) + private UUID softwareId; + public DeviceProfileEntity() { super(); } @@ -120,6 +123,9 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl if (deviceProfile.getFirmwareId() != null) { this.firmwareId = deviceProfile.getFirmwareId().getId(); } + if (deviceProfile.getSoftwareId() != null) { + this.firmwareId = deviceProfile.getSoftwareId().getId(); + } } @Override @@ -160,6 +166,10 @@ public final class DeviceProfileEntity extends BaseSqlEntity impl deviceProfile.setFirmwareId(new FirmwareId(firmwareId)); } + if (softwareId != null) { + deviceProfile.setSoftwareId(new FirmwareId(softwareId)); + } + return deviceProfile; } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java index 6dfa2e893e..a10ec8f7ed 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java @@ -22,6 +22,7 @@ import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.Firmware; 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.dao.model.BaseSqlEntity; @@ -43,6 +44,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ 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; @@ -61,6 +63,9 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex @Column(name = FIRMWARE_TENANT_ID_COLUMN) private UUID tenantId; + @Column(name = FIRMWARE_DEVICE_PROFILE_ID_COLUMN) + private UUID deviceProfileId; + @Enumerated(EnumType.STRING) @Column(name = FIRMWARE_TYPE_COLUMN) private FirmwareType type; @@ -105,6 +110,7 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex this.createdTime = firmware.getCreatedTime(); this.setUuid(firmware.getUuidId()); this.tenantId = firmware.getTenantId().getId(); + this.deviceProfileId = firmware.getDeviceProfileId().getId(); this.type = firmware.getType(); this.title = firmware.getTitle(); this.version = firmware.getVersion(); @@ -132,6 +138,7 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex Firmware firmware = new Firmware(new FirmwareId(id)); firmware.setCreatedTime(createdTime); firmware.setTenantId(new TenantId(tenantId)); + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); firmware.setType(type); firmware.setTitle(title); firmware.setVersion(version); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java index 067b061396..b1e058a012 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java @@ -23,6 +23,7 @@ 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.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.dao.model.BaseSqlEntity; @@ -42,6 +43,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ 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; @@ -60,6 +62,9 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S @Column(name = FIRMWARE_TENANT_ID_COLUMN) private UUID tenantId; + @Column(name = FIRMWARE_DEVICE_PROFILE_ID_COLUMN) + private UUID deviceProfileId; + @Enumerated(EnumType.STRING) @Column(name = FIRMWARE_TYPE_COLUMN) private FirmwareType type; @@ -103,6 +108,8 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S this.createdTime = firmware.getCreatedTime(); this.setUuid(firmware.getUuidId()); this.tenantId = firmware.getTenantId().getId(); + this.type = firmware.getType(); + this.deviceProfileId = firmware.getDeviceProfileId().getId(); this.title = firmware.getTitle(); this.version = firmware.getVersion(); this.fileName = firmware.getFileName(); @@ -113,13 +120,14 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S this.additionalInfo = firmware.getAdditionalInfo(); } - public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, String type, String title, String version, + public FirmwareInfoEntity(UUID id, long createdTime, UUID tenantId, UUID deviceProfileId, FirmwareType type, String title, String version, String fileName, String contentType, String checksumAlgorithm, String checksum, Long dataSize, Object additionalInfo, boolean hasData) { this.id = id; this.createdTime = createdTime; this.tenantId = tenantId; - this.type = FirmwareType.valueOf(type); + this.deviceProfileId = deviceProfileId; + this.type = type; this.title = title; this.version = version; this.fileName = fileName; @@ -146,6 +154,7 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id)); firmware.setCreatedTime(createdTime); firmware.setTenantId(new TenantId(tenantId)); + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); firmware.setType(type); firmware.setTitle(title); firmware.setVersion(version); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java index 458cecf63d..5a7af9997b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java @@ -20,27 +20,32 @@ 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 { - @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, 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 " + + @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 findAllByTenantId(@Param("tenantId") UUID tenantId, @Param("searchText") String searchText, Pageable pageable); - @Query("SELECT new FirmwareInfoEntity(f.id, f.createdTime, f.tenantId, 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 " + + @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 findAllByTenantIdAndHasData(@Param("tenantId") UUID tenantId, - @Param("hasData") boolean hasData, - @Param("searchText") String searchText, - Pageable pageable); + Page 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.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") + @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); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/JpaFirmwareInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/JpaFirmwareInfoDao.java index 3b80c1c7e5..db7fb37ffe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/JpaFirmwareInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/JpaFirmwareInfoDao.java @@ -20,6 +20,8 @@ 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.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -73,10 +75,12 @@ public class JpaFirmwareInfoDao extends JpaAbstractSearchTextDao findFirmwareInfoByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink) { + public PageData findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink) { return DaoUtil.toPageData(firmwareInfoRepository - .findAllByTenantIdAndHasData( + .findAllByTenantIdAndTypeAndDeviceProfileIdAndHasData( tenantId.getId(), + deviceProfileId.getId(), + firmwareType, hasData, Objects.toString(pageLink.getTextSearch(), ""), DaoUtil.toPageable(pageLink))); diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql index d9bc1003dc..89dcf44f35 100644 --- a/dao/src/main/resources/sql/schema-entities-hsql.sql +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -162,6 +162,7 @@ CREATE TABLE IF NOT EXISTS firmware ( id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, created_time bigint NOT NULL, tenant_id uuid NOT NULL, + device_profile_id uuid NOT NULL, type varchar(32) NOT NULL, title varchar(255) NOT NULL, version varchar(255) NOT NULL, @@ -189,13 +190,15 @@ CREATE TABLE IF NOT EXISTS device_profile ( is_default boolean, tenant_id uuid, firmware_id uuid, + software_id uuid, default_rule_chain_id uuid, default_queue_name varchar(255), provision_device_key varchar, CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), 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_firmware_device_profile FOREIGN KEY (firmware_id) REFERENCES firmware(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) ); CREATE TABLE IF NOT EXISTS device ( @@ -211,9 +214,11 @@ CREATE TABLE IF NOT EXISTS device ( search_text varchar(255), tenant_id uuid, firmware_id uuid, + 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_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id), + CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES firmware(id) ); CREATE TABLE IF NOT EXISTS device_credentials ( diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index a5373fbaaf..245759cd22 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -192,8 +192,8 @@ 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 fk_firmware_device_profile FOREIGN KEY (device_profile_id) REFERENCES device_profile(id) ON DELETE CASCADE + CONSTRAINT firmware_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 ); CREATE TABLE IF NOT EXISTS device_profile ( @@ -216,8 +216,8 @@ CREATE TABLE IF NOT EXISTS device_profile ( CONSTRAINT device_profile_name_unq_key UNIQUE (tenant_id, name), 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_device_profile_firmware FOREIGN KEY (firmware_id) REFERENCES firmware(id) - CONSTRAINT fk_device_profile_software FOREIGN KEY (software_id) REFERENCES firmware(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) ); -- We will use one-to-many relation in the first release and extend this feature in case of user requests @@ -245,7 +245,7 @@ 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_firmware_device FOREIGN KEY (firmware_id) REFERENCES firmware(id), CONSTRAINT fk_software_device FOREIGN KEY (software_id) REFERENCES firmware(id) ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java index e377baa2cb..618135fdd3 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceProfileServiceTest.java @@ -30,6 +30,7 @@ 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.Tenant; +import org.thingsboard.server.common.data.firmware.FirmwareType; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -43,6 +44,8 @@ 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; + public class BaseDeviceProfileServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); @@ -97,6 +100,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(savedDeviceProfile.getId()); + firmware.setType(FIRMWARE); firmware.setTitle("my firmware"); firmware.setVersion("v1.0"); firmware.setFileName("test.txt"); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java index 6d7b695ef1..4fcdd93bce 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java @@ -20,10 +20,13 @@ import org.apache.commons.lang3.RandomStringUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.thingsboard.server.common.data.Customer; 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.Tenant; @@ -42,6 +45,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.dao.model.ModelConstants.NULL_UUID; public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -66,6 +70,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { tenantProfileService.deleteTenantProfiles(anotherTenantId); } + @Rule + public ExpectedException thrown = ExpectedException.none(); + @Test public void testSaveDevicesWithoutMaxDeviceLimit() { Device device = this.saveDevice(tenantId, "My device"); @@ -183,6 +190,8 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(device.getDeviceProfileId()); + firmware.setType(FIRMWARE); firmware.setTitle("my firmware"); firmware.setVersion("v1.0"); firmware.setFileName("test.txt"); @@ -198,6 +207,40 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { Device foundDevice = deviceService.findDeviceById(tenantId, savedDevice.getId()); Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); } + + @Test + public void testAssignFirmwareToDeviceWithDifferentDeviceProfile() { + Device device = new Device(); + device.setTenantId(tenantId); + device.setName("My device"); + device.setType("default"); + Device savedDevice = deviceService.saveDevice(device); + + Assert.assertNotNull(savedDevice); + + DeviceProfile deviceProfile = createDeviceProfile(tenantId, "New device Profile"); + DeviceProfile savedProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + Assert.assertNotNull(savedProfile); + + Firmware firmware = new Firmware(); + firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(savedProfile.getId()); + firmware.setType(FIRMWARE); + firmware.setTitle("my firmware"); + firmware.setVersion("v1.0"); + firmware.setFileName("test.txt"); + firmware.setContentType("text/plain"); + firmware.setChecksumAlgorithm("sha256"); + firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"); + firmware.setData(ByteBuffer.wrap(new byte[]{1})); + Firmware savedFirmware = firmwareService.saveFirmware(firmware); + + savedDevice.setFirmwareId(savedFirmware.getId()); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Can't assign firmware with different deviceProfile!"); + deviceService.saveDevice(savedDevice); + } @Test(expected = DataValidationException.class) public void testSaveDeviceWithEmptyName() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseFirmwareServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseFirmwareServiceTest.java index bf96d09922..816b59fb64 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseFirmwareServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseFirmwareServiceTest.java @@ -19,13 +19,16 @@ import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.After; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; 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.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -36,6 +39,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE; + public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { public static final String TITLE = "My firmware"; @@ -50,6 +55,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { private TenantId tenantId; + private DeviceProfileId deviceProfileId; + @Before public void before() { Tenant tenant = new Tenant(); @@ -57,8 +64,16 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Assert.assertNotNull(savedTenant); tenantId = savedTenant.getId(); + + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile"); + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + Assert.assertNotNull(savedDeviceProfile); + deviceProfileId = savedDeviceProfile.getId(); } + @Rule + public ExpectedException thrown = ExpectedException.none(); + @After public void after() { tenantService.deleteTenant(tenantId); @@ -68,6 +83,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { public void testSaveFirmware() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -99,6 +116,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { public void testSaveFirmwareInfoAndUpdateWithData() { FirmwareInfo firmwareInfo = new FirmwareInfo(); firmwareInfo.setTenantId(tenantId); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); FirmwareInfo savedFirmwareInfo = firmwareService.saveFirmwareInfo(firmwareInfo); @@ -112,6 +131,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { Firmware firmware = new Firmware(savedFirmwareInfo.getId()); firmware.setCreatedTime(firmwareInfo.getCreatedTime()); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -135,9 +156,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { firmwareService.deleteFirmware(tenantId, savedFirmwareInfo.getId()); } - @Test(expected = DataValidationException.class) + @Test public void testSaveFirmwareWithEmptyTenant() { Firmware firmware = new Firmware(); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -145,65 +168,126 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksum(CHECKSUM); firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware should be assigned to tenant!"); firmwareService.saveFirmware(firmware); } - @Test(expected = DataValidationException.class) + @Test + public void testSaveFirmwareWithEmptyDeviceProfile() { + Firmware firmware = new Firmware(); + firmware.setTenantId(tenantId); + firmware.setType(FIRMWARE); + firmware.setTitle(TITLE); + firmware.setVersion(VERSION); + firmware.setFileName(FILE_NAME); + firmware.setContentType(CONTENT_TYPE); + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); + firmware.setChecksum(CHECKSUM); + firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware should be assigned to deviceProfile!"); + firmwareService.saveFirmware(firmware); + } + + @Test + public void testSaveFirmwareWithEmptyType() { + Firmware firmware = new Firmware(); + firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setTitle(TITLE); + firmware.setVersion(VERSION); + firmware.setFileName(FILE_NAME); + firmware.setContentType(CONTENT_TYPE); + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); + firmware.setChecksum(CHECKSUM); + firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Type should be specified!"); + firmwareService.saveFirmware(firmware); + } + + @Test public void testSaveFirmwareWithEmptyTitle() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); firmware.setContentType(CONTENT_TYPE); firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksum(CHECKSUM); firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware title should be specified!"); firmwareService.saveFirmware(firmware); } - @Test(expected = DataValidationException.class) + @Test public void testSaveFirmwareWithEmptyFileName() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setContentType(CONTENT_TYPE); firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksum(CHECKSUM); firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware file name should be specified!"); firmwareService.saveFirmware(firmware); } - @Test(expected = DataValidationException.class) + @Test public void testSaveFirmwareWithEmptyContentType() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksum(CHECKSUM); firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware content type should be specified!"); firmwareService.saveFirmware(firmware); } - @Test(expected = DataValidationException.class) + @Test public void testSaveFirmwareWithEmptyData() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); firmware.setContentType(CONTENT_TYPE); firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksum(CHECKSUM); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware data should be specified!"); firmwareService.saveFirmware(firmware); } - @Test(expected = DataValidationException.class) + @Test public void testSaveFirmwareWithInvalidTenant() { Firmware firmware = new Firmware(); firmware.setTenantId(new TenantId(Uuids.timeBased())); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -211,41 +295,77 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksum(CHECKSUM); firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware is referencing to non-existent tenant!"); firmwareService.saveFirmware(firmware); } - @Test(expected = DataValidationException.class) + @Test + public void testSaveFirmwareWithInvalidDeviceProfileId() { + Firmware firmware = new Firmware(); + firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(new DeviceProfileId(Uuids.timeBased())); + firmware.setType(FIRMWARE); + firmware.setTitle(TITLE); + firmware.setVersion(VERSION); + firmware.setFileName(FILE_NAME); + firmware.setContentType(CONTENT_TYPE); + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); + firmware.setChecksum(CHECKSUM); + firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware is referencing to non-existent device profile!"); + firmwareService.saveFirmware(firmware); + } + + @Test public void testSaveFirmwareWithEmptyChecksum() { Firmware firmware = new Firmware(); - firmware.setTenantId(new TenantId(Uuids.timeBased())); + firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); firmware.setContentType(CONTENT_TYPE); firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware checksum should be specified!"); firmwareService.saveFirmware(firmware); } - @Test(expected = DataValidationException.class) + @Test public void testSaveFirmwareInfoWithExistingTitleAndVersion() { FirmwareInfo firmwareInfo = new FirmwareInfo(); firmwareInfo.setTenantId(tenantId); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION); firmwareService.saveFirmwareInfo(firmwareInfo); FirmwareInfo newFirmwareInfo = new FirmwareInfo(); newFirmwareInfo.setTenantId(tenantId); + newFirmwareInfo.setDeviceProfileId(deviceProfileId); + newFirmwareInfo.setType(FIRMWARE); newFirmwareInfo.setTitle(TITLE); newFirmwareInfo.setVersion(VERSION); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware with such title and version already exists!"); firmwareService.saveFirmwareInfo(newFirmwareInfo); } - @Test(expected = DataValidationException.class) + @Test public void testSaveFirmwareWithExistingTitleAndVersion() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -257,18 +377,27 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { Firmware newFirmware = new Firmware(); newFirmware.setTenantId(tenantId); + newFirmware.setDeviceProfileId(deviceProfileId); + newFirmware.setType(FIRMWARE); newFirmware.setTitle(TITLE); newFirmware.setVersion(VERSION); newFirmware.setFileName(FILE_NAME); newFirmware.setContentType(CONTENT_TYPE); + newFirmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); + newFirmware.setChecksum(CHECKSUM); newFirmware.setData(DATA); + + thrown.expect(DataValidationException.class); + thrown.expectMessage("Firmware with such title and version already exists!"); firmwareService.saveFirmware(newFirmware); } - @Test(expected = DataValidationException.class) + @Test public void testDeleteFirmwareWithReferenceByDevice() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -281,11 +410,13 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { Device device = new Device(); device.setTenantId(tenantId); device.setName("My device"); - device.setType("default"); + device.setDeviceProfileId(deviceProfileId); device.setFirmwareId(savedFirmware.getId()); Device savedDevice = deviceService.saveDevice(device); try { + thrown.expect(DataValidationException.class); + thrown.expectMessage("The firmware referenced by the devices cannot be deleted!"); firmwareService.deleteFirmware(tenantId, savedFirmware.getId()); } finally { deviceService.deleteDevice(tenantId, savedDevice.getId()); @@ -293,10 +424,15 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { } } - @Test(expected = DataValidationException.class) + @Test public void testDeleteFirmwareWithReferenceByDeviceProfile() { + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Test Device Profile"); + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(savedDeviceProfile.getId()); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -306,11 +442,12 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { firmware.setData(DATA); Firmware savedFirmware = firmwareService.saveFirmware(firmware); - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile"); - deviceProfile.setFirmwareId(savedFirmware.getId()); - DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + savedDeviceProfile.setFirmwareId(savedFirmware.getId()); + deviceProfileService.saveDeviceProfile(savedDeviceProfile); try { + thrown.expect(DataValidationException.class); + thrown.expectMessage("The firmware referenced by the device profile cannot be deleted!"); firmwareService.deleteFirmware(tenantId, savedFirmware.getId()); } finally { deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); @@ -322,6 +459,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { public void testFindFirmwareById() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -341,6 +480,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { public void testFindFirmwareInfoById() { FirmwareInfo firmware = new FirmwareInfo(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); FirmwareInfo savedFirmware = firmwareService.saveFirmwareInfo(firmware); @@ -355,6 +496,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { public void testDeleteFirmware() { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION); firmware.setFileName(FILE_NAME); @@ -377,6 +520,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { for (int i = 0; i < 165; i++) { Firmware firmware = new Firmware(); firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(TITLE); firmware.setVersion(VERSION + i); firmware.setFileName(FILE_NAME); @@ -420,6 +565,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { for (int i = 0; i < 165; i++) { FirmwareInfo firmwareInfo = new FirmwareInfo(); firmwareInfo.setTenantId(tenantId); + firmwareInfo.setDeviceProfileId(deviceProfileId); + firmwareInfo.setType(FIRMWARE); firmwareInfo.setTitle(TITLE); firmwareInfo.setVersion(VERSION + i); firmwareInfo.setFileName(FILE_NAME); @@ -434,7 +581,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { PageLink pageLink = new PageLink(16); PageData pageData; do { - pageData = firmwareService.findTenantFirmwaresByTenantIdAndHasData(tenantId, false, pageLink); + pageData = firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, FIRMWARE, false, pageLink); loadedFirmwares.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -450,6 +597,8 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { Firmware firmware = new Firmware(f.getId()); firmware.setCreatedTime(f.getCreatedTime()); firmware.setTenantId(f.getTenantId()); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); firmware.setTitle(f.getTitle()); firmware.setVersion(f.getVersion()); firmware.setFileName(FILE_NAME); @@ -465,7 +614,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { loadedFirmwares = new ArrayList<>(); pageLink = new PageLink(16); do { - pageData = firmwareService.findTenantFirmwaresByTenantIdAndHasData(tenantId, true, pageLink); + pageData = firmwareService.findTenantFirmwaresByTenantIdAndDeviceProfileIdAndTypeAndHasData(tenantId, deviceProfileId, FIRMWARE, true, pageLink); loadedFirmwares.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); From ca2e08f8490e642dbd361be1a69c1fd2ef730c7f Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 29 Apr 2021 10:10:21 +0300 Subject: [PATCH 3/7] refactoring --- .../thingsboard/server/controller/ControllerSqlTestSuite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java index 85b058f597..653f6978f6 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -29,7 +29,7 @@ import java.util.Arrays; // "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", // "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest", - "org.thingsboard.server.controller.sql.FirmwareControllerSqlTest", + "org.thingsboard.server.controller.sql.*Test", }) public class ControllerSqlTestSuite { From fd8dee0a9d5252d6d65d8bfeef906bf401e3ee61 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 29 Apr 2021 16:01:47 +0300 Subject: [PATCH 4/7] UI: Add firmware type --- ui-ngx/src/app/core/http/entity.service.ts | 2 +- ui-ngx/src/app/core/http/firmware.service.ts | 15 +++---- .../add-device-profile-dialog.component.html | 4 -- .../add-device-profile-dialog.component.ts | 2 - .../profile/device-profile.component.html | 8 ++++ .../profile/device-profile.component.ts | 5 +++ .../device-wizard-dialog.component.html | 4 -- .../wizard/device-wizard-dialog.component.ts | 2 - .../home/pages/device/device.component.html | 8 ++++ .../home/pages/device/device.component.ts | 30 +++++++++----- .../firmware/firmware-table-config.resolve.ts | 18 ++++++--- .../pages/firmware/firmwares.component.html | 19 ++++++++- .../pages/firmware/firmwares.component.ts | 14 ++++++- .../firmware-autocomplete.component.html | 4 +- .../firmware-autocomplete.component.ts | 40 +++++++++++++++++-- ui-ngx/src/app/shared/models/device.models.ts | 2 + .../src/app/shared/models/firmware.models.ts | 19 ++++++++- .../assets/locale/locale.constant-en_US.json | 9 +++++ 18 files changed, 159 insertions(+), 46 deletions(-) diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 04d2db610d..c5ef4b8db4 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -361,7 +361,7 @@ export class EntityService { break; case EntityType.FIRMWARE: pageLink.sortOrder.property = 'title'; - entitiesObservable = this.firmwareService.getFirmwares(pageLink, true, config); + entitiesObservable = this.firmwareService.getFirmwares(pageLink, config); break; } return entitiesObservable; diff --git a/ui-ngx/src/app/core/http/firmware.service.ts b/ui-ngx/src/app/core/http/firmware.service.ts index 7bf42fb49e..8c3249aee6 100644 --- a/ui-ngx/src/app/core/http/firmware.service.ts +++ b/ui-ngx/src/app/core/http/firmware.service.ts @@ -20,7 +20,7 @@ import { PageLink } from '@shared/models/page/page-link'; import { defaultHttpOptionsFromConfig, defaultHttpUploadOptions, RequestConfig } from '@core/http/http-utils'; import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; -import { Firmware, FirmwareInfo } from '@shared/models/firmware.models'; +import { Firmware, FirmwareInfo, FirmwareType } from '@shared/models/firmware.models'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { deepClone, isDefinedAndNotNull } from '@core/utils'; @@ -34,12 +34,13 @@ export class FirmwareService { } - public getFirmwares(pageLink: PageLink, hasData?: boolean, config?: RequestConfig): Observable> { - let url = `/api/firmwares`; - if (isDefinedAndNotNull(hasData)) { - url += `/${hasData}`; - } - url += `${pageLink.toQuery()}`; + public getFirmwares(pageLink: PageLink, config?: RequestConfig): Observable> { + return this.http.get>(`/api/firmwares${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); + } + + public getFirmwaresInfoByDeviceProfileId(pageLink: PageLink, deviceProfileId: string, type: FirmwareType, + hasData = true, config?: RequestConfig): Observable> { + const url = `/api/firmwares/${deviceProfileId}/${type}/${hasData}${pageLink.toQuery()}`; return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html index a4f9fc3482..23219f1074 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html @@ -60,10 +60,6 @@ {{ 'device-profile.type-required' | translate }} - - device-profile.description diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index 83f248db92..9ad7993857 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -108,7 +108,6 @@ export class AddDeviceProfileDialogComponent extends type: [DeviceProfileType.DEFAULT, [Validators.required]], defaultRuleChainId: [null, []], defaultQueueName: ['', []], - firmwareId: [null], description: ['', []] } ); @@ -187,7 +186,6 @@ export class AddDeviceProfileDialogComponent extends transportType: this.transportConfigFormGroup.get('transportType').value, provisionType: deviceProvisionConfiguration.type, provisionDeviceKey, - firmwareId: this.deviceProfileDetailsFormGroup.get('firmwareId').value, description: this.deviceProfileDetailsFormGroup.get('description').value, profileData: { configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT), diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html index 5f7593a03b..5c21d65adc 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html @@ -65,8 +65,16 @@ + + device-profile.type diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts index 23f1bd511c..d8505a0a3b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts @@ -40,6 +40,7 @@ import { EntityType } from '@shared/models/entity-type.models'; import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { ServiceType } from '@shared/models/queue.models'; import { EntityId } from '@shared/models/id/entity-id'; +import { FirmwareType } from '@shared/models/firmware.models'; @Component({ selector: 'tb-device-profile', @@ -69,6 +70,8 @@ export class DeviceProfileComponent extends EntityComponent { deviceProfileId: EntityId; + firmwareTypes = FirmwareType; + constructor(protected store: Store, protected translate: TranslateService, @Optional() @Inject('entity') protected entityValue: DeviceProfile, @@ -110,6 +113,7 @@ export class DeviceProfileComponent extends EntityComponent { defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], defaultQueueName: [entity ? entity.defaultQueueName : '', []], firmwareId: [entity ? entity.firmwareId : null], + softwareId: [entity ? entity.softwareId : null], description: [entity ? entity.description : '', []], } ); @@ -186,6 +190,7 @@ export class DeviceProfileComponent extends EntityComponent { this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false}); this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false}); this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false}); + this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false}); this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); } diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 416b006499..245cb6503b 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -48,10 +48,6 @@ device.label - - device-profile.transport-type diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index df925e4e21..4e2b5b2ff8 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -107,7 +107,6 @@ export class DeviceWizardDialogComponent extends this.deviceWizardFormGroup = this.fb.group({ name: ['', Validators.required], label: [''], - firmwareId: [null], gateway: [false], overwriteActivityTime: [false], transportType: [DeviceTransportType.DEFAULT, Validators.required], @@ -313,7 +312,6 @@ export class DeviceWizardDialogComponent extends const device = { name: this.deviceWizardFormGroup.get('name').value, label: this.deviceWizardFormGroup.get('label').value, - firmwareId: this.deviceWizardFormGroup.get('firmwareId').value, deviceProfileId: profileId, additionalInfo: { gateway: this.deviceWizardFormGroup.get('gateway').value, diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index be2ce1367d..f09437662a 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -103,8 +103,16 @@ + + diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.ts b/ui-ngx/src/app/modules/home/pages/device/device.component.ts index 34335b5e2f..d7f21fb2fc 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.ts @@ -34,6 +34,7 @@ import { ActionNotificationShow } from '@core/notification/notification.actions' import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { Subject } from 'rxjs'; +import { FirmwareType } from '@shared/models/firmware.models'; @Component({ selector: 'tb-device', @@ -48,6 +49,8 @@ export class DeviceComponent extends EntityComponent { deviceScope: 'tenant' | 'customer' | 'customer_user' | 'edge'; + firmwareTypes = FirmwareType; + constructor(protected store: Store, protected translate: TranslateService, @Inject('entity') protected entityValue: DeviceInfo, @@ -80,6 +83,7 @@ export class DeviceComponent extends EntityComponent { name: [entity ? entity.name : '', [Validators.required]], deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], firmwareId: [entity ? entity.firmwareId : null], + softwareId: [entity ? entity.softwareId : null], label: [entity ? entity.label : ''], deviceData: [entity ? entity.deviceData : null, [Validators.required]], additionalInfo: this.fb.group( @@ -94,19 +98,19 @@ export class DeviceComponent extends EntityComponent { } updateForm(entity: DeviceInfo) { - this.entityForm.patchValue({name: entity.name}); - this.entityForm.patchValue({deviceProfileId: entity.deviceProfileId}); - this.entityForm.patchValue({firmwareId: entity.firmwareId}); - this.entityForm.patchValue({label: entity.label}); - this.entityForm.patchValue({deviceData: entity.deviceData}); this.entityForm.patchValue({ - additionalInfo: - { - gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false, - overwriteActivityTime: entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false - } + name: entity.name, + deviceProfileId: entity.deviceProfileId, + firmwareId: entity.firmwareId, + softwareId: entity.softwareId, + label: entity.label, + deviceData: entity.deviceData, + additionalInfo: { + gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false, + overwriteActivityTime: entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false, + description: entity.additionalInfo ? entity.additionalInfo.description : '' + } }); - this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); } @@ -152,6 +156,10 @@ export class DeviceComponent extends EntityComponent { this.entityForm.markAsDirty(); } } + this.entityForm.patchValue({ + firmwareId: null, + softwareId: null + }); } } } diff --git a/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts b/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts index b809f6f403..23efe2117b 100644 --- a/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts +++ b/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts @@ -21,7 +21,12 @@ import { EntityTableColumn, EntityTableConfig } from '@home/models/entity/entities-table-config.models'; -import { Firmware, FirmwareInfo } from '@shared/models/firmware.models'; +import { + ChecksumAlgorithmTranslationMap, + Firmware, + FirmwareInfo, + FirmwareTypeTranslationMap +} from '@shared/models/firmware.models'; import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; import { TranslateService } from '@ngx-translate/core'; import { DatePipe } from '@angular/common'; @@ -49,14 +54,17 @@ export class FirmwareTableConfigResolve implements Resolve('createdTime', 'common.created-time', this.datePipe, '150px'), - new EntityTableColumn('title', 'firmware.title', '33%'), - new EntityTableColumn('version', 'firmware.version', '33%'), - new EntityTableColumn('fileName', 'firmware.file-name', '33%'), + new EntityTableColumn('title', 'firmware.title', '25%'), + new EntityTableColumn('version', 'firmware.version', '25%'), + new EntityTableColumn('type', 'firmware.type', '25%', entity => { + return this.translate.instant(FirmwareTypeTranslationMap.get(entity.type)); + }), + new EntityTableColumn('fileName', 'firmware.file-name', '25%'), new EntityTableColumn('dataSize', 'firmware.file-size', '70px', entity => { return this.fileSize.transform(entity.dataSize || 0); }), new EntityTableColumn('checksum', 'firmware.checksum', '540px', entity => { - return `${entity.checksumAlgorithm}: ${entity.checksum}`; + return `${ChecksumAlgorithmTranslationMap.get(entity.checksumAlgorithm)}: ${entity.checksum}`; }, () => ({}), false) ); diff --git a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html index 2911802a75..cba515f1d8 100644 --- a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html +++ b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html @@ -67,10 +67,27 @@ +
+ + firmware.type + + + + {{ firmwareTypeTranslationMap.get(firmwareType) | translate }} + + + + + +
firmware.checksum-algorithm - + diff --git a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts index 8ffef239b4..adfd2050c7 100644 --- a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts +++ b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts @@ -22,7 +22,13 @@ import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { EntityComponent } from '@home/components/entity/entity.component'; -import { ChecksumAlgorithm, ChecksumAlgorithmTranslationMap, Firmware } from '@shared/models/firmware.models'; +import { + ChecksumAlgorithm, + ChecksumAlgorithmTranslationMap, + Firmware, + FirmwareType, + FirmwareTypeTranslationMap +} from '@shared/models/firmware.models'; import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; import { ActionNotificationShow } from '@core/notification/notification.actions'; @@ -36,6 +42,8 @@ export class FirmwaresComponent extends EntityComponent implements OnI checksumAlgorithms = Object.values(ChecksumAlgorithm); checksumAlgorithmTranslationMap = ChecksumAlgorithmTranslationMap; + firmwareTypes = Object.values(FirmwareType); + firmwareTypeTranslationMap = FirmwareTypeTranslationMap; constructor(protected store: Store, protected translate: TranslateService, @@ -83,6 +91,8 @@ export class FirmwaresComponent extends EntityComponent implements OnI const form = this.fb.group({ title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]], + type: [entity?.type ? entity.type : FirmwareType.FIRMWARE, [Validators.required]], + deviceProfileId: [entity ? entity.deviceProfileId : null], checksumAlgorithm: [entity ? entity.checksumAlgorithm : null], checksum: [entity ? entity.checksum : '', Validators.maxLength(1020)], additionalInfo: this.fb.group( @@ -105,6 +115,8 @@ export class FirmwaresComponent extends EntityComponent implements OnI this.entityForm.patchValue({ title: entity.title, version: entity.version, + type: entity.type, + deviceProfileId: entity.deviceProfileId, checksumAlgorithm: entity.checksumAlgorithm, checksum: entity.checksum, fileName: entity.fileName, diff --git a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html index 4e733b3132..7bb434e7d1 100644 --- a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html @@ -37,11 +37,11 @@
- firmware.no-firmware-text + {{ notFoundFirmware | translate }}
- {{ translate.get('firmware.no-firmware-matching', + {{ translate.get(notMatchingFirmware, {entity: truncate.transform(searchText, true, 6, '...')}) | async }} diff --git a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts index 79dc170c7b..ccdf16aedd 100644 --- a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts @@ -28,7 +28,7 @@ import { BaseData } from '@shared/models/base-data'; import { EntityService } from '@core/http/entity.service'; import { TruncatePipe } from '@shared/pipe/truncate.pipe'; import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { FirmwareInfo } from '@shared/models/firmware.models'; +import { FirmwareInfo, FirmwareType } from '@shared/models/firmware.models'; import { FirmwareService } from '@core/http/firmware.service'; import { PageLink } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; @@ -49,6 +49,12 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn modelValue: string | null; + @Input() + type = FirmwareType.FIRMWARE; + + @Input() + deviceProfileId: string; + @Input() labelText: string; @@ -81,6 +87,23 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn private dirty = false; + private firmwareTypeTranslation = new Map( + [ + [FirmwareType.FIRMWARE, { + label: 'firmware.firmware', + required: 'firmware.firmware-required', + noFound: 'firmware.no-firmware-text', + noMatching: 'firmware.no-firmware-matching' + }], + [FirmwareType.SOFTWARE, { + label: 'firmware.software', + required: 'firmware.software-required', + noFound: 'firmware.no-software-text', + noMatching: 'firmware.no-software-matching' + }] + ] + ); + private propagateChange = (v: any) => { }; constructor(private store: Store, @@ -209,7 +232,8 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn property: 'title', direction: Direction.ASC }); - return this.firmwareService.getFirmwares(pageLink, true, {ignoreLoading: true}).pipe( + return this.firmwareService.getFirmwaresInfoByDeviceProfileId(pageLink, this.deviceProfileId, this.type, + true, {ignoreLoading: true}).pipe( map((data) => data && data.data.length ? data.data : null) ); } @@ -223,11 +247,19 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn } get placeholderText(): string { - return this.labelText || 'firmware.firmware'; + return this.labelText || this.firmwareTypeTranslation.get(this.type).label; } get requiredErrorText(): string { - return this.requiredText || 'firmware.firmware-required'; + return this.requiredText || this.firmwareTypeTranslation.get(this.type).required; + } + + get notFoundFirmware(): string { + return this.firmwareTypeTranslation.get(this.type).noFound; + } + + get notMatchingFirmware(): string { + return this.firmwareTypeTranslation.get(this.type).noMatching; } firmwareTitleText(firmware: FirmwareInfo): string { diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 6067eeee38..42c1689006 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -467,6 +467,7 @@ export interface DeviceProfile extends BaseData { defaultRuleChainId?: RuleChainId; defaultQueueName?: string; firmwareId?: FirmwareId; + softwareId?: FirmwareId; profileData: DeviceProfileData; } @@ -522,6 +523,7 @@ export interface Device extends BaseData { type: string; label: string; firmwareId?: FirmwareId; + softwareId?: FirmwareId; deviceProfileId?: DeviceProfileId; deviceData?: DeviceData; additionalInfo?: any; diff --git a/ui-ngx/src/app/shared/models/firmware.models.ts b/ui-ngx/src/app/shared/models/firmware.models.ts index 65dd1761bf..57c95c3c9a 100644 --- a/ui-ngx/src/app/shared/models/firmware.models.ts +++ b/ui-ngx/src/app/shared/models/firmware.models.ts @@ -17,6 +17,7 @@ import { BaseData } from '@shared/models/base-data'; import { TenantId } from '@shared/models/id/tenant-id'; import { FirmwareId } from '@shared/models/id/firmware-id'; +import { DeviceProfileId } from '@shared/models/id/device-profile-id'; export enum ChecksumAlgorithm { MD5 = 'md5', @@ -32,14 +33,28 @@ export const ChecksumAlgorithmTranslationMap = new Map( + [ + [FirmwareType.FIRMWARE, 'firmware.types.firmware'], + [FirmwareType.SOFTWARE, 'firmware.types.software'] + ] +); + export interface FirmwareInfo extends BaseData { tenantId?: TenantId; + type: FirmwareType; + deviceProfileId?: DeviceProfileId; title?: string; version?: string; hasData?: boolean; fileName: string; - checksum?: ChecksumAlgorithm; - checksumAlgorithm?: string; + checksum?: string; + checksumAlgorithm?: ChecksumAlgorithm; contentType: string; dataSize?: number; additionalInfo?: any; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index d59ee56236..5b90961b29 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1928,6 +1928,8 @@ "idCopiedMessage": "Firmware Id has been copied to clipboard", "no-firmware-matching": "No firmware matching '{{entity}}' were found.", "no-firmware-text": "No firmwares found", + "no-software-matching": "No sowtware matching '{{entity}}' were found.", + "no-software-text": "No software found", "file-name": "File name", "file-size": "File size", "file-size-bytes": "File size in bytes", @@ -1936,8 +1938,15 @@ "firmware-required": "Firmware is required.", "search": "Search firmwares", "selected-firmware": "{ count, plural, 1 {1 firmware} other {# firmwares} } selected", + "software": "Software", + "software-required": "Software is required.", "title": "Title", "title-required": "Title is required.", + "type": "Firmware type", + "types": { + "firmware": "Firmware", + "software": "Software" + }, "version": "Version", "version-required": "Version is required.", "warning-after-save-no-edit": "Once the firmware is saved, it will not be possible to change the title and version fields." From 4d4ca9b723f295b798448ddde1d40d56dd3f5a81 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 29 Apr 2021 17:00:05 +0300 Subject: [PATCH 5/7] firmware tests and validation improvements --- .../main/data/upgrade/3.2.2/schema_update.sql | 19 ++++- .../dao/device/DeviceProfileServiceImpl.java | 13 +++ .../server/dao/device/DeviceServiceImpl.java | 7 ++ .../dao/firmware/BaseFirmwareService.java | 16 ++-- .../server/dao/firmware/FirmwareInfoDao.java | 3 + .../server/dao/model/sql/FirmwareEntity.java | 10 ++- .../dao/model/sql/FirmwareInfoEntity.java | 8 +- .../sql/firmware/FirmwareInfoRepository.java | 9 ++ .../dao/sql/firmware/JpaFirmwareInfoDao.java | 6 ++ .../resources/sql/schema-entities-hsql.sql | 2 +- .../main/resources/sql/schema-entities.sql | 2 +- .../dao/service/BaseFirmwareServiceTest.java | 83 +++++++++++++++---- 12 files changed, 145 insertions(+), 33 deletions(-) diff --git a/application/src/main/data/upgrade/3.2.2/schema_update.sql b/application/src/main/data/upgrade/3.2.2/schema_update.sql index da120f680e..af3fd418a8 100644 --- a/application/src/main/data/upgrade/3.2.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.2.2/schema_update.sql @@ -63,6 +63,7 @@ CREATE TABLE IF NOT EXISTS firmware ( id uuid NOT NULL CONSTRAINT firmware_pkey PRIMARY KEY, created_time bigint NOT NULL, tenant_id uuid NOT NULL, + device_profile_id uuid, type varchar(32) NOT NULL, title varchar(255) NOT NULL, version varchar(255) NOT NULL, @@ -78,10 +79,12 @@ CREATE TABLE IF NOT EXISTS firmware ( ); ALTER TABLE device_profile - ADD COLUMN IF NOT EXISTS firmware_id uuid; + ADD COLUMN IF NOT EXISTS firmware_id uuid, + ADD COLUMN IF NOT EXISTS software_id uuid; ALTER TABLE device - ADD COLUMN IF NOT EXISTS firmware_id uuid; + ADD COLUMN IF NOT EXISTS firmware_id uuid, + ADD COLUMN IF NOT EXISTS software_id uuid; DO $$ BEGIN @@ -91,11 +94,23 @@ DO $$ FOREIGN KEY (firmware_id) REFERENCES firmware(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); + END IF; + 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); 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); + END IF; END; $$; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 020fd7c524..9df20674c8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -56,6 +56,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.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -405,9 +406,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (firmware == null) { throw new DataValidationException("Can't assign non-existent firmware!"); } + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) { + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType()); + } if (firmware.getData() == null) { throw new DataValidationException("Can't assign firmware with empty data!"); } + if (!firmware.getDeviceProfileId().equals(deviceProfile.getId())) { + throw new DataValidationException("Can't assign firmware with different deviceProfile!"); + } } if (deviceProfile.getSoftwareId() != null) { @@ -415,9 +422,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (software == null) { throw new DataValidationException("Can't assign non-existent software!"); } + if (!software.getType().equals(FirmwareType.SOFTWARE)) { + throw new DataValidationException("Can't assign software with type: " + software.getType()); + } if (software.getData() == null) { throw new DataValidationException("Can't assign software with empty data!"); } + if (!software.getDeviceProfileId().equals(deviceProfile.getId())) { + throw new DataValidationException("Can't assign firmware with different deviceProfile!"); + } } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index dd9b46b62f..11d2fecd24 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.device.data.DeviceData; import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; 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; @@ -683,6 +684,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe if (firmware == null) { throw new DataValidationException("Can't assign non-existent firmware!"); } + if (!firmware.getType().equals(FirmwareType.FIRMWARE)) { + throw new DataValidationException("Can't assign firmware with type: " + firmware.getType()); + } if (firmware.getData() == null) { throw new DataValidationException("Can't assign firmware with empty data!"); } @@ -696,6 +700,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe if (software == null) { throw new DataValidationException("Can't assign non-existent software!"); } + if (!software.getType().equals(FirmwareType.SOFTWARE)) { + throw new DataValidationException("Can't assign software with type: " + software.getType()); + } if (software.getData() == null) { throw new DataValidationException("Can't assign software with empty data!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java b/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java index 207d629bbe..6ac3df8292 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/firmware/BaseFirmwareService.java @@ -191,6 +191,7 @@ public class BaseFirmwareService implements FirmwareService { protected void validateUpdate(TenantId tenantId, FirmwareInfo firmware) { FirmwareInfo firmwareOld = firmwareInfoDao.findById(tenantId, firmware.getUuidId()); + validateUpdateDeviceProfile(firmware, firmwareOld); BaseFirmwareService.validateUpdate(firmware, firmwareOld); } }; @@ -247,6 +248,7 @@ public class BaseFirmwareService implements FirmwareService { 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())) { @@ -255,11 +257,15 @@ public class BaseFirmwareService implements FirmwareService { } }; - private static void validateUpdate(FirmwareInfo firmware, FirmwareInfo firmwareOld) { - if (!firmwareOld.getDeviceProfileId().equals(firmware.getDeviceProfileId())) { - throw new DataValidationException("Updating firmware deviceProfile 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!"); } @@ -303,9 +309,7 @@ public class BaseFirmwareService implements FirmwareService { } } - if (firmwareInfo.getDeviceProfileId() == null) { - throw new DataValidationException("Firmware should be assigned to deviceProfile!"); - } else { + 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!"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java b/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java index 32ca8dc528..7cb6c3a57f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/firmware/FirmwareInfoDao.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.firmware; 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; @@ -31,4 +32,6 @@ public interface FirmwareInfoDao extends Dao { PageData findFirmwareInfoByTenantIdAndDeviceProfileIdAndTypeAndHasData(TenantId tenantId, DeviceProfileId deviceProfileId, FirmwareType firmwareType, boolean hasData, PageLink pageLink); + boolean isFirmwareUsed(FirmwareId firmwareId, FirmwareType type, DeviceProfileId deviceProfileId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java index a10ec8f7ed..4f3aded716 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareEntity.java @@ -32,9 +32,9 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.Lob; import javax.persistence.EnumType; import javax.persistence.Enumerated; +import javax.persistence.Lob; import javax.persistence.Table; import java.nio.ByteBuffer; import java.util.UUID; @@ -110,7 +110,9 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex this.createdTime = firmware.getCreatedTime(); this.setUuid(firmware.getUuidId()); this.tenantId = firmware.getTenantId().getId(); - this.deviceProfileId = firmware.getDeviceProfileId().getId(); + if (firmware.getDeviceProfileId() != null) { + this.deviceProfileId = firmware.getDeviceProfileId().getId(); + } this.type = firmware.getType(); this.title = firmware.getTitle(); this.version = firmware.getVersion(); @@ -138,7 +140,9 @@ public class FirmwareEntity extends BaseSqlEntity implements SearchTex Firmware firmware = new Firmware(new FirmwareId(id)); firmware.setCreatedTime(createdTime); firmware.setTenantId(new TenantId(tenantId)); - firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); + if (deviceProfileId != null) { + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); + } firmware.setType(type); firmware.setTitle(title); firmware.setVersion(version); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java index b1e058a012..bb62db5ea4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/FirmwareInfoEntity.java @@ -109,7 +109,9 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S this.setUuid(firmware.getUuidId()); this.tenantId = firmware.getTenantId().getId(); this.type = firmware.getType(); - this.deviceProfileId = firmware.getDeviceProfileId().getId(); + if (firmware.getDeviceProfileId() != null) { + this.deviceProfileId = firmware.getDeviceProfileId().getId(); + } this.title = firmware.getTitle(); this.version = firmware.getVersion(); this.fileName = firmware.getFileName(); @@ -154,7 +156,9 @@ public class FirmwareInfoEntity extends BaseSqlEntity implements S FirmwareInfo firmware = new FirmwareInfo(new FirmwareId(id)); firmware.setCreatedTime(createdTime); firmware.setTenantId(new TenantId(tenantId)); - firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); + if (deviceProfileId != null) { + firmware.setDeviceProfileId(new DeviceProfileId(deviceProfileId)); + } firmware.setType(type); firmware.setTitle(title); firmware.setVersion(version); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java index 5a7af9997b..dab6ce3304 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/firmware/FirmwareInfoRepository.java @@ -48,4 +48,13 @@ public interface FirmwareInfoRepository extends CrudRepository Date: Fri, 30 Apr 2021 10:52:07 +0300 Subject: [PATCH 6/7] implemented software update --- .../controller/DeviceProfileController.java | 9 +- .../firmware/DefaultFirmwareStateService.java | 108 +++++++++++++++--- .../firmware/FirmwareStateService.java | 2 +- .../transport/DefaultTransportApiService.java | 22 +++- .../server/dao/device/DeviceService.java | 2 + .../data/device/profile/MqttTopics.java | 13 ++- .../common/data/firmware/FirmwareKeyUtil.java | 34 +++++- .../common/msg/session/FeatureType.java | 2 +- .../common/msg/session/SessionMsgType.java | 3 +- common/queue/src/main/proto/queue.proto | 2 + .../transport/coap/CoapTransportResource.java | 23 +++- .../transport/http/DeviceApiController.java | 37 ++++-- .../transport/mqtt/MqttTransportHandler.java | 88 ++++++++------ .../mqtt/adaptors/JsonMqttAdaptor.java | 8 +- .../mqtt/adaptors/MqttTransportAdaptor.java | 3 +- .../mqtt/adaptors/ProtoMqttAdaptor.java | 7 +- .../server/dao/device/DeviceDao.java | 2 + .../server/dao/device/DeviceServiceImpl.java | 11 +- .../dao/model/sql/AbstractDeviceEntity.java | 2 +- .../dao/sql/device/DeviceRepository.java | 9 ++ .../server/dao/sql/device/JpaDeviceDao.java | 10 ++ .../firmware-autocomplete.component.ts | 3 +- 22 files changed, 308 insertions(+), 92 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java index 225c79b79a..849bcb51b9 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceProfileController.java @@ -146,12 +146,16 @@ public class DeviceProfileController extends BaseController { checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE); boolean isFirmwareChanged = false; + boolean isSoftwareChanged = false; if (!created) { DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId()); if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) { isFirmwareChanged = true; } + if (!Objects.equals(deviceProfile.getSoftwareId(), oldDeviceProfile.getSoftwareId())) { + isSoftwareChanged = true; + } } DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); @@ -164,9 +168,8 @@ public class DeviceProfileController extends BaseController { null, created ? ActionType.ADDED : ActionType.UPDATED, null); - if (isFirmwareChanged) { - firmwareStateService.update(savedDeviceProfile); - } + firmwareStateService.update(savedDeviceProfile, isFirmwareChanged, isSoftwareChanged); + sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(), deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); return savedDeviceProfile; diff --git a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java index c4ad9feceb..a09ac3bb31 100644 --- a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java @@ -25,6 +25,7 @@ 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.FirmwareKeyUtil; +import org.thingsboard.server.common.data.firmware.FirmwareType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.FirmwareId; import org.thingsboard.server.common.data.id.TenantId; @@ -56,6 +57,7 @@ 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; @@ -67,6 +69,8 @@ import static org.thingsboard.server.common.data.firmware.FirmwareKey.VERSION; import static org.thingsboard.server.common.data.firmware.FirmwareKeyUtil.getAttributeKey; import static org.thingsboard.server.common.data.firmware.FirmwareKeyUtil.getTargetTelemetryKey; import static org.thingsboard.server.common.data.firmware.FirmwareKeyUtil.getTelemetryKey; +import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE; +import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE; @Slf4j @Service @@ -95,6 +99,11 @@ public class DefaultFirmwareStateService implements FirmwareStateService { @Override public void update(Device device, Device oldDevice) { + updateFirmware(device, oldDevice); + updateSoftware(device, oldDevice); + } + + private void updateFirmware(Device device, Device oldDevice) { FirmwareId newFirmwareId = device.getFirmwareId(); if (newFirmwareId == null) { DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); @@ -109,35 +118,84 @@ public class DefaultFirmwareStateService implements FirmwareStateService { } if (!newFirmwareId.equals(oldFirmwareId)) { // Device was updated and new firmware is different from previous firmware. - send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE); } } else { // Device was updated and new firmware is not set. - remove(device); + remove(device, FIRMWARE); } } else if (newFirmwareId != null) { // Device was created and firmware is defined. - send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); + send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis(), FIRMWARE); + } + } + + private void updateSoftware(Device device, Device oldDevice) { + FirmwareId 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(); + if (oldSoftwareId == null) { + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId()); + oldSoftwareId = oldDeviceProfile.getSoftwareId(); + } + if (!newSoftwareId.equals(oldSoftwareId)) { + // Device was updated and new firmware is different from previous firmware. + send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE); + } + } else { + // Device was updated and new firmware is not set. + remove(device, SOFTWARE); + } + } else if (newSoftwareId != null) { + // Device was created and firmware is defined. + send(device.getTenantId(), device.getId(), newSoftwareId, System.currentTimeMillis(), SOFTWARE); } } @Override - public void update(DeviceProfile deviceProfile) { + public void update(DeviceProfile deviceProfile, boolean isFirmwareChanged, boolean isSoftwareChanged) { TenantId tenantId = deviceProfile.getTenantId(); + if (isFirmwareChanged) { + update(tenantId, deviceProfile, FIRMWARE); + } + if (isSoftwareChanged) { + update(tenantId, deviceProfile, SOFTWARE); + } + } + + private void update(TenantId tenantId, DeviceProfile deviceProfile, FirmwareType firmwareType) { + Function> getDevicesFunction; Consumer 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); + updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts, firmwareType); } else { - updateConsumer = this::remove; + updateConsumer = d -> remove(d, firmwareType); } PageLink pageLink = new PageLink(100); PageData pageData; do { - pageData = deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pageLink); - + pageData = getDevicesFunction.apply(pageLink); pageData.getData().forEach(updateConsumer); if (pageData.hasNext()) { @@ -152,16 +210,37 @@ public class DefaultFirmwareStateService implements FirmwareStateService { FirmwareId targetFirmwareId = new FirmwareId(new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB())); 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()); 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 = device.getFirmwareId(); + FirmwareId currentFirmwareId; + + switch (firmwareType) { + case FIRMWARE: + currentFirmwareId = device.getFirmwareId(); + break; + case SOFTWARE: + currentFirmwareId = device.getSoftwareId(); + break; + default: + log.warn("Unsupported firmware type: [{}]", firmwareType); + return false; + } if (currentFirmwareId == null) { - currentFirmwareId = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId()).getFirmwareId(); + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId()); + switch (firmwareType) { + case FIRMWARE: + currentFirmwareId = deviceProfile.getFirmwareId(); + break; + case SOFTWARE: + currentFirmwareId = deviceProfile.getSoftwareId(); + break; + } } if (targetFirmwareId.equals(currentFirmwareId)) { @@ -174,7 +253,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService { return isSuccess; } - private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts) { + private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts, FirmwareType firmwareType) { ToFirmwareStateServiceMsg msg = ToFirmwareStateServiceMsg.newBuilder() .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) @@ -182,6 +261,7 @@ public class DefaultFirmwareStateService implements FirmwareStateService { .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) .setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits()) .setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits()) + .setType(firmwareType.name()) .setTs(ts) .build(); @@ -252,14 +332,14 @@ public class DefaultFirmwareStateService implements FirmwareStateService { }); } - private void remove(Device device) { - telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, FirmwareKeyUtil.ALL_ATTRIBUTE_KEYS, + private void remove(Device device, FirmwareType firmwareType) { + telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, FirmwareKeyUtil.getAttributeKeys(firmwareType), new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { log.trace("[{}] Success remove target firmware attributes!", device.getId()); Set keysToNotify = new HashSet<>(); - FirmwareKeyUtil.ALL_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key))); + FirmwareKeyUtil.ALL_FW_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key))); tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(device.getTenantId(), device.getId(), keysToNotify), null); } diff --git a/application/src/main/java/org/thingsboard/server/service/firmware/FirmwareStateService.java b/application/src/main/java/org/thingsboard/server/service/firmware/FirmwareStateService.java index ac51b0d95e..8562f096c9 100644 --- a/application/src/main/java/org/thingsboard/server/service/firmware/FirmwareStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/firmware/FirmwareStateService.java @@ -23,7 +23,7 @@ public interface FirmwareStateService { void update(Device device, Device oldDevice); - void update(DeviceProfile deviceProfile); + void update(DeviceProfile deviceProfile, boolean isFirmwareChanged, boolean isSoftwareChanged); boolean process(ToFirmwareStateServiceMsg msg); diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 463af51862..6a765dff63 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -40,6 +40,7 @@ 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.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -455,16 +456,33 @@ public class DefaultTransportApiService implements TransportApiService { private ListenableFuture handle(TransportProtos.GetFirmwareRequestMsg 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()); Device device = deviceService.findDeviceById(tenantId, deviceId); if (device == null) { return getEmptyTransportApiResponseFuture(); } - FirmwareId firmwareId = device.getFirmwareId(); + FirmwareId firmwareId = null; + switch (firmwareType) { + case FIRMWARE: + firmwareId = device.getFirmwareId(); + break; + case SOFTWARE: + firmwareId = device.getSoftwareId(); + break; + } if (firmwareId == null) { - firmwareId = deviceProfileCache.find(device.getDeviceProfileId()).getFirmwareId(); + DeviceProfile deviceProfile = deviceProfileCache.find(device.getDeviceProfileId()); + switch (firmwareType) { + case FIRMWARE: + firmwareId = deviceProfile.getFirmwareId(); + break; + case SOFTWARE: + firmwareId = deviceProfile.getSoftwareId(); + break; + } } TransportProtos.GetFirmwareResponseMsg.Builder builder = TransportProtos.GetFirmwareResponseMsg.newBuilder(); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index afea29c394..26ea48ca2f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -63,6 +63,8 @@ public interface DeviceService { PageData findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink); + PageData findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink); + PageData findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink); PageData findDeviceInfosByTenantIdAndDeviceProfileId(TenantId tenantId, DeviceProfileId deviceProfileId, PageLink pageLink); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttTopics.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttTopics.java index 419f9c7f43..6373d41803 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttTopics.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/MqttTopics.java @@ -31,6 +31,7 @@ public class MqttTopics { private static final String SUB_TOPIC = "+"; private static final String PROVISION = "/provision"; private static final String FIRMWARE = "/fw"; + private static final String SOFTWARE = "/sw"; private static final String CHUNK = "/chunk/"; private static final String ERROR = "/error"; @@ -75,9 +76,17 @@ public class MqttTopics { // v2 topics public static final String BASE_DEVICE_API_TOPIC_V2 = "v2"; - public static final String DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + RESPONSE + "/"; - public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC = DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + SUB_TOPIC + CHUNK + SUB_TOPIC; + public static final String REQUEST_ID_PATTERN = "(?\\d+)"; + public static final String CHUNK_PATTERN = "(?\\d+)"; + + public static final String DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN; + public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC; public static final String DEVICE_FIRMWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + FIRMWARE + ERROR; + public static final String DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT = BASE_DEVICE_API_TOPIC_V2 + "%s" + RESPONSE + "/"+ "%s" + CHUNK + "%d"; + + public static final String DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + REQUEST + "/" + REQUEST_ID_PATTERN + CHUNK + CHUNK_PATTERN; + public static final String DEVICE_SOFTWARE_RESPONSES_TOPIC = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + RESPONSE + "/" + SUB_TOPIC + CHUNK + SUB_TOPIC; + public static final String DEVICE_SOFTWARE_ERROR_TOPIC = BASE_DEVICE_API_TOPIC_V2 + SOFTWARE + ERROR; private MqttTopics() { } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKeyUtil.java b/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKeyUtil.java index 8863016978..4712d48430 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKeyUtil.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKeyUtil.java @@ -16,18 +16,40 @@ package org.thingsboard.server.common.data.firmware; 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; + public class FirmwareKeyUtil { - public static final List ALL_ATTRIBUTE_KEYS; + public static final List ALL_FW_ATTRIBUTE_KEYS; + + public static final List ALL_SW_ATTRIBUTE_KEYS; + static { - ALL_ATTRIBUTE_KEYS = new ArrayList<>(); - for (FirmwareType type : FirmwareType.values()) { - for (FirmwareKey key : FirmwareKey.values()) { - ALL_ATTRIBUTE_KEYS.add(getAttributeKey(type, key)); - } + ALL_FW_ATTRIBUTE_KEYS = new ArrayList<>(); + for (FirmwareKey key : FirmwareKey.values()) { + ALL_FW_ATTRIBUTE_KEYS.add(getAttributeKey(FIRMWARE, key)); + + } + + ALL_SW_ATTRIBUTE_KEYS = new ArrayList<>(); + for (FirmwareKey key : FirmwareKey.values()) { + ALL_SW_ATTRIBUTE_KEYS.add(getAttributeKey(SOFTWARE, key)); + + } + } + + public static List getAttributeKeys(FirmwareType firmwareType) { + switch (firmwareType) { + case FIRMWARE: + return ALL_FW_ATTRIBUTE_KEYS; + case SOFTWARE: + return ALL_SW_ATTRIBUTE_KEYS; } + return Collections.emptyList(); } public static String getAttributeKey(FirmwareType type, FirmwareKey key) { diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/session/FeatureType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/session/FeatureType.java index 2756276dc4..ae965e327a 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/session/FeatureType.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/session/FeatureType.java @@ -16,5 +16,5 @@ package org.thingsboard.server.common.msg.session; public enum FeatureType { - ATTRIBUTES, TELEMETRY, RPC, CLAIM, PROVISION, FIRMWARE + ATTRIBUTES, TELEMETRY, RPC, CLAIM, PROVISION, FIRMWARE, SOFTWARE } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java index a6f05018f8..939197af80 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java @@ -32,7 +32,8 @@ public enum SessionMsgType { CLAIM_REQUEST(), - GET_FIRMWARE_REQUEST; + GET_FIRMWARE_REQUEST, + GET_SOFTWARE_REQUEST; private final boolean requiresRulesProcessing; diff --git a/common/queue/src/main/proto/queue.proto b/common/queue/src/main/proto/queue.proto index c1857e8933..25afefa12e 100644 --- a/common/queue/src/main/proto/queue.proto +++ b/common/queue/src/main/proto/queue.proto @@ -357,6 +357,7 @@ message GetFirmwareRequestMsg { int64 deviceIdLSB = 2; int64 tenantIdMSB = 3; int64 tenantIdLSB = 4; + string type = 5; } message GetFirmwareResponseMsg { @@ -675,4 +676,5 @@ message ToFirmwareStateServiceMsg { int64 deviceIdLSB = 5; int64 firmwareIdMSB = 6; int64 firmwareIdLSB = 7; + string type = 8; } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 468bc244c6..e287a28aa0 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -43,6 +43,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.security.DeviceTokenCredentials; import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.SessionMsgType; @@ -122,6 +123,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource { processRequest(exchange, SessionMsgType.GET_ATTRIBUTES_REQUEST); } else if (featureType.get() == FeatureType.FIRMWARE) { processRequest(exchange, SessionMsgType.GET_FIRMWARE_REQUEST); + } else if (featureType.get() == FeatureType.SOFTWARE) { + processRequest(exchange, SessionMsgType.GET_SOFTWARE_REQUEST); } else { log.trace("Invalid feature type parameter"); exchange.respond(CoAP.ResponseCode.BAD_REQUEST); @@ -326,12 +329,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource { new CoapNoOpCallback(exchange)); break; case GET_FIRMWARE_REQUEST: - TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder() - .setTenantIdMSB(sessionInfo.getTenantIdMSB()) - .setTenantIdLSB(sessionInfo.getTenantIdLSB()) - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()).build(); - transportContext.getTransportService().process(sessionInfo, requestMsg, new FirmwareCallback(exchange)); + getFirmwareCallback(sessionInfo, exchange, FirmwareType.FIRMWARE); + break; + case GET_SOFTWARE_REQUEST: + getFirmwareCallback(sessionInfo, exchange, FirmwareType.SOFTWARE); break; } } catch (AdaptorException e) { @@ -340,6 +341,16 @@ public class CoapTransportResource extends AbstractCoapTransportResource { } } + private void getFirmwareCallback(TransportProtos.SessionInfoProto sessionInfo, CoapExchange exchange, FirmwareType firmwareType) { + TransportProtos.GetFirmwareRequestMsg requestMsg = TransportProtos.GetFirmwareRequestMsg.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)); + } + private TransportProtos.SessionInfoProto lookupAsyncSessionInfo(String token) { tokenToNotificationCounterMap.remove(token); return tokenToSessionIdMap.remove(token); diff --git a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java b/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java index 62b46a5fe7..dcd5755d04 100644 --- a/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java +++ b/common/transport/http/src/main/java/org/thingsboard/server/transport/http/DeviceApiController.java @@ -34,6 +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.id.DeviceId; import org.thingsboard.server.common.transport.SessionMsgListener; import org.thingsboard.server.common.transport.TransportContext; @@ -209,8 +210,29 @@ public class DeviceApiController { public DeferredResult getFirmware(@PathVariable("deviceToken") String deviceToken, @RequestParam(value = "title") String title, @RequestParam(value = "version") String version, - @RequestParam(value = "chunkSize", required = false, defaultValue = "0") int chunkSize, + @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); + } + + @RequestMapping(value = "/{deviceToken}/software", method = RequestMethod.GET) + public DeferredResult getSoftware(@PathVariable("deviceToken") String deviceToken, + @RequestParam(value = "title") String title, + @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); + } + + @RequestMapping(value = "/provision", method = RequestMethod.POST) + public DeferredResult provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) { + DeferredResult responseWriter = new DeferredResult<>(); + transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json), + new DeviceProvisionCallback(responseWriter)); + return responseWriter; + } + + private DeferredResult getFirmwareCallback(String deviceToken, String title, String version, int size, int chunk, FirmwareType firmwareType) { DeferredResult responseWriter = new DeferredResult<>(); transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { @@ -218,20 +240,13 @@ public class DeviceApiController { .setTenantIdMSB(sessionInfo.getTenantIdMSB()) .setTenantIdLSB(sessionInfo.getTenantIdLSB()) .setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()).build(); - transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, chunkSize, chunk)); + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()) + .setType(firmwareType.name()).build(); + transportContext.getTransportService().process(sessionInfo, requestMsg, new GetFirmwareCallback(responseWriter, title, version, size, chunk)); })); return responseWriter; } - @RequestMapping(value = "/provision", method = RequestMethod.POST) - public DeferredResult provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) { - DeferredResult responseWriter = new DeferredResult<>(); - transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json), - new DeviceProvisionCallback(responseWriter)); - return responseWriter; - } - private static class DeviceAuthCallback implements TransportServiceCallback { private final TransportContext transportContext; private final DeferredResult responseWriter; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 5e4d8a75b9..bb1311429c 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -47,6 +47,7 @@ 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.msg.EncryptionUtil; import org.thingsboard.server.common.msg.tools.TbRateLimitsException; @@ -59,6 +60,7 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.common.transport.service.SessionMetaData; +import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; @@ -68,7 +70,6 @@ import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx; import org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler; import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher; -import org.thingsboard.server.common.transport.util.SslUtil; import javax.net.ssl.SSLPeerUnverifiedException; import java.io.IOException; @@ -97,6 +98,8 @@ import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK; import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE; import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN; +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN; /** * @author Andrew Shvayka @@ -104,7 +107,9 @@ import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; @Slf4j public class MqttTransportHandler extends ChannelInboundHandlerAdapter implements GenericFutureListener>, SessionMsgListener { - private static final Pattern FW_PATTERN = Pattern.compile("v2/fw/request/(?\\d+)/chunk/(?\\d+)"); + private static final Pattern FW_REQUEST_PATTERN = Pattern.compile(DEVICE_FIRMWARE_REQUEST_TOPIC_PATTERN); + private static final Pattern SW_REQUEST_PATTERN = Pattern.compile(DEVICE_SOFTWARE_REQUEST_TOPIC_PATTERN); + private static final String PAYLOAD_TOO_LARGE = "PAYLOAD_TOO_LARGE"; @@ -314,38 +319,10 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } else if (topicName.equals(MqttTopics.DEVICE_CLAIM_TOPIC)) { TransportProtos.ClaimDeviceMsg claimDeviceMsg = payloadAdaptor.convertToClaimDevice(deviceSessionCtx, mqttMsg); transportService.process(deviceSessionCtx.getSessionInfo(), claimDeviceMsg, getPubAckCallback(ctx, msgId, claimDeviceMsg)); - } else if ((fwMatcher = FW_PATTERN.matcher(topicName)).find()) { - 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); - } else { - chunkSize = fwChunkSizes.getOrDefault(requestId, 0); - } - - if (chunkSize > context.getMaxPayloadSize()) { - sendFirmwareError(ctx, PAYLOAD_TOO_LARGE); - return; - } - - String firmwareId = fwSessions.get(requestId); - - if (firmwareId != null) { - sendFirmware(ctx, mqttMsg.variableHeader().packetId(), firmwareId, requestId, chunkSize, chunk); - } else { - TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo(); - TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder() - .setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) - .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()) - .setTenantIdMSB(sessionInfo.getTenantIdMSB()) - .setTenantIdLSB(sessionInfo.getTenantIdLSB()) - .build(); - transportService.process(deviceSessionCtx.getSessionInfo(), getFirmwareRequestMsg, - new FirmwareCallback(ctx, mqttMsg.variableHeader().packetId(), getFirmwareRequestMsg, requestId, chunkSize, chunk)); - } + } else if ((fwMatcher = FW_REQUEST_PATTERN.matcher(topicName)).find()) { + getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.FIRMWARE); + } else if ((fwMatcher = SW_REQUEST_PATTERN.matcher(topicName)).find()) { + getFirmwareCallback(ctx, mqttMsg, msgId, fwMatcher, FirmwareType.SOFTWARE); } else { transportService.reportActivity(deviceSessionCtx.getSessionInfo()); ack(ctx, msgId); @@ -357,6 +334,41 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } + private void getFirmwareCallback(ChannelHandlerContext ctx, MqttPublishMessage mqttMsg, int msgId, Matcher fwMatcher, FirmwareType 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); + } else { + chunkSize = fwChunkSizes.getOrDefault(requestId, 0); + } + + if (chunkSize > context.getMaxPayloadSize()) { + sendFirmwareError(ctx, PAYLOAD_TOO_LARGE); + return; + } + + String firmwareId = fwSessions.get(requestId); + + if (firmwareId != null) { + sendFirmware(ctx, mqttMsg.variableHeader().packetId(), firmwareId, requestId, chunkSize, chunk, type); + } else { + TransportProtos.SessionInfoProto sessionInfo = deviceSessionCtx.getSessionInfo(); + TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.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)); + } + } + private void ack(ChannelHandlerContext ctx, int msgId) { if (msgId > 0) { ctx.writeAndFlush(createMqttPubAckMsg(msgId)); @@ -435,7 +447,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement 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); + sendFirmware(ctx, msgId, firmwareId.toString(), requestId, chunkSize, chunk, FirmwareType.valueOf(response.getType())); } else { sendFirmwareError(ctx, response.getResponseStatus().toString()); } @@ -448,13 +460,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } - private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk) { + private void sendFirmware(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, FirmwareType type) { log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId); ack(ctx, msgId); try { byte[] firmwareChunk = context.getFirmwareDataCache().get(firmwareId, chunkSize, chunk); deviceSessionCtx.getPayloadAdaptor() - .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk) + .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk, type) .ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); if (firmwareChunk != null && chunkSize != firmwareChunk.length) { scheduler.schedule(() -> processDisconnect(ctx), 60, TimeUnit.SECONDS); @@ -504,6 +516,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC: case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC: + case MqttTopics.DEVICE_SOFTWARE_RESPONSES_TOPIC: + case MqttTopics.DEVICE_SOFTWARE_ERROR_TOPIC: registerSubQoS(topic, grantedQoSList, reqQoS); break; default: diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index 8d0bf312a0..dbda48d15d 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -30,6 +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.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.gen.transport.TransportProtos; @@ -43,6 +44,9 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT; + + /** * @author Andrew Shvayka */ @@ -151,8 +155,8 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) { - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + requestId + "/chunk/" + chunk, firmwareChunk)); + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) { + return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk)); } public static JsonElement validateJsonPayload(UUID sessionId, ByteBuf payloadData) throws AdaptorException { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java index 2bd35df8d9..d0c1f30524 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java @@ -23,6 +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.transport.adaptor.AdaptorException; import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; @@ -77,7 +78,7 @@ public interface MqttTransportAdaptor { Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ProvisionDeviceResponseMsg provisionResponse) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) throws AdaptorException; + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException; default MqttPublishMessage createMqttPublishMsg(MqttDeviceAwareSessionContext ctx, String topic, byte[] payloadInBytes) { MqttFixedHeader mqttFixedHeader = diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java index d42e7d85e8..29df08e9c3 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java @@ -28,6 +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.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.ProtoConverter; @@ -38,6 +39,8 @@ import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionConte import java.util.Optional; +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT; + @Component @Slf4j public class ProtoMqttAdaptor implements MqttTransportAdaptor { @@ -165,8 +168,8 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { } @Override - public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk) throws AdaptorException { - return Optional.of(createMqttPublishMsg(ctx, MqttTopics.DEVICE_FIRMWARE_RESPONSE_TOPIC_PREFIX + requestId + "/" + chunk, firmwareChunk)); + public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, byte[] firmwareChunk, String requestId, int chunk, FirmwareType firmwareType) throws AdaptorException { + return Optional.of(createMqttPublishMsg(ctx, String.format(DEVICE_FIRMWARE_RESPONSES_TOPIC_FORMAT, firmwareType.getKeyPrefix(), requestId, chunk), firmwareChunk)); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java index 0a61ce554e..c8d35603ab 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceDao.java @@ -83,6 +83,8 @@ public interface DeviceDao extends Dao, TenantEntityDao { PageData findDevicesByTenantIdAndTypeAndEmptyFirmware(UUID tenantId, String type, PageLink pageLink); + PageData findDevicesByTenantIdAndTypeAndEmptySoftware(UUID tenantId, String type, PageLink pageLink); + /** * Find device infos by tenantId, type and page link. * diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 11d2fecd24..811f944a37 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -357,13 +357,22 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @Override public PageData findDevicesByTenantIdAndTypeAndEmptyFirmware(TenantId tenantId, String type, PageLink pageLink) { - log.trace("Executing findDevicesByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); + log.trace("Executing findDevicesByTenantIdAndTypeAndEmptyFirmware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateString(type, "Incorrect type " + type); validatePageLink(pageLink); return deviceDao.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId.getId(), type, pageLink); } + @Override + public PageData findDevicesByTenantIdAndTypeAndEmptySoftware(TenantId tenantId, String type, PageLink pageLink) { + log.trace("Executing findDevicesByTenantIdAndTypeAndEmptySoftware, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateString(type, "Incorrect type " + type); + validatePageLink(pageLink); + return deviceDao.findDevicesByTenantIdAndTypeAndEmptySoftware(tenantId.getId(), type, pageLink); + } + @Override public PageData findDeviceInfosByTenantIdAndType(TenantId tenantId, String type, PageLink pageLink) { log.trace("Executing findDeviceInfosByTenantIdAndType, tenantId [{}], type [{}], pageLink [{}]", tenantId, type, pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java index 5b9d49a036..ed6a871fea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java @@ -106,7 +106,7 @@ public abstract class AbstractDeviceEntity extends BaseSqlEnti this.firmwareId = device.getFirmwareId().getId(); } if (device.getSoftwareId() != null) { - this.firmwareId = device.getSoftwareId().getId(); + this.softwareId = device.getSoftwareId().getId(); } this.deviceData = JacksonUtil.convertValue(device.getDeviceData(), ObjectNode.class); this.name = device.getName(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java index 999e69f330..ac71fee1a8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceRepository.java @@ -103,6 +103,15 @@ public interface DeviceRepository extends PagingAndSortingRepository findByTenantIdAndTypeAndSoftwareIdIsNull(@Param("tenantId") UUID tenantId, + @Param("type") String type, + @Param("textSearch") String textSearch, + Pageable pageable); + @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 " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java index a545c7cc6b..efdd70f53b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/JpaDeviceDao.java @@ -159,6 +159,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao DaoUtil.toPageable(pageLink))); } + @Override + public PageData findDevicesByTenantIdAndTypeAndEmptySoftware(UUID tenantId, String type, PageLink pageLink) { + return DaoUtil.toPageData( + deviceRepository.findByTenantIdAndTypeAndSoftwareIdIsNull( + tenantId, + type, + Objects.toString(pageLink.getTextSearch(), ""), + DaoUtil.toPageable(pageLink))); + } + @Override public PageData findDeviceInfosByTenantIdAndType(UUID tenantId, String type, PageLink pageLink) { return DaoUtil.toPageData( diff --git a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts index ccdf16aedd..751415bcce 100644 --- a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts @@ -183,7 +183,7 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn this.entityService.getEntity(EntityType.FIRMWARE, firmwareId, {ignoreLoading: true, ignoreErrors: true}).subscribe( (entity) => { this.modelValue = entity.id.id; - this.firmwareFormGroup.get('firmwareId').patchValue(entity, {emitEvent: false}); + this.firmwareFormGroup.get('firmwareId').patchValue(entity); }, () => { this.modelValue = null; @@ -196,6 +196,7 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn } else { this.modelValue = null; this.firmwareFormGroup.get('firmwareId').patchValue('', {emitEvent: false}); + this.propagateChange(null); } } else { this.modelValue = null; From 37891ec6c6f4313fb74f46fc8e83371e56367f65 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Fri, 30 Apr 2021 11:14:29 +0300 Subject: [PATCH 7/7] Minor refactoring --- .../firmware/DefaultFirmwareStateService.java | 36 +++++-------------- .../transport/DefaultTransportApiService.java | 21 ++--------- .../server/common/data/Device.java | 2 +- .../server/common/data/DeviceProfile.java | 2 +- .../server/common/data/HasFirmware.java | 25 +++++++++++++ ...FirmwareKeyUtil.java => FirmwareUtil.java} | 19 +++++++++- 6 files changed, 56 insertions(+), 49 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/HasFirmware.java rename common/data/src/main/java/org/thingsboard/server/common/data/firmware/{FirmwareKeyUtil.java => FirmwareUtil.java} (80%) diff --git a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java index a09ac3bb31..ca369b3698 100644 --- a/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/firmware/DefaultFirmwareStateService.java @@ -24,7 +24,7 @@ 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.FirmwareKeyUtil; +import org.thingsboard.server.common.data.firmware.FirmwareUtil; import org.thingsboard.server.common.data.firmware.FirmwareType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.FirmwareId; @@ -66,9 +66,9 @@ 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.FirmwareKeyUtil.getAttributeKey; -import static org.thingsboard.server.common.data.firmware.FirmwareKeyUtil.getTargetTelemetryKey; -import static org.thingsboard.server.common.data.firmware.FirmwareKeyUtil.getTelemetryKey; +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.firmware.FirmwareType.FIRMWARE; import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE; @@ -217,30 +217,10 @@ public class DefaultFirmwareStateService implements FirmwareStateService { if (device == null) { log.warn("[{}] [{}] Device was removed during firmware update msg was queued!", tenantId, deviceId); } else { - FirmwareId currentFirmwareId; - - switch (firmwareType) { - case FIRMWARE: - currentFirmwareId = device.getFirmwareId(); - break; - case SOFTWARE: - currentFirmwareId = device.getSoftwareId(); - break; - default: - log.warn("Unsupported firmware type: [{}]", firmwareType); - return false; - } - + FirmwareId currentFirmwareId = FirmwareUtil.getFirmwareId(device, firmwareType); if (currentFirmwareId == null) { DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId()); - switch (firmwareType) { - case FIRMWARE: - currentFirmwareId = deviceProfile.getFirmwareId(); - break; - case SOFTWARE: - currentFirmwareId = deviceProfile.getSoftwareId(); - break; - } + currentFirmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType); } if (targetFirmwareId.equals(currentFirmwareId)) { @@ -333,13 +313,13 @@ public class DefaultFirmwareStateService implements FirmwareStateService { } private void remove(Device device, FirmwareType firmwareType) { - telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, FirmwareKeyUtil.getAttributeKeys(firmwareType), + telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, FirmwareUtil.getAttributeKeys(firmwareType), new FutureCallback<>() { @Override public void onSuccess(@Nullable Void tmp) { log.trace("[{}] Success remove target firmware attributes!", device.getId()); Set keysToNotify = new HashSet<>(); - FirmwareKeyUtil.ALL_FW_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key))); + FirmwareUtil.ALL_FW_ATTRIBUTE_KEYS.forEach(key -> keysToNotify.add(new AttributeKey(DataConstants.SHARED_SCOPE, key))); tbClusterService.pushMsgToCore(DeviceAttributesEventNotificationMsg.onDelete(device.getTenantId(), device.getId(), keysToNotify), null); } diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 6a765dff63..28890700e7 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -41,6 +41,7 @@ import org.thingsboard.server.common.data.device.credentials.BasicMqttCredential 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.id.CustomerId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; @@ -463,26 +464,10 @@ public class DefaultTransportApiService implements TransportApiService { return getEmptyTransportApiResponseFuture(); } - FirmwareId firmwareId = null; - switch (firmwareType) { - case FIRMWARE: - firmwareId = device.getFirmwareId(); - break; - case SOFTWARE: - firmwareId = device.getSoftwareId(); - break; - } - + FirmwareId firmwareId = FirmwareUtil.getFirmwareId(device, firmwareType); if (firmwareId == null) { DeviceProfile deviceProfile = deviceProfileCache.find(device.getDeviceProfileId()); - switch (firmwareType) { - case FIRMWARE: - firmwareId = deviceProfile.getFirmwareId(); - break; - case SOFTWARE: - firmwareId = deviceProfile.getSoftwareId(); - break; - } + firmwareId = FirmwareUtil.getFirmwareId(deviceProfile, firmwareType); } TransportProtos.GetFirmwareResponseMsg.Builder builder = TransportProtos.GetFirmwareResponseMsg.newBuilder(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java index b48fc114cb..bce3ba703f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/Device.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/Device.java @@ -32,7 +32,7 @@ import java.io.IOException; @EqualsAndHashCode(callSuper = true) @Slf4j -public class Device extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId { +public class Device extends SearchTextBasedWithAdditionalInfo implements HasName, HasTenantId, HasCustomerId, HasFirmware { private static final long serialVersionUID = 2807343040519543363L; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index c3a2e5ecee..daf7d77af0 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -36,7 +36,7 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn @Data @EqualsAndHashCode(callSuper = true) @Slf4j -public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId { +public class DeviceProfile extends SearchTextBased implements HasName, HasTenantId, HasFirmware { private TenantId tenantId; @NoXss diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/HasFirmware.java b/common/data/src/main/java/org/thingsboard/server/common/data/HasFirmware.java new file mode 100644 index 0000000000..ae05829092 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/HasFirmware.java @@ -0,0 +1,25 @@ +/** + * 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.common.data; + +import org.thingsboard.server.common.data.id.FirmwareId; + +public interface HasFirmware { + + FirmwareId getFirmwareId(); + + FirmwareId getSoftwareId(); +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKeyUtil.java b/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareUtil.java similarity index 80% rename from common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKeyUtil.java rename to common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareUtil.java index 4712d48430..646ad24173 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareKeyUtil.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/firmware/FirmwareUtil.java @@ -15,6 +15,10 @@ */ package org.thingsboard.server.common.data.firmware; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.HasFirmware; +import org.thingsboard.server.common.data.id.FirmwareId; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -22,7 +26,8 @@ import java.util.List; import static org.thingsboard.server.common.data.firmware.FirmwareType.FIRMWARE; import static org.thingsboard.server.common.data.firmware.FirmwareType.SOFTWARE; -public class FirmwareKeyUtil { +@Slf4j +public class FirmwareUtil { public static final List ALL_FW_ATTRIBUTE_KEYS; @@ -71,4 +76,16 @@ public class FirmwareKeyUtil { public static String getTelemetryKey(FirmwareType type, FirmwareKey key) { return type.getKeyPrefix() + "_" + key.getValue(); } + + public static FirmwareId getFirmwareId(HasFirmware entity, FirmwareType firmwareType) { + switch (firmwareType) { + case FIRMWARE: + return entity.getFirmwareId(); + case SOFTWARE: + return entity.getSoftwareId(); + default: + log.warn("Unsupported firmware type: [{}]", firmwareType); + return null; + } + } }