Commit 935aab753506e2e5d46718ae458588ef1439e0a7

Authored by YevhenBondarenko
1 parent 7954f91f

added checksum and checksum algorithm for firmware

@@ -32,10 +32,15 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -32,10 +32,15 @@ CREATE TABLE IF NOT EXISTS firmware (
32 created_time bigint NOT NULL, 32 created_time bigint NOT NULL,
33 tenant_id uuid NOT NULL, 33 tenant_id uuid NOT NULL,
34 title varchar(255) NOT NULL, 34 title varchar(255) NOT NULL,
  35 + version varchar(255) NOT NULL,
  36 + file_name varchar(255),
  37 + content_type varchar(255),
  38 + checksum_algorithm varchar(32),
  39 + checksum varchar(1020),
  40 + data binary,
  41 + additional_info varchar,
35 search_text varchar(255), 42 search_text varchar(255),
36 - file_name varchar(255) NOT NULL,  
37 - content_type varchar(255) NOT NULL,  
38 - data bytea 43 + CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
39 ); 44 );
40 45
41 ALTER TABLE device_profile 46 ALTER TABLE device_profile
@@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.page.PageData; @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.page.PageData;
36 import org.thingsboard.server.common.data.page.PageLink; 36 import org.thingsboard.server.common.data.page.PageLink;
37 import org.thingsboard.server.queue.util.TbCoreComponent; 37 import org.thingsboard.server.queue.util.TbCoreComponent;
38 import org.thingsboard.server.service.security.permission.Operation; 38 import org.thingsboard.server.service.security.permission.Operation;
  39 +import org.thingsboard.server.service.security.permission.Resource;
39 40
40 import java.nio.ByteBuffer; 41 import java.nio.ByteBuffer;
41 42
@@ -97,14 +98,36 @@ public class FirmwareController extends BaseController { @@ -97,14 +98,36 @@ public class FirmwareController extends BaseController {
97 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") 98 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
98 @RequestMapping(value = "/firmware", method = RequestMethod.POST) 99 @RequestMapping(value = "/firmware", method = RequestMethod.POST)
99 @ResponseBody 100 @ResponseBody
100 - public Firmware saveFirmware(@RequestParam("title") String title,  
101 - @RequestBody MultipartFile firmwareFile) throws ThingsboardException {  
102 - checkParameter("title", title); 101 + public FirmwareInfo saveFirmwareInfo(@RequestParam("title") FirmwareInfo firmwareInfo) throws ThingsboardException {
  102 + checkEntity(firmwareInfo.getId(), firmwareInfo, Resource.FIRMWARE);
103 try { 103 try {
104 - checkNotNull(firmwareFile);  
105 - Firmware firmware = new Firmware(); 104 + return firmwareService.saveFirmwareInfo(firmwareInfo);
  105 + } catch (Exception e) {
  106 + throw handleException(e);
  107 + }
  108 + }
  109 +
  110 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
  111 + @RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.POST)
  112 + @ResponseBody
  113 + public Firmware saveFirmwareData(@PathVariable(FIRMWARE_ID) String strFirmwareId,
  114 + @RequestParam String checksum,
  115 + @RequestParam String checksumAlgorithm,
  116 + @RequestBody MultipartFile firmwareFile) throws ThingsboardException {
  117 + checkParameter(FIRMWARE_ID, strFirmwareId);
  118 + checkParameter("checksum", checksum);
  119 + try {
  120 + FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId));
  121 + FirmwareInfo info = checkFirmwareInfoId(firmwareId, Operation.READ);
  122 +
  123 + Firmware firmware = new Firmware(firmwareId);
  124 + firmware.setCreatedTime(info.getCreatedTime());
106 firmware.setTenantId(getTenantId()); 125 firmware.setTenantId(getTenantId());
107 - firmware.setTitle(title); 126 + firmware.setVersion(info.getVersion());
  127 + firmware.setAdditionalInfo(info.getAdditionalInfo());
  128 +
  129 + firmware.setChecksumAlgorithm(checksumAlgorithm);
  130 + firmware.setChecksum(checksum);
108 firmware.setFileName(firmwareFile.getOriginalFilename()); 131 firmware.setFileName(firmwareFile.getOriginalFilename());
109 firmware.setContentType(firmwareFile.getContentType()); 132 firmware.setContentType(firmwareFile.getContentType());
110 firmware.setData(ByteBuffer.wrap(firmwareFile.getBytes())); 133 firmware.setData(ByteBuffer.wrap(firmwareFile.getBytes()));
@@ -230,7 +230,6 @@ public class ThingsboardInstallService { @@ -230,7 +230,6 @@ public class ThingsboardInstallService {
230 systemDataLoaderService.createAdminSettings(); 230 systemDataLoaderService.createAdminSettings();
231 systemDataLoaderService.loadSystemWidgets(); 231 systemDataLoaderService.loadSystemWidgets();
232 systemDataLoaderService.createOAuth2Templates(); 232 systemDataLoaderService.createOAuth2Templates();
233 - systemDataLoaderService.loadSystemLwm2mResources();  
234 // systemDataLoaderService.loadSystemPlugins(); 233 // systemDataLoaderService.loadSystemPlugins();
235 // systemDataLoaderService.loadSystemRules(); 234 // systemDataLoaderService.loadSystemRules();
236 235
@@ -22,9 +22,10 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -22,9 +22,10 @@ import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.data.page.PageData; 22 import org.thingsboard.server.common.data.page.PageData;
23 import org.thingsboard.server.common.data.page.PageLink; 23 import org.thingsboard.server.common.data.page.PageLink;
24 24
25 -  
26 public interface FirmwareService { 25 public interface FirmwareService {
27 26
  27 + FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo);
  28 +
28 Firmware saveFirmware(Firmware firmware); 29 Firmware saveFirmware(Firmware firmware);
29 30
30 Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId); 31 Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId);
@@ -27,6 +27,14 @@ public class Firmware extends FirmwareInfo { @@ -27,6 +27,14 @@ public class Firmware extends FirmwareInfo {
27 27
28 private static final long serialVersionUID = 3091601761339422546L; 28 private static final long serialVersionUID = 3091601761339422546L;
29 29
  30 + private String fileName;
  31 +
  32 + private String contentType;
  33 +
  34 + private String checksumAlgorithm;
  35 +
  36 + private String checksum;
  37 +
30 private transient ByteBuffer data; 38 private transient ByteBuffer data;
31 39
32 public Firmware() { 40 public Firmware() {
@@ -39,6 +47,10 @@ public class Firmware extends FirmwareInfo { @@ -39,6 +47,10 @@ public class Firmware extends FirmwareInfo {
39 47
40 public Firmware(Firmware firmware) { 48 public Firmware(Firmware firmware) {
41 super(firmware); 49 super(firmware);
  50 + this.fileName = firmware.getFileName();
  51 + this.contentType = firmware.getContentType();
42 this.data = firmware.getData(); 52 this.data = firmware.getData();
  53 + this.checksumAlgorithm = firmware.getChecksumAlgorithm();
  54 + this.checksum = firmware.getChecksum();
43 } 55 }
44 } 56 }
@@ -24,14 +24,13 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -24,14 +24,13 @@ import org.thingsboard.server.common.data.id.TenantId;
24 @Slf4j 24 @Slf4j
25 @Data 25 @Data
26 @EqualsAndHashCode(callSuper = true) 26 @EqualsAndHashCode(callSuper = true)
27 -public class FirmwareInfo extends SearchTextBased<FirmwareId> implements HasTenantId { 27 +public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId> implements HasTenantId {
28 28
29 private static final long serialVersionUID = 3168391583570815419L; 29 private static final long serialVersionUID = 3168391583570815419L;
30 30
31 private TenantId tenantId; 31 private TenantId tenantId;
32 private String title; 32 private String title;
33 - private String fileName;  
34 - private String contentType; 33 + private String version;
35 34
36 public FirmwareInfo() { 35 public FirmwareInfo() {
37 super(); 36 super();
@@ -45,8 +44,7 @@ public class FirmwareInfo extends SearchTextBased<FirmwareId> implements HasTena @@ -45,8 +44,7 @@ public class FirmwareInfo extends SearchTextBased<FirmwareId> implements HasTena
45 super(firmwareInfo); 44 super(firmwareInfo);
46 this.tenantId = firmwareInfo.getTenantId(); 45 this.tenantId = firmwareInfo.getTenantId();
47 this.title = firmwareInfo.getTitle(); 46 this.title = firmwareInfo.getTitle();
48 - this.fileName = firmwareInfo.getFileName();  
49 - this.contentType = firmwareInfo.getContentType(); 47 + this.version = firmwareInfo.getVersion();
50 } 48 }
51 49
52 @Override 50 @Override
@@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo;
40 import org.thingsboard.server.common.data.DeviceProfileProvisionType; 40 import org.thingsboard.server.common.data.DeviceProfileProvisionType;
41 import org.thingsboard.server.common.data.DeviceProfileType; 41 import org.thingsboard.server.common.data.DeviceProfileType;
42 import org.thingsboard.server.common.data.DeviceTransportType; 42 import org.thingsboard.server.common.data.DeviceTransportType;
  43 +import org.thingsboard.server.common.data.Firmware;
43 import org.thingsboard.server.common.data.Tenant; 44 import org.thingsboard.server.common.data.Tenant;
44 import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; 45 import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
45 import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; 46 import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
@@ -59,6 +60,7 @@ import org.thingsboard.server.common.data.page.PageData; @@ -59,6 +60,7 @@ import org.thingsboard.server.common.data.page.PageData;
59 import org.thingsboard.server.common.data.page.PageLink; 60 import org.thingsboard.server.common.data.page.PageLink;
60 import org.thingsboard.server.dao.entity.AbstractEntityService; 61 import org.thingsboard.server.dao.entity.AbstractEntityService;
61 import org.thingsboard.server.dao.exception.DataValidationException; 62 import org.thingsboard.server.dao.exception.DataValidationException;
  63 +import org.thingsboard.server.dao.firmware.FirmwareService;
62 import org.thingsboard.server.dao.service.DataValidator; 64 import org.thingsboard.server.dao.service.DataValidator;
63 import org.thingsboard.server.dao.service.PaginatedRemover; 65 import org.thingsboard.server.dao.service.PaginatedRemover;
64 import org.thingsboard.server.dao.service.Validator; 66 import org.thingsboard.server.dao.service.Validator;
@@ -107,6 +109,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -107,6 +109,9 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
107 @Autowired 109 @Autowired
108 private CacheManager cacheManager; 110 private CacheManager cacheManager;
109 111
  112 + @Autowired
  113 + private FirmwareService firmwareService;
  114 +
110 private final Lock findOrCreateLock = new ReentrantLock(); 115 private final Lock findOrCreateLock = new ReentrantLock();
111 116
112 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}") 117 @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}")
@@ -389,6 +394,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -389,6 +394,15 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
389 } 394 }
390 } 395 }
391 396
  397 + if (deviceProfile.getFirmwareId() != null) {
  398 + Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId());
  399 + if (firmware == null) {
  400 + throw new DataValidationException("Can't assign non-existent firmware!");
  401 + }
  402 + if (firmware.getData() == null) {
  403 + throw new DataValidationException("Can't assign firmware with empty data!");
  404 + }
  405 + }
392 } 406 }
393 407
394 @Override 408 @Override
@@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.DeviceProfile; @@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.DeviceProfile;
39 import org.thingsboard.server.common.data.EntitySubtype; 39 import org.thingsboard.server.common.data.EntitySubtype;
40 import org.thingsboard.server.common.data.EntityType; 40 import org.thingsboard.server.common.data.EntityType;
41 import org.thingsboard.server.common.data.EntityView; 41 import org.thingsboard.server.common.data.EntityView;
  42 +import org.thingsboard.server.common.data.Firmware;
42 import org.thingsboard.server.common.data.Tenant; 43 import org.thingsboard.server.common.data.Tenant;
43 import org.thingsboard.server.common.data.device.DeviceSearchQuery; 44 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
44 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; 45 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
@@ -68,6 +69,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -68,6 +69,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService;
68 import org.thingsboard.server.dao.entityview.EntityViewService; 69 import org.thingsboard.server.dao.entityview.EntityViewService;
69 import org.thingsboard.server.dao.event.EventService; 70 import org.thingsboard.server.dao.event.EventService;
70 import org.thingsboard.server.dao.exception.DataValidationException; 71 import org.thingsboard.server.dao.exception.DataValidationException;
  72 +import org.thingsboard.server.dao.firmware.FirmwareService;
71 import org.thingsboard.server.dao.service.DataValidator; 73 import org.thingsboard.server.dao.service.DataValidator;
72 import org.thingsboard.server.dao.service.PaginatedRemover; 74 import org.thingsboard.server.dao.service.PaginatedRemover;
73 import org.thingsboard.server.dao.tenant.TbTenantProfileCache; 75 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
@@ -128,6 +130,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -128,6 +130,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
128 @Lazy 130 @Lazy
129 private TbTenantProfileCache tenantProfileCache; 131 private TbTenantProfileCache tenantProfileCache;
130 132
  133 + @Autowired
  134 + private FirmwareService firmwareService;
  135 +
131 @Override 136 @Override
132 public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) { 137 public DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId) {
133 log.trace("Executing findDeviceInfoById [{}]", deviceId); 138 log.trace("Executing findDeviceInfoById [{}]", deviceId);
@@ -598,6 +603,16 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -598,6 +603,16 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
598 throw new DataValidationException("Can't assign device to customer from different tenant!"); 603 throw new DataValidationException("Can't assign device to customer from different tenant!");
599 } 604 }
600 } 605 }
  606 +
  607 + if (device.getFirmwareId() != null) {
  608 + Firmware firmware = firmwareService.findFirmwareById(tenantId, device.getFirmwareId());
  609 + if (firmware == null) {
  610 + throw new DataValidationException("Can't assign non-existent firmware!");
  611 + }
  612 + if (firmware.getData() == null) {
  613 + throw new DataValidationException("Can't assign firmware with empty data!");
  614 + }
  615 + }
601 } 616 }
602 }; 617 };
603 618
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 */ 15 */
16 package org.thingsboard.server.dao.firmware; 16 package org.thingsboard.server.dao.firmware;
17 17
  18 +import com.google.common.hash.HashFunction;
  19 +import com.google.common.hash.Hashing;
18 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
19 import org.apache.commons.lang3.StringUtils; 21 import org.apache.commons.lang3.StringUtils;
20 import org.hibernate.exception.ConstraintViolationException; 22 import org.hibernate.exception.ConstraintViolationException;
@@ -54,10 +56,35 @@ public class BaseFirmwareService implements FirmwareService { @@ -54,10 +56,35 @@ public class BaseFirmwareService implements FirmwareService {
54 } 56 }
55 57
56 @Override 58 @Override
  59 + public FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo) {
  60 + log.trace("Executing saveFirmwareInfo [{}]", firmwareInfo);
  61 + firmwareInfoValidator.validate(firmwareInfo, FirmwareInfo::getTenantId);
  62 + try {
  63 + return firmwareInfoDao.save(firmwareInfo.getTenantId(), firmwareInfo);
  64 + } catch (Exception t) {
  65 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  66 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("firmware_tenant_title_version_unq_key")) {
  67 + throw new DataValidationException("Firmware with such title and version already exists!");
  68 + } else {
  69 + throw t;
  70 + }
  71 + }
  72 + }
  73 +
  74 + @Override
57 public Firmware saveFirmware(Firmware firmware) { 75 public Firmware saveFirmware(Firmware firmware) {
58 log.trace("Executing saveFirmware [{}]", firmware); 76 log.trace("Executing saveFirmware [{}]", firmware);
59 - firmwareValidator.validate(firmware, Firmware::getTenantId);  
60 - return firmwareDao.save(firmware.getTenantId(), firmware); 77 + firmwareValidator.validate(firmware, FirmwareInfo::getTenantId);
  78 + try {
  79 + return firmwareDao.save(firmware.getTenantId(), firmware);
  80 + } catch (Exception t) {
  81 + ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
  82 + if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("firmware_tenant_title_version_unq_key")) {
  83 + throw new DataValidationException("Firmware with such title and version already exists!");
  84 + } else {
  85 + throw t;
  86 + }
  87 + }
61 } 88 }
62 89
63 @Override 90 @Override
@@ -107,6 +134,42 @@ public class BaseFirmwareService implements FirmwareService { @@ -107,6 +134,42 @@ public class BaseFirmwareService implements FirmwareService {
107 tenantFirmwareRemover.removeEntities(tenantId, tenantId); 134 tenantFirmwareRemover.removeEntities(tenantId, tenantId);
108 } 135 }
109 136
  137 + private DataValidator<FirmwareInfo> firmwareInfoValidator = new DataValidator<>() {
  138 +
  139 + @Override
  140 + protected void validateDataImpl(TenantId tenantId, FirmwareInfo firmware) {
  141 + if (firmware.getTenantId() == null) {
  142 + throw new DataValidationException("Firmware should be assigned to tenant!");
  143 + } else {
  144 + Tenant tenant = tenantDao.findById(firmware.getTenantId(), firmware.getTenantId().getId());
  145 + if (tenant == null) {
  146 + throw new DataValidationException("Firmware is referencing to non-existent tenant!");
  147 + }
  148 + }
  149 +
  150 + if (StringUtils.isEmpty(firmware.getTitle())) {
  151 + throw new DataValidationException("Firmware title should be specified!");
  152 + }
  153 +
  154 + if (StringUtils.isEmpty(firmware.getVersion())) {
  155 + throw new DataValidationException("Firmware version should be specified!");
  156 + }
  157 + }
  158 +
  159 + @Override
  160 + protected void validateUpdate(TenantId tenantId, FirmwareInfo firmware) {
  161 + FirmwareInfo firmwareOld = firmwareInfoDao.findById(tenantId, firmware.getUuidId());
  162 +
  163 + if (!firmwareOld.getTitle().equals(firmware.getTitle())) {
  164 + throw new DataValidationException("Updating firmware title is prohibited!");
  165 + }
  166 +
  167 + if (!firmwareOld.getVersion().equals(firmware.getVersion())) {
  168 + throw new DataValidationException("Updating firmware version is prohibited!");
  169 + }
  170 + }
  171 + };
  172 +
110 private DataValidator<Firmware> firmwareValidator = new DataValidator<>() { 173 private DataValidator<Firmware> firmwareValidator = new DataValidator<>() {
111 174
112 @Override 175 @Override
@@ -123,22 +186,91 @@ public class BaseFirmwareService implements FirmwareService { @@ -123,22 +186,91 @@ public class BaseFirmwareService implements FirmwareService {
123 if (StringUtils.isEmpty(firmware.getTitle())) { 186 if (StringUtils.isEmpty(firmware.getTitle())) {
124 throw new DataValidationException("Firmware title should be specified!"); 187 throw new DataValidationException("Firmware title should be specified!");
125 } 188 }
  189 +
  190 + if (StringUtils.isEmpty(firmware.getVersion())) {
  191 + throw new DataValidationException("Firmware version should be specified!");
  192 + }
  193 +
126 if (StringUtils.isEmpty(firmware.getFileName())) { 194 if (StringUtils.isEmpty(firmware.getFileName())) {
127 throw new DataValidationException("Firmware file name should be specified!"); 195 throw new DataValidationException("Firmware file name should be specified!");
128 } 196 }
  197 +
129 if (StringUtils.isEmpty(firmware.getContentType())) { 198 if (StringUtils.isEmpty(firmware.getContentType())) {
130 throw new DataValidationException("Firmware content type should be specified!"); 199 throw new DataValidationException("Firmware content type should be specified!");
131 } 200 }
  201 +
  202 + if (StringUtils.isEmpty(firmware.getChecksum())) {
  203 + throw new DataValidationException("Firmware checksum should be specified!");
  204 + }
  205 +
132 ByteBuffer data = firmware.getData(); 206 ByteBuffer data = firmware.getData();
133 if (data == null || !data.hasArray() || data.array().length == 0) { 207 if (data == null || !data.hasArray() || data.array().length == 0) {
134 throw new DataValidationException("Firmware data should be specified!"); 208 throw new DataValidationException("Firmware data should be specified!");
135 } 209 }
  210 +
  211 + if (firmware.getChecksumAlgorithm() != null) {
  212 + HashFunction hashFunction;
  213 + switch (firmware.getChecksumAlgorithm()) {
  214 + case "sha256":
  215 + hashFunction = Hashing.sha256();
  216 + break;
  217 + case "md5":
  218 + hashFunction = Hashing.md5();
  219 + break;
  220 + case "crc32":
  221 + hashFunction = Hashing.crc32();
  222 + break;
  223 + default:
  224 + throw new DataValidationException("Unknown checksum algorithm!");
  225 + }
  226 +
  227 + String currentChecksum = hashFunction.hashBytes(data.array()).toString();
  228 + ;
  229 +
  230 + if (!currentChecksum.equals(firmware.getChecksum())) {
  231 + throw new DataValidationException("Wrong firmware file!");
  232 + }
  233 + }
  234 + }
  235 +
  236 + @Override
  237 + protected void validateUpdate(TenantId tenantId, Firmware firmware) {
  238 + Firmware firmwareOld = firmwareDao.findById(tenantId, firmware.getUuidId());
  239 +
  240 + if (!firmwareOld.getTitle().equals(firmware.getTitle())) {
  241 + throw new DataValidationException("Updating firmware title is prohibited!");
  242 + }
  243 +
  244 + if (!firmwareOld.getVersion().equals(firmware.getVersion())) {
  245 + throw new DataValidationException("Updating firmware version is prohibited!");
  246 + }
  247 +
  248 + if (firmwareOld.getFileName() != null && !firmwareOld.getFileName().equals(firmware.getFileName())) {
  249 + throw new DataValidationException("Updating firmware file name is prohibited!");
  250 + }
  251 +
  252 + if (firmwareOld.getContentType() != null && !firmwareOld.getContentType().equals(firmware.getContentType())) {
  253 + throw new DataValidationException("Updating firmware content type is prohibited!");
  254 + }
  255 +
  256 + if (firmwareOld.getChecksumAlgorithm() != null && !firmwareOld.getChecksumAlgorithm().equals(firmware.getChecksumAlgorithm())) {
  257 + throw new DataValidationException("Updating firmware content type is prohibited!");
  258 + }
  259 +
  260 + if (firmwareOld.getChecksum() != null && !firmwareOld.getChecksum().equals(firmware.getChecksum())) {
  261 + throw new DataValidationException("Updating firmware content type is prohibited!");
  262 + }
  263 +
  264 + if (firmwareOld.getData() != null && !firmwareOld.getData().equals(firmware.getData())) {
  265 + throw new DataValidationException("Updating firmware data is prohibited!");
  266 + }
136 } 267 }
137 }; 268 };
138 269
139 private PaginatedRemover<TenantId, FirmwareInfo> tenantFirmwareRemover = 270 private PaginatedRemover<TenantId, FirmwareInfo> tenantFirmwareRemover =
140 new PaginatedRemover<>() { 271 new PaginatedRemover<>() {
141 272
  273 +
142 @Override 274 @Override
143 protected PageData<FirmwareInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { 275 protected PageData<FirmwareInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
144 return firmwareInfoDao.findFirmwareInfoByTenantId(id, pageLink); 276 return firmwareInfoDao.findFirmwareInfoByTenantId(id, pageLink);
@@ -475,9 +475,14 @@ public class ModelConstants { @@ -475,9 +475,14 @@ public class ModelConstants {
475 public static final String FIRMWARE_TABLE_NAME = "firmware"; 475 public static final String FIRMWARE_TABLE_NAME = "firmware";
476 public static final String FIRMWARE_TENANT_ID_COLUMN = TENANT_ID_COLUMN; 476 public static final String FIRMWARE_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
477 public static final String FIRMWARE_TITLE_COLUMN = TITLE_PROPERTY; 477 public static final String FIRMWARE_TITLE_COLUMN = TITLE_PROPERTY;
  478 + public static final String FIRMWARE_VERSION_COLUMN = "version";
478 public static final String FIRMWARE_FILE_NAME_COLUMN = "file_name"; 479 public static final String FIRMWARE_FILE_NAME_COLUMN = "file_name";
479 public static final String FIRMWARE_CONTENT_TYPE_COLUMN = "content_type"; 480 public static final String FIRMWARE_CONTENT_TYPE_COLUMN = "content_type";
  481 + public static final String FIRMWARE_CHECKSUM_ALGORITHM_COLUMN = "checksum_algorithm";
  482 + public static final String FIRMWARE_CHECKSUM_COLUMN = "checksum";
480 public static final String FIRMWARE_DATA_COLUMN = "data"; 483 public static final String FIRMWARE_DATA_COLUMN = "data";
  484 + public static final String FIRMWARE_ADDITIONAL_INFO_COLUMN = ADDITIONAL_INFO_PROPERTY;
  485 +
481 486
482 /** 487 /**
483 * Cassandra attributes and timeseries constants. 488 * Cassandra attributes and timeseries constants.
@@ -15,13 +15,18 @@ @@ -15,13 +15,18 @@
15 */ 15 */
16 package org.thingsboard.server.dao.model.sql; 16 package org.thingsboard.server.dao.model.sql;
17 17
  18 +import com.fasterxml.jackson.databind.JsonNode;
18 import lombok.Data; 19 import lombok.Data;
19 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
  21 +import org.hibernate.annotations.Type;
  22 +import org.hibernate.annotations.TypeDef;
20 import org.thingsboard.server.common.data.Firmware; 23 import org.thingsboard.server.common.data.Firmware;
21 import org.thingsboard.server.common.data.id.FirmwareId; 24 import org.thingsboard.server.common.data.id.FirmwareId;
22 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.dao.model.BaseSqlEntity; 26 import org.thingsboard.server.dao.model.BaseSqlEntity;
  27 +import org.thingsboard.server.dao.model.ModelConstants;
24 import org.thingsboard.server.dao.model.SearchTextEntity; 28 import org.thingsboard.server.dao.model.SearchTextEntity;
  29 +import org.thingsboard.server.dao.util.mapping.JsonStringType;
25 30
26 import javax.persistence.Column; 31 import javax.persistence.Column;
27 import javax.persistence.Entity; 32 import javax.persistence.Entity;
@@ -29,17 +34,21 @@ import javax.persistence.Table; @@ -29,17 +34,21 @@ import javax.persistence.Table;
29 import java.nio.ByteBuffer; 34 import java.nio.ByteBuffer;
30 import java.util.UUID; 35 import java.util.UUID;
31 36
  37 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_ALGORITHM_COLUMN;
  38 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CHECKSUM_COLUMN;
32 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN; 39 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN;
33 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN; 40 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_DATA_COLUMN;
34 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN; 41 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN;
35 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME; 42 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME;
36 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN; 43 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN;
37 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN; 44 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN;
  45 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN;
38 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; 46 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
39 47
40 @Data 48 @Data
41 @EqualsAndHashCode(callSuper = true) 49 @EqualsAndHashCode(callSuper = true)
42 @Entity 50 @Entity
  51 +@TypeDef(name = "json", typeClass = JsonStringType.class)
43 @Table(name = FIRMWARE_TABLE_NAME) 52 @Table(name = FIRMWARE_TABLE_NAME)
44 public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTextEntity<Firmware> { 53 public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTextEntity<Firmware> {
45 54
@@ -49,15 +58,28 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex @@ -49,15 +58,28 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
49 @Column(name = FIRMWARE_TITLE_COLUMN) 58 @Column(name = FIRMWARE_TITLE_COLUMN)
50 private String title; 59 private String title;
51 60
  61 + @Column(name = FIRMWARE_VERSION_COLUMN)
  62 + private String version;
  63 +
52 @Column(name = FIRMWARE_FILE_NAME_COLUMN) 64 @Column(name = FIRMWARE_FILE_NAME_COLUMN)
53 private String fileName; 65 private String fileName;
54 66
55 @Column(name = FIRMWARE_CONTENT_TYPE_COLUMN) 67 @Column(name = FIRMWARE_CONTENT_TYPE_COLUMN)
56 private String contentType; 68 private String contentType;
57 69
  70 + @Column(name = FIRMWARE_CHECKSUM_ALGORITHM_COLUMN)
  71 + private String checksumAlgorithm;
  72 +
  73 + @Column(name = FIRMWARE_CHECKSUM_COLUMN)
  74 + private String checksum;
  75 +
58 @Column(name = FIRMWARE_DATA_COLUMN, columnDefinition = "BINARY") 76 @Column(name = FIRMWARE_DATA_COLUMN, columnDefinition = "BINARY")
59 private byte[] data; 77 private byte[] data;
60 78
  79 + @Type(type = "json")
  80 + @Column(name = ModelConstants.FIRMWARE_ADDITIONAL_INFO_COLUMN)
  81 + private JsonNode additionalInfo;
  82 +
61 @Column(name = SEARCH_TEXT_PROPERTY) 83 @Column(name = SEARCH_TEXT_PROPERTY)
62 private String searchText; 84 private String searchText;
63 85
@@ -70,9 +92,13 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex @@ -70,9 +92,13 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
70 this.setUuid(firmware.getUuidId()); 92 this.setUuid(firmware.getUuidId());
71 this.tenantId = firmware.getTenantId().getId(); 93 this.tenantId = firmware.getTenantId().getId();
72 this.title = firmware.getTitle(); 94 this.title = firmware.getTitle();
  95 + this.version = firmware.getVersion();
73 this.fileName = firmware.getFileName(); 96 this.fileName = firmware.getFileName();
74 this.contentType = firmware.getContentType(); 97 this.contentType = firmware.getContentType();
  98 + this.checksumAlgorithm = firmware.getChecksumAlgorithm();
  99 + this.checksum = firmware.getChecksum();
75 this.data = firmware.getData().array(); 100 this.data = firmware.getData().array();
  101 + this.additionalInfo = firmware.getAdditionalInfo();
76 } 102 }
77 103
78 @Override 104 @Override
@@ -91,9 +117,15 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex @@ -91,9 +117,15 @@ public class FirmwareEntity extends BaseSqlEntity<Firmware> implements SearchTex
91 firmware.setCreatedTime(createdTime); 117 firmware.setCreatedTime(createdTime);
92 firmware.setTenantId(new TenantId(tenantId)); 118 firmware.setTenantId(new TenantId(tenantId));
93 firmware.setTitle(title); 119 firmware.setTitle(title);
  120 + firmware.setVersion(version);
94 firmware.setFileName(fileName); 121 firmware.setFileName(fileName);
95 firmware.setContentType(contentType); 122 firmware.setContentType(contentType);
96 - firmware.setData(ByteBuffer.wrap(data)); 123 + firmware.setChecksumAlgorithm(checksumAlgorithm);
  124 + firmware.setChecksum(checksum);
  125 + if (data != null) {
  126 + firmware.setData(ByteBuffer.wrap(data));
  127 + }
  128 + firmware.setAdditionalInfo(additionalInfo);
97 return firmware; 129 return firmware;
98 } 130 }
99 } 131 }
@@ -15,29 +15,34 @@ @@ -15,29 +15,34 @@
15 */ 15 */
16 package org.thingsboard.server.dao.model.sql; 16 package org.thingsboard.server.dao.model.sql;
17 17
  18 +import com.fasterxml.jackson.databind.JsonNode;
18 import lombok.Data; 19 import lombok.Data;
19 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
  21 +import org.hibernate.annotations.Type;
  22 +import org.hibernate.annotations.TypeDef;
20 import org.thingsboard.server.common.data.FirmwareInfo; 23 import org.thingsboard.server.common.data.FirmwareInfo;
21 import org.thingsboard.server.common.data.id.FirmwareId; 24 import org.thingsboard.server.common.data.id.FirmwareId;
22 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.dao.model.BaseSqlEntity; 26 import org.thingsboard.server.dao.model.BaseSqlEntity;
  27 +import org.thingsboard.server.dao.model.ModelConstants;
24 import org.thingsboard.server.dao.model.SearchTextEntity; 28 import org.thingsboard.server.dao.model.SearchTextEntity;
  29 +import org.thingsboard.server.dao.util.mapping.JsonStringType;
25 30
26 import javax.persistence.Column; 31 import javax.persistence.Column;
27 import javax.persistence.Entity; 32 import javax.persistence.Entity;
28 import javax.persistence.Table; 33 import javax.persistence.Table;
29 import java.util.UUID; 34 import java.util.UUID;
30 35
31 -import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_CONTENT_TYPE_COLUMN;  
32 -import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_FILE_NAME_COLUMN;  
33 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME; 36 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TABLE_NAME;
34 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN; 37 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TENANT_ID_COLUMN;
35 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN; 38 import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_TITLE_COLUMN;
  39 +import static org.thingsboard.server.dao.model.ModelConstants.FIRMWARE_VERSION_COLUMN;
36 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY; 40 import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
37 41
38 @Data 42 @Data
39 @EqualsAndHashCode(callSuper = true) 43 @EqualsAndHashCode(callSuper = true)
40 @Entity 44 @Entity
  45 +@TypeDef(name = "json", typeClass = JsonStringType.class)
41 @Table(name = FIRMWARE_TABLE_NAME) 46 @Table(name = FIRMWARE_TABLE_NAME)
42 public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements SearchTextEntity<FirmwareInfo> { 47 public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements SearchTextEntity<FirmwareInfo> {
43 48
@@ -47,11 +52,12 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S @@ -47,11 +52,12 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
47 @Column(name = FIRMWARE_TITLE_COLUMN) 52 @Column(name = FIRMWARE_TITLE_COLUMN)
48 private String title; 53 private String title;
49 54
50 - @Column(name = FIRMWARE_FILE_NAME_COLUMN)  
51 - private String fileName; 55 + @Column(name = FIRMWARE_VERSION_COLUMN)
  56 + private String version;
52 57
53 - @Column(name = FIRMWARE_CONTENT_TYPE_COLUMN)  
54 - private String contentType; 58 + @Type(type = "json")
  59 + @Column(name = ModelConstants.FIRMWARE_ADDITIONAL_INFO_COLUMN)
  60 + private JsonNode additionalInfo;
55 61
56 @Column(name = SEARCH_TEXT_PROPERTY) 62 @Column(name = SEARCH_TEXT_PROPERTY)
57 private String searchText; 63 private String searchText;
@@ -65,8 +71,8 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S @@ -65,8 +71,8 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
65 this.setUuid(firmware.getUuidId()); 71 this.setUuid(firmware.getUuidId());
66 this.tenantId = firmware.getTenantId().getId(); 72 this.tenantId = firmware.getTenantId().getId();
67 this.title = firmware.getTitle(); 73 this.title = firmware.getTitle();
68 - this.fileName = firmware.getFileName();  
69 - this.contentType = firmware.getContentType(); 74 + this.version = firmware.getVersion();
  75 + this.additionalInfo = firmware.getAdditionalInfo();
70 } 76 }
71 77
72 @Override 78 @Override
@@ -85,8 +91,8 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S @@ -85,8 +91,8 @@ public class FirmwareInfoEntity extends BaseSqlEntity<FirmwareInfo> implements S
85 firmware.setCreatedTime(createdTime); 91 firmware.setCreatedTime(createdTime);
86 firmware.setTenantId(new TenantId(tenantId)); 92 firmware.setTenantId(new TenantId(tenantId));
87 firmware.setTitle(title); 93 firmware.setTitle(title);
88 - firmware.setFileName(fileName);  
89 - firmware.setContentType(contentType); 94 + firmware.setVersion(version);
  95 + firmware.setAdditionalInfo(additionalInfo);
90 return firmware; 96 return firmware;
91 } 97 }
92 } 98 }
@@ -162,10 +162,15 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -162,10 +162,15 @@ CREATE TABLE IF NOT EXISTS firmware (
162 created_time bigint NOT NULL, 162 created_time bigint NOT NULL,
163 tenant_id uuid NOT NULL, 163 tenant_id uuid NOT NULL,
164 title varchar(255) NOT NULL, 164 title varchar(255) NOT NULL,
  165 + version varchar(255) NOT NULL,
  166 + file_name varchar(255),
  167 + content_type varchar(255),
  168 + checksum_algorithm varchar(32),
  169 + checksum varchar(1020),
  170 + data binary,
  171 + additional_info varchar,
165 search_text varchar(255), 172 search_text varchar(255),
166 - file_name varchar(255) NOT NULL,  
167 - content_type varchar(255) NOT NULL,  
168 - data binary 173 + CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
169 ); 174 );
170 175
171 CREATE TABLE IF NOT EXISTS device_profile ( 176 CREATE TABLE IF NOT EXISTS device_profile (
@@ -180,10 +180,15 @@ CREATE TABLE IF NOT EXISTS firmware ( @@ -180,10 +180,15 @@ CREATE TABLE IF NOT EXISTS firmware (
180 created_time bigint NOT NULL, 180 created_time bigint NOT NULL,
181 tenant_id uuid NOT NULL, 181 tenant_id uuid NOT NULL,
182 title varchar(255) NOT NULL, 182 title varchar(255) NOT NULL,
  183 + version varchar(255) NOT NULL,
  184 + file_name varchar(255),
  185 + content_type varchar(255),
  186 + checksum_algorithm varchar(32),
  187 + checksum varchar(1020),
  188 + data bytea,
  189 + additional_info varchar,
183 search_text varchar(255), 190 search_text varchar(255),
184 - file_name varchar(255) NOT NULL,  
185 - content_type varchar(255) NOT NULL,  
186 - data bytea 191 + CONSTRAINT firmware_tenant_title_version_unq_key UNIQUE (tenant_id, title, version)
187 ); 192 );
188 193
189 CREATE TABLE IF NOT EXISTS device_profile ( 194 CREATE TABLE IF NOT EXISTS device_profile (
@@ -24,7 +24,7 @@ import java.util.Arrays; @@ -24,7 +24,7 @@ import java.util.Arrays;
24 24
25 @RunWith(ClasspathSuite.class) 25 @RunWith(ClasspathSuite.class)
26 @ClassnameFilters({ 26 @ClassnameFilters({
27 - "org.thingsboard.server.dao.service.sql.FirmwareServiceSqlTest" 27 + "org.thingsboard.server.dao.service.sql.*Test"
28 }) 28 })
29 public class SqlDaoServiceTestSuite { 29 public class SqlDaoServiceTestSuite {
30 30
@@ -27,19 +27,19 @@ import org.junit.Test; @@ -27,19 +27,19 @@ import org.junit.Test;
27 import org.thingsboard.server.common.data.Device; 27 import org.thingsboard.server.common.data.Device;
28 import org.thingsboard.server.common.data.DeviceProfile; 28 import org.thingsboard.server.common.data.DeviceProfile;
29 import org.thingsboard.server.common.data.DeviceProfileInfo; 29 import org.thingsboard.server.common.data.DeviceProfileInfo;
30 -import org.thingsboard.server.common.data.DeviceProfileType;  
31 import org.thingsboard.server.common.data.DeviceTransportType; 30 import org.thingsboard.server.common.data.DeviceTransportType;
  31 +import org.thingsboard.server.common.data.Firmware;
32 import org.thingsboard.server.common.data.Tenant; 32 import org.thingsboard.server.common.data.Tenant;
33 import org.thingsboard.server.common.data.id.TenantId; 33 import org.thingsboard.server.common.data.id.TenantId;
34 import org.thingsboard.server.common.data.page.PageData; 34 import org.thingsboard.server.common.data.page.PageData;
35 import org.thingsboard.server.common.data.page.PageLink; 35 import org.thingsboard.server.common.data.page.PageLink;
36 import org.thingsboard.server.dao.exception.DataValidationException; 36 import org.thingsboard.server.dao.exception.DataValidationException;
37 37
  38 +import java.nio.ByteBuffer;
38 import java.util.ArrayList; 39 import java.util.ArrayList;
39 import java.util.Collections; 40 import java.util.Collections;
40 import java.util.List; 41 import java.util.List;
41 import java.util.concurrent.ExecutionException; 42 import java.util.concurrent.ExecutionException;
42 -import java.util.concurrent.ExecutorService;  
43 import java.util.concurrent.Executors; 43 import java.util.concurrent.Executors;
44 import java.util.stream.Collectors; 44 import java.util.stream.Collectors;
45 45
@@ -83,17 +83,48 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -83,17 +83,48 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
83 } 83 }
84 84
85 @Test 85 @Test
  86 + public void testSaveDeviceProfileWithFirmware() {
  87 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
  88 + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
  89 + Assert.assertNotNull(savedDeviceProfile);
  90 + Assert.assertNotNull(savedDeviceProfile.getId());
  91 + Assert.assertTrue(savedDeviceProfile.getCreatedTime() > 0);
  92 + Assert.assertEquals(deviceProfile.getName(), savedDeviceProfile.getName());
  93 + Assert.assertEquals(deviceProfile.getDescription(), savedDeviceProfile.getDescription());
  94 + Assert.assertEquals(deviceProfile.getProfileData(), savedDeviceProfile.getProfileData());
  95 + Assert.assertEquals(deviceProfile.isDefault(), savedDeviceProfile.isDefault());
  96 + Assert.assertEquals(deviceProfile.getDefaultRuleChainId(), savedDeviceProfile.getDefaultRuleChainId());
  97 +
  98 + Firmware firmware = new Firmware();
  99 + firmware.setTenantId(tenantId);
  100 + firmware.setTitle("my firmware");
  101 + firmware.setVersion("v1.0");
  102 + firmware.setFileName("test.txt");
  103 + firmware.setContentType("text/plain");
  104 + firmware.setChecksumAlgorithm("sha256");
  105 + firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
  106 + firmware.setData(ByteBuffer.wrap(new byte[]{1}));
  107 + Firmware savedFirmware = firmwareService.saveFirmware(firmware);
  108 +
  109 + deviceProfile.setFirmwareId(savedFirmware.getId());
  110 +
  111 + deviceProfileService.saveDeviceProfile(savedDeviceProfile);
  112 + DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId());
  113 + Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName());
  114 + }
  115 +
  116 + @Test
86 public void testFindDeviceProfileById() { 117 public void testFindDeviceProfileById() {
87 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); 118 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
88 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 119 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
89 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId()); 120 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId());
90 Assert.assertNotNull(foundDeviceProfile); 121 Assert.assertNotNull(foundDeviceProfile);
91 Assert.assertEquals(savedDeviceProfile, foundDeviceProfile); 122 Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
92 - } 123 + }
93 124
94 @Test 125 @Test
95 public void testFindDeviceProfileInfoById() { 126 public void testFindDeviceProfileInfoById() {
96 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); 127 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
97 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 128 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
98 DeviceProfileInfo foundDeviceProfileInfo = deviceProfileService.findDeviceProfileInfoById(tenantId, savedDeviceProfile.getId()); 129 DeviceProfileInfo foundDeviceProfileInfo = deviceProfileService.findDeviceProfileInfoById(tenantId, savedDeviceProfile.getId());
99 Assert.assertNotNull(foundDeviceProfileInfo); 130 Assert.assertNotNull(foundDeviceProfileInfo);
@@ -124,7 +155,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -124,7 +155,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
124 ListeningExecutorService testExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(100)); 155 ListeningExecutorService testExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(100));
125 try { 156 try {
126 List<ListenableFuture<DeviceProfile>> futures = new ArrayList<>(); 157 List<ListenableFuture<DeviceProfile>> futures = new ArrayList<>();
127 - for (int i = 0; i < 50; i ++) { 158 + for (int i = 0; i < 50; i++) {
128 futures.add(testExecutor.submit(() -> deviceProfileService.findOrCreateDeviceProfile(tenantId, "Device Profile 1"))); 159 futures.add(testExecutor.submit(() -> deviceProfileService.findOrCreateDeviceProfile(tenantId, "Device Profile 1")));
129 futures.add(testExecutor.submit(() -> deviceProfileService.findOrCreateDeviceProfile(tenantId, "Device Profile 2"))); 160 futures.add(testExecutor.submit(() -> deviceProfileService.findOrCreateDeviceProfile(tenantId, "Device Profile 2")));
130 } 161 }
@@ -138,8 +169,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -138,8 +169,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
138 169
139 @Test 170 @Test
140 public void testSetDefaultDeviceProfile() { 171 public void testSetDefaultDeviceProfile() {
141 - DeviceProfile deviceProfile1 = this.createDeviceProfile(tenantId,"Device Profile 1");  
142 - DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile 2"); 172 + DeviceProfile deviceProfile1 = this.createDeviceProfile(tenantId, "Device Profile 1");
  173 + DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId, "Device Profile 2");
143 174
144 DeviceProfile savedDeviceProfile1 = deviceProfileService.saveDeviceProfile(deviceProfile1); 175 DeviceProfile savedDeviceProfile1 = deviceProfileService.saveDeviceProfile(deviceProfile1);
145 DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2); 176 DeviceProfile savedDeviceProfile2 = deviceProfileService.saveDeviceProfile(deviceProfile2);
@@ -165,16 +196,16 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -165,16 +196,16 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
165 196
166 @Test(expected = DataValidationException.class) 197 @Test(expected = DataValidationException.class)
167 public void testSaveDeviceProfileWithSameName() { 198 public void testSaveDeviceProfileWithSameName() {
168 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); 199 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
169 deviceProfileService.saveDeviceProfile(deviceProfile); 200 deviceProfileService.saveDeviceProfile(deviceProfile);
170 - DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId,"Device Profile"); 201 + DeviceProfile deviceProfile2 = this.createDeviceProfile(tenantId, "Device Profile");
171 deviceProfileService.saveDeviceProfile(deviceProfile2); 202 deviceProfileService.saveDeviceProfile(deviceProfile2);
172 } 203 }
173 204
174 @Ignore 205 @Ignore
175 @Test(expected = DataValidationException.class) 206 @Test(expected = DataValidationException.class)
176 public void testChangeDeviceProfileTypeWithExistingDevices() { 207 public void testChangeDeviceProfileTypeWithExistingDevices() {
177 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); 208 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
178 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 209 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
179 Device device = new Device(); 210 Device device = new Device();
180 device.setTenantId(tenantId); 211 device.setTenantId(tenantId);
@@ -189,7 +220,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -189,7 +220,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
189 220
190 @Test(expected = DataValidationException.class) 221 @Test(expected = DataValidationException.class)
191 public void testChangeDeviceProfileTransportTypeWithExistingDevices() { 222 public void testChangeDeviceProfileTransportTypeWithExistingDevices() {
192 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); 223 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
193 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 224 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
194 Device device = new Device(); 225 Device device = new Device();
195 device.setTenantId(tenantId); 226 device.setTenantId(tenantId);
@@ -203,7 +234,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -203,7 +234,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
203 234
204 @Test(expected = DataValidationException.class) 235 @Test(expected = DataValidationException.class)
205 public void testDeleteDeviceProfileWithExistingDevice() { 236 public void testDeleteDeviceProfileWithExistingDevice() {
206 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); 237 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
207 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 238 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
208 Device device = new Device(); 239 Device device = new Device();
209 device.setTenantId(tenantId); 240 device.setTenantId(tenantId);
@@ -216,7 +247,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -216,7 +247,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
216 247
217 @Test 248 @Test
218 public void testDeleteDeviceProfile() { 249 public void testDeleteDeviceProfile() {
219 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"); 250 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile");
220 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); 251 DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile);
221 deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); 252 deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
222 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId()); 253 DeviceProfile foundDeviceProfile = deviceProfileService.findDeviceProfileById(tenantId, savedDeviceProfile.getId());
@@ -233,8 +264,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -233,8 +264,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
233 Assert.assertEquals(1, pageData.getTotalElements()); 264 Assert.assertEquals(1, pageData.getTotalElements());
234 deviceProfiles.addAll(pageData.getData()); 265 deviceProfiles.addAll(pageData.getData());
235 266
236 - for (int i=0;i<28;i++) {  
237 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"+i); 267 + for (int i = 0; i < 28; i++) {
  268 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile" + i);
238 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile)); 269 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile));
239 } 270 }
240 271
@@ -275,8 +306,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -275,8 +306,8 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
275 Assert.assertEquals(1, deviceProfilePageData.getTotalElements()); 306 Assert.assertEquals(1, deviceProfilePageData.getTotalElements());
276 deviceProfiles.addAll(deviceProfilePageData.getData()); 307 deviceProfiles.addAll(deviceProfilePageData.getData());
277 308
278 - for (int i=0;i<28;i++) {  
279 - DeviceProfile deviceProfile = this.createDeviceProfile(tenantId,"Device Profile"+i); 309 + for (int i = 0; i < 28; i++) {
  310 + DeviceProfile deviceProfile = this.createDeviceProfile(tenantId, "Device Profile" + i);
280 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile)); 311 deviceProfiles.add(deviceProfileService.saveDeviceProfile(deviceProfile));
281 } 312 }
282 313
@@ -297,7 +328,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -297,7 +328,7 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
297 328
298 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream() 329 List<DeviceProfileInfo> deviceProfileInfos = deviceProfiles.stream()
299 .map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(), 330 .map(deviceProfile -> new DeviceProfileInfo(deviceProfile.getId(),
300 - deviceProfile.getName(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList()); 331 + deviceProfile.getName(), deviceProfile.getType(), deviceProfile.getTransportType())).collect(Collectors.toList());
301 332
302 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos); 333 Assert.assertEquals(deviceProfileInfos, loadedDeviceProfileInfos);
303 334
@@ -312,4 +343,5 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest { @@ -312,4 +343,5 @@ public class BaseDeviceProfileServiceTest extends AbstractServiceTest {
312 Assert.assertFalse(pageData.hasNext()); 343 Assert.assertFalse(pageData.hasNext());
313 Assert.assertEquals(1, pageData.getTotalElements()); 344 Assert.assertEquals(1, pageData.getTotalElements());
314 } 345 }
  346 +
315 } 347 }
@@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; @@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
30 import org.thingsboard.server.common.data.security.DeviceCredentialsType; 30 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
31 import org.thingsboard.server.dao.exception.DataValidationException; 31 import org.thingsboard.server.dao.exception.DataValidationException;
32 32
  33 +import java.nio.ByteBuffer;
33 import java.util.ArrayList; 34 import java.util.ArrayList;
34 import java.util.Collections; 35 import java.util.Collections;
35 import java.util.List; 36 import java.util.List;
@@ -88,6 +89,49 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest { @@ -88,6 +89,49 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
88 89
89 deviceService.deleteDevice(tenantId, savedDevice.getId()); 90 deviceService.deleteDevice(tenantId, savedDevice.getId());
90 } 91 }
  92 +
  93 + @Test
  94 + public void testSaveDeviceWithFirmware() {
  95 + Device device = new Device();
  96 + device.setTenantId(tenantId);
  97 + device.setName("My device");
  98 + device.setType("default");
  99 + Device savedDevice = deviceService.saveDevice(device);
  100 +
  101 + Assert.assertNotNull(savedDevice);
  102 + Assert.assertNotNull(savedDevice.getId());
  103 + Assert.assertTrue(savedDevice.getCreatedTime() > 0);
  104 + Assert.assertEquals(device.getTenantId(), savedDevice.getTenantId());
  105 + Assert.assertNotNull(savedDevice.getCustomerId());
  106 + Assert.assertEquals(NULL_UUID, savedDevice.getCustomerId().getId());
  107 + Assert.assertEquals(device.getName(), savedDevice.getName());
  108 +
  109 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, savedDevice.getId());
  110 + Assert.assertNotNull(deviceCredentials);
  111 + Assert.assertNotNull(deviceCredentials.getId());
  112 + Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
  113 + Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, deviceCredentials.getCredentialsType());
  114 + Assert.assertNotNull(deviceCredentials.getCredentialsId());
  115 + Assert.assertEquals(20, deviceCredentials.getCredentialsId().length());
  116 +
  117 +
  118 + Firmware firmware = new Firmware();
  119 + firmware.setTenantId(tenantId);
  120 + firmware.setTitle("my firmware");
  121 + firmware.setVersion("v1.0");
  122 + firmware.setFileName("test.txt");
  123 + firmware.setContentType("text/plain");
  124 + firmware.setChecksumAlgorithm("sha256");
  125 + firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
  126 + firmware.setData(ByteBuffer.wrap(new byte[]{1}));
  127 + Firmware savedFirmware = firmwareService.saveFirmware(firmware);
  128 +
  129 + savedDevice.setFirmwareId(savedFirmware.getId());
  130 +
  131 + deviceService.saveDevice(savedDevice);
  132 + Device foundDevice = deviceService.findDeviceById(tenantId, savedDevice.getId());
  133 + Assert.assertEquals(foundDevice.getName(), savedDevice.getName());
  134 + }
91 135
92 @Test(expected = DataValidationException.class) 136 @Test(expected = DataValidationException.class)
93 public void testSaveDeviceWithEmptyName() { 137 public void testSaveDeviceWithEmptyName() {
@@ -20,6 +20,7 @@ import org.junit.After; @@ -20,6 +20,7 @@ import org.junit.After;
20 import org.junit.Assert; 20 import org.junit.Assert;
21 import org.junit.Before; 21 import org.junit.Before;
22 import org.junit.Test; 22 import org.junit.Test;
  23 +import org.thingsboard.common.util.JacksonUtil;
23 import org.thingsboard.server.common.data.Device; 24 import org.thingsboard.server.common.data.Device;
24 import org.thingsboard.server.common.data.DeviceProfile; 25 import org.thingsboard.server.common.data.DeviceProfile;
25 import org.thingsboard.server.common.data.Firmware; 26 import org.thingsboard.server.common.data.Firmware;
@@ -39,8 +40,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -39,8 +40,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
39 40
40 public static final String TITLE = "My firmware"; 41 public static final String TITLE = "My firmware";
41 private static final String FILE_NAME = "filename.txt"; 42 private static final String FILE_NAME = "filename.txt";
  43 + private static final String VERSION = "v1.0";
42 private static final String CONTENT_TYPE = "text/plain"; 44 private static final String CONTENT_TYPE = "text/plain";
43 - private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[]{0}); 45 + private static final String CHECKSUM_ALGORITHM = "sha256";
  46 + private static final String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a";
  47 + private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[]{1});
44 48
45 private IdComparator<FirmwareInfo> idComparator = new IdComparator<>(); 49 private IdComparator<FirmwareInfo> idComparator = new IdComparator<>();
46 50
@@ -65,8 +69,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -65,8 +69,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
65 Firmware firmware = new Firmware(); 69 Firmware firmware = new Firmware();
66 firmware.setTenantId(tenantId); 70 firmware.setTenantId(tenantId);
67 firmware.setTitle(TITLE); 71 firmware.setTitle(TITLE);
  72 + firmware.setVersion(VERSION);
68 firmware.setFileName(FILE_NAME); 73 firmware.setFileName(FILE_NAME);
69 firmware.setContentType(CONTENT_TYPE); 74 firmware.setContentType(CONTENT_TYPE);
  75 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  76 + firmware.setChecksum(CHECKSUM);
70 firmware.setData(DATA); 77 firmware.setData(DATA);
71 Firmware savedFirmware = firmwareService.saveFirmware(firmware); 78 Firmware savedFirmware = firmwareService.saveFirmware(firmware);
72 79
@@ -79,7 +86,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -79,7 +86,7 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
79 Assert.assertEquals(firmware.getContentType(), savedFirmware.getContentType()); 86 Assert.assertEquals(firmware.getContentType(), savedFirmware.getContentType());
80 Assert.assertEquals(firmware.getData(), savedFirmware.getData()); 87 Assert.assertEquals(firmware.getData(), savedFirmware.getData());
81 88
82 - savedFirmware.setTitle("My new firmware"); 89 + savedFirmware.setAdditionalInfo(JacksonUtil.newObjectNode());
83 firmwareService.saveFirmware(savedFirmware); 90 firmwareService.saveFirmware(savedFirmware);
84 91
85 Firmware foundFirmware = firmwareService.findFirmwareById(tenantId, savedFirmware.getId()); 92 Firmware foundFirmware = firmwareService.findFirmwareById(tenantId, savedFirmware.getId());
@@ -88,12 +95,52 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -88,12 +95,52 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
88 firmwareService.deleteFirmware(tenantId, savedFirmware.getId()); 95 firmwareService.deleteFirmware(tenantId, savedFirmware.getId());
89 } 96 }
90 97
  98 + @Test
  99 + public void testSaveFirmwareInfoAndUpdateWithData() {
  100 + FirmwareInfo firmwareInfo = new FirmwareInfo();
  101 + firmwareInfo.setTenantId(tenantId);
  102 + firmwareInfo.setTitle(TITLE);
  103 + firmwareInfo.setVersion(VERSION);
  104 + FirmwareInfo savedFirmwareInfo = firmwareService.saveFirmwareInfo(firmwareInfo);
  105 +
  106 + Assert.assertNotNull(savedFirmwareInfo);
  107 + Assert.assertNotNull(savedFirmwareInfo.getId());
  108 + Assert.assertTrue(savedFirmwareInfo.getCreatedTime() > 0);
  109 + Assert.assertEquals(firmwareInfo.getTenantId(), savedFirmwareInfo.getTenantId());
  110 + Assert.assertEquals(firmwareInfo.getTitle(), savedFirmwareInfo.getTitle());
  111 +
  112 + Firmware firmware = new Firmware(savedFirmwareInfo.getId());
  113 + firmware.setCreatedTime(firmwareInfo.getCreatedTime());
  114 + firmware.setTenantId(tenantId);
  115 + firmware.setTitle(TITLE);
  116 + firmware.setVersion(VERSION);
  117 + firmware.setFileName(FILE_NAME);
  118 + firmware.setContentType(CONTENT_TYPE);
  119 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  120 + firmware.setChecksum(CHECKSUM);
  121 + firmware.setData(DATA);
  122 +
  123 + firmwareService.saveFirmware(firmware);
  124 +
  125 + savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode());
  126 + firmwareService.saveFirmwareInfo(savedFirmwareInfo);
  127 +
  128 + Firmware foundFirmware = firmwareService.findFirmwareById(tenantId, firmware.getId());
  129 + firmware.setAdditionalInfo(JacksonUtil.newObjectNode());
  130 + Assert.assertEquals(foundFirmware.getTitle(), firmware.getTitle());
  131 +
  132 + firmwareService.deleteFirmware(tenantId, savedFirmwareInfo.getId());
  133 + }
  134 +
91 @Test(expected = DataValidationException.class) 135 @Test(expected = DataValidationException.class)
92 public void testSaveFirmwareWithEmptyTenant() { 136 public void testSaveFirmwareWithEmptyTenant() {
93 Firmware firmware = new Firmware(); 137 Firmware firmware = new Firmware();
94 firmware.setTitle(TITLE); 138 firmware.setTitle(TITLE);
  139 + firmware.setVersion(VERSION);
95 firmware.setFileName(FILE_NAME); 140 firmware.setFileName(FILE_NAME);
96 firmware.setContentType(CONTENT_TYPE); 141 firmware.setContentType(CONTENT_TYPE);
  142 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  143 + firmware.setChecksum(CHECKSUM);
97 firmware.setData(DATA); 144 firmware.setData(DATA);
98 firmwareService.saveFirmware(firmware); 145 firmwareService.saveFirmware(firmware);
99 } 146 }
@@ -102,8 +149,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -102,8 +149,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
102 public void testSaveFirmwareWithEmptyTitle() { 149 public void testSaveFirmwareWithEmptyTitle() {
103 Firmware firmware = new Firmware(); 150 Firmware firmware = new Firmware();
104 firmware.setTenantId(tenantId); 151 firmware.setTenantId(tenantId);
  152 + firmware.setVersion(VERSION);
105 firmware.setFileName(FILE_NAME); 153 firmware.setFileName(FILE_NAME);
106 firmware.setContentType(CONTENT_TYPE); 154 firmware.setContentType(CONTENT_TYPE);
  155 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  156 + firmware.setChecksum(CHECKSUM);
107 firmware.setData(DATA); 157 firmware.setData(DATA);
108 firmwareService.saveFirmware(firmware); 158 firmwareService.saveFirmware(firmware);
109 } 159 }
@@ -113,7 +163,10 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -113,7 +163,10 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
113 Firmware firmware = new Firmware(); 163 Firmware firmware = new Firmware();
114 firmware.setTenantId(tenantId); 164 firmware.setTenantId(tenantId);
115 firmware.setTitle(TITLE); 165 firmware.setTitle(TITLE);
  166 + firmware.setVersion(VERSION);
116 firmware.setContentType(CONTENT_TYPE); 167 firmware.setContentType(CONTENT_TYPE);
  168 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  169 + firmware.setChecksum(CHECKSUM);
117 firmware.setData(DATA); 170 firmware.setData(DATA);
118 firmwareService.saveFirmware(firmware); 171 firmwareService.saveFirmware(firmware);
119 } 172 }
@@ -123,7 +176,10 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -123,7 +176,10 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
123 Firmware firmware = new Firmware(); 176 Firmware firmware = new Firmware();
124 firmware.setTenantId(tenantId); 177 firmware.setTenantId(tenantId);
125 firmware.setTitle(TITLE); 178 firmware.setTitle(TITLE);
  179 + firmware.setVersion(VERSION);
126 firmware.setFileName(FILE_NAME); 180 firmware.setFileName(FILE_NAME);
  181 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  182 + firmware.setChecksum(CHECKSUM);
127 firmware.setData(DATA); 183 firmware.setData(DATA);
128 firmwareService.saveFirmware(firmware); 184 firmwareService.saveFirmware(firmware);
129 } 185 }
@@ -133,8 +189,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -133,8 +189,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
133 Firmware firmware = new Firmware(); 189 Firmware firmware = new Firmware();
134 firmware.setTenantId(tenantId); 190 firmware.setTenantId(tenantId);
135 firmware.setTitle(TITLE); 191 firmware.setTitle(TITLE);
  192 + firmware.setVersion(VERSION);
136 firmware.setFileName(FILE_NAME); 193 firmware.setFileName(FILE_NAME);
137 firmware.setContentType(CONTENT_TYPE); 194 firmware.setContentType(CONTENT_TYPE);
  195 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  196 + firmware.setChecksum(CHECKSUM);
138 firmwareService.saveFirmware(firmware); 197 firmwareService.saveFirmware(firmware);
139 } 198 }
140 199
@@ -143,21 +202,76 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -143,21 +202,76 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
143 Firmware firmware = new Firmware(); 202 Firmware firmware = new Firmware();
144 firmware.setTenantId(new TenantId(Uuids.timeBased())); 203 firmware.setTenantId(new TenantId(Uuids.timeBased()));
145 firmware.setTitle(TITLE); 204 firmware.setTitle(TITLE);
  205 + firmware.setVersion(VERSION);
146 firmware.setFileName(FILE_NAME); 206 firmware.setFileName(FILE_NAME);
147 firmware.setContentType(CONTENT_TYPE); 207 firmware.setContentType(CONTENT_TYPE);
  208 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  209 + firmware.setChecksum(CHECKSUM);
148 firmware.setData(DATA); 210 firmware.setData(DATA);
149 firmwareService.saveFirmware(firmware); 211 firmwareService.saveFirmware(firmware);
150 } 212 }
151 213
  214 + @Test(expected = DataValidationException.class)
  215 + public void testSaveFirmwareWithEmptyChecksum() {
  216 + Firmware firmware = new Firmware();
  217 + firmware.setTenantId(new TenantId(Uuids.timeBased()));
  218 + firmware.setTitle(TITLE);
  219 + firmware.setVersion(VERSION);
  220 + firmware.setFileName(FILE_NAME);
  221 + firmware.setContentType(CONTENT_TYPE);
  222 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  223 + firmware.setData(DATA);
  224 + firmwareService.saveFirmware(firmware);
  225 + }
152 226
  227 + @Test(expected = DataValidationException.class)
  228 + public void testSaveFirmwareInfoWithExistingTitleAndVersion() {
  229 + FirmwareInfo firmwareInfo = new FirmwareInfo();
  230 + firmwareInfo.setTenantId(tenantId);
  231 + firmwareInfo.setTitle(TITLE);
  232 + firmwareInfo.setVersion(VERSION);
  233 + firmwareService.saveFirmwareInfo(firmwareInfo);
  234 +
  235 + FirmwareInfo newFirmwareInfo = new FirmwareInfo();
  236 + newFirmwareInfo.setTenantId(tenantId);
  237 + newFirmwareInfo.setTitle(TITLE);
  238 + newFirmwareInfo.setVersion(VERSION);
  239 + firmwareService.saveFirmwareInfo(newFirmwareInfo);
  240 + }
  241 +
  242 + @Test(expected = DataValidationException.class)
  243 + public void testSaveFirmwareWithExistingTitleAndVersion() {
  244 + Firmware firmware = new Firmware();
  245 + firmware.setTenantId(tenantId);
  246 + firmware.setTitle(TITLE);
  247 + firmware.setVersion(VERSION);
  248 + firmware.setFileName(FILE_NAME);
  249 + firmware.setContentType(CONTENT_TYPE);
  250 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  251 + firmware.setChecksum(CHECKSUM);
  252 + firmware.setData(DATA);
  253 + firmwareService.saveFirmware(firmware);
  254 +
  255 + Firmware newFirmware = new Firmware();
  256 + newFirmware.setTenantId(tenantId);
  257 + newFirmware.setTitle(TITLE);
  258 + newFirmware.setVersion(VERSION);
  259 + newFirmware.setFileName(FILE_NAME);
  260 + newFirmware.setContentType(CONTENT_TYPE);
  261 + newFirmware.setData(DATA);
  262 + firmwareService.saveFirmware(newFirmware);
  263 + }
153 264
154 @Test(expected = DataValidationException.class) 265 @Test(expected = DataValidationException.class)
155 public void testDeleteFirmwareWithReferenceByDevice() { 266 public void testDeleteFirmwareWithReferenceByDevice() {
156 Firmware firmware = new Firmware(); 267 Firmware firmware = new Firmware();
157 firmware.setTenantId(tenantId); 268 firmware.setTenantId(tenantId);
158 firmware.setTitle(TITLE); 269 firmware.setTitle(TITLE);
  270 + firmware.setVersion(VERSION);
159 firmware.setFileName(FILE_NAME); 271 firmware.setFileName(FILE_NAME);
160 firmware.setContentType(CONTENT_TYPE); 272 firmware.setContentType(CONTENT_TYPE);
  273 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  274 + firmware.setChecksum(CHECKSUM);
161 firmware.setData(DATA); 275 firmware.setData(DATA);
162 Firmware savedFirmware = firmwareService.saveFirmware(firmware); 276 Firmware savedFirmware = firmwareService.saveFirmware(firmware);
163 277
@@ -181,8 +295,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -181,8 +295,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
181 Firmware firmware = new Firmware(); 295 Firmware firmware = new Firmware();
182 firmware.setTenantId(tenantId); 296 firmware.setTenantId(tenantId);
183 firmware.setTitle(TITLE); 297 firmware.setTitle(TITLE);
  298 + firmware.setVersion(VERSION);
184 firmware.setFileName(FILE_NAME); 299 firmware.setFileName(FILE_NAME);
185 firmware.setContentType(CONTENT_TYPE); 300 firmware.setContentType(CONTENT_TYPE);
  301 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  302 + firmware.setChecksum(CHECKSUM);
186 firmware.setData(DATA); 303 firmware.setData(DATA);
187 Firmware savedFirmware = firmwareService.saveFirmware(firmware); 304 Firmware savedFirmware = firmwareService.saveFirmware(firmware);
188 305
@@ -203,8 +320,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -203,8 +320,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
203 Firmware firmware = new Firmware(); 320 Firmware firmware = new Firmware();
204 firmware.setTenantId(tenantId); 321 firmware.setTenantId(tenantId);
205 firmware.setTitle(TITLE); 322 firmware.setTitle(TITLE);
  323 + firmware.setVersion(VERSION);
206 firmware.setFileName(FILE_NAME); 324 firmware.setFileName(FILE_NAME);
207 firmware.setContentType(CONTENT_TYPE); 325 firmware.setContentType(CONTENT_TYPE);
  326 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  327 + firmware.setChecksum(CHECKSUM);
208 firmware.setData(DATA); 328 firmware.setData(DATA);
209 Firmware savedFirmware = firmwareService.saveFirmware(firmware); 329 Firmware savedFirmware = firmwareService.saveFirmware(firmware);
210 330
@@ -219,8 +339,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -219,8 +339,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
219 Firmware firmware = new Firmware(); 339 Firmware firmware = new Firmware();
220 firmware.setTenantId(tenantId); 340 firmware.setTenantId(tenantId);
221 firmware.setTitle(TITLE); 341 firmware.setTitle(TITLE);
  342 + firmware.setVersion(VERSION);
222 firmware.setFileName(FILE_NAME); 343 firmware.setFileName(FILE_NAME);
223 firmware.setContentType(CONTENT_TYPE); 344 firmware.setContentType(CONTENT_TYPE);
  345 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  346 + firmware.setChecksum(CHECKSUM);
224 firmware.setData(DATA); 347 firmware.setData(DATA);
225 Firmware savedFirmware = firmwareService.saveFirmware(firmware); 348 Firmware savedFirmware = firmwareService.saveFirmware(firmware);
226 349
@@ -238,8 +361,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest { @@ -238,8 +361,11 @@ public abstract class BaseFirmwareServiceTest extends AbstractServiceTest {
238 Firmware firmware = new Firmware(); 361 Firmware firmware = new Firmware();
239 firmware.setTenantId(tenantId); 362 firmware.setTenantId(tenantId);
240 firmware.setTitle(TITLE); 363 firmware.setTitle(TITLE);
  364 + firmware.setVersion(VERSION + i);
241 firmware.setFileName(FILE_NAME); 365 firmware.setFileName(FILE_NAME);
242 firmware.setContentType(CONTENT_TYPE); 366 firmware.setContentType(CONTENT_TYPE);
  367 + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
  368 + firmware.setChecksum(CHECKSUM);
243 firmware.setData(DATA); 369 firmware.setData(DATA);
244 firmwares.add(new FirmwareInfo(firmwareService.saveFirmware(firmware))); 370 firmwares.add(new FirmwareInfo(firmwareService.saveFirmware(firmware)));
245 } 371 }