Commit d6f451ccca90ce6cd7c56d46f3b75ab804680b5e

Authored by YevhenBondarenko
1 parent 81b203ef

created FirmwareStateService

@@ -119,6 +119,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; @@ -119,6 +119,7 @@ import org.thingsboard.server.queue.discovery.PartitionService;
119 import org.thingsboard.server.queue.provider.TbQueueProducerProvider; 119 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
120 import org.thingsboard.server.queue.util.TbCoreComponent; 120 import org.thingsboard.server.queue.util.TbCoreComponent;
121 import org.thingsboard.server.service.component.ComponentDiscoveryService; 121 import org.thingsboard.server.service.component.ComponentDiscoveryService;
  122 +import org.thingsboard.server.service.firmware.FirmwareStateService;
122 import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository; 123 import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository;
123 import org.thingsboard.server.service.profile.TbDeviceProfileCache; 124 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
124 import org.thingsboard.server.service.queue.TbClusterService; 125 import org.thingsboard.server.service.queue.TbClusterService;
@@ -241,6 +242,9 @@ public abstract class BaseController { @@ -241,6 +242,9 @@ public abstract class BaseController {
241 protected FirmwareService firmwareService; 242 protected FirmwareService firmwareService;
242 243
243 @Autowired 244 @Autowired
  245 + protected FirmwareStateService firmwareStateService;
  246 +
  247 + @Autowired
244 protected TbQueueProducerProvider producerProvider; 248 protected TbQueueProducerProvider producerProvider;
245 249
246 @Autowired 250 @Autowired
@@ -70,6 +70,7 @@ import javax.annotation.Nullable; @@ -70,6 +70,7 @@ import javax.annotation.Nullable;
70 import java.io.IOException; 70 import java.io.IOException;
71 import java.util.ArrayList; 71 import java.util.ArrayList;
72 import java.util.List; 72 import java.util.List;
  73 +import java.util.Objects;
73 import java.util.stream.Collectors; 74 import java.util.stream.Collectors;
74 75
75 @RestController 76 @RestController
@@ -117,13 +118,25 @@ public class DeviceController extends BaseController { @@ -117,13 +118,25 @@ public class DeviceController extends BaseController {
117 118
118 checkEntity(device.getId(), device, Resource.DEVICE); 119 checkEntity(device.getId(), device, Resource.DEVICE);
119 120
  121 + boolean created = device.getId() == null;
  122 +
  123 + boolean isFirmwareChanged = false;
  124 +
  125 + if (created) {
  126 + isFirmwareChanged = true;
  127 + } else {
  128 + Device oldDevice = deviceService.findDeviceById(getTenantId(), device.getId());
  129 + if (!Objects.equals(device.getFirmwareId(), oldDevice.getFirmwareId()) || !oldDevice.getDeviceProfileId().equals(device.getDeviceProfileId())) {
  130 + isFirmwareChanged = true;
  131 + }
  132 + }
  133 +
120 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); 134 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
121 135
122 tbClusterService.onDeviceChange(savedDevice, null); 136 tbClusterService.onDeviceChange(savedDevice, null);
123 tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(), 137 tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),
124 savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null); 138 savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null);
125 - tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(),  
126 - device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 139 + tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
127 140
128 logEntityAction(savedDevice.getId(), savedDevice, 141 logEntityAction(savedDevice.getId(), savedDevice,
129 savedDevice.getCustomerId(), 142 savedDevice.getCustomerId(),
@@ -134,12 +147,19 @@ public class DeviceController extends BaseController { @@ -134,12 +147,19 @@ public class DeviceController extends BaseController {
134 } else { 147 } else {
135 deviceStateService.onDeviceUpdated(savedDevice); 148 deviceStateService.onDeviceUpdated(savedDevice);
136 } 149 }
  150 +
  151 + if (isFirmwareChanged) {
  152 + firmwareStateService.update(savedDevice, created);
  153 + }
  154 +
137 return savedDevice; 155 return savedDevice;
138 - } catch (Exception e) { 156 + } catch (
  157 + Exception e) {
139 logEntityAction(emptyId(EntityType.DEVICE), device, 158 logEntityAction(emptyId(EntityType.DEVICE), device,
140 null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); 159 null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
141 throw handleException(e); 160 throw handleException(e);
142 } 161 }
  162 +
143 } 163 }
144 164
145 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 165 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@@ -43,6 +43,7 @@ import org.thingsboard.server.service.security.permission.Operation; @@ -43,6 +43,7 @@ import org.thingsboard.server.service.security.permission.Operation;
43 import org.thingsboard.server.service.security.permission.Resource; 43 import org.thingsboard.server.service.security.permission.Resource;
44 44
45 import java.util.List; 45 import java.util.List;
  46 +import java.util.Objects;
46 import java.util.UUID; 47 import java.util.UUID;
47 48
48 @RestController 49 @RestController
@@ -143,6 +144,15 @@ public class DeviceProfileController extends BaseController { @@ -143,6 +144,15 @@ public class DeviceProfileController extends BaseController {
143 144
144 checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE); 145 checkEntity(deviceProfile.getId(), deviceProfile, Resource.DEVICE_PROFILE);
145 146
  147 + boolean isFirmwareChanged = false;
  148 +
  149 + if (!created) {
  150 + DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(getTenantId(), deviceProfile.getId());
  151 + if (!Objects.equals(deviceProfile.getFirmwareId(), oldDeviceProfile.getFirmwareId())) {
  152 + isFirmwareChanged = true;
  153 + }
  154 + }
  155 +
146 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile)); 156 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
147 157
148 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null); 158 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
@@ -153,6 +163,10 @@ public class DeviceProfileController extends BaseController { @@ -153,6 +163,10 @@ public class DeviceProfileController extends BaseController {
153 null, 163 null,
154 created ? ActionType.ADDED : ActionType.UPDATED, null); 164 created ? ActionType.ADDED : ActionType.UPDATED, null);
155 165
  166 + if (isFirmwareChanged) {
  167 + firmwareStateService.update(savedDeviceProfile);
  168 + }
  169 +
156 return savedDeviceProfile; 170 return savedDeviceProfile;
157 } catch (Exception e) { 171 } catch (Exception e) {
158 logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile, 172 logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile,
@@ -15,7 +15,9 @@ @@ -15,7 +15,9 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
  18 +import com.google.common.hash.Hashing;
18 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.apache.commons.lang3.StringUtils;
19 import org.springframework.core.io.ByteArrayResource; 21 import org.springframework.core.io.ByteArrayResource;
20 import org.springframework.http.HttpHeaders; 22 import org.springframework.http.HttpHeaders;
21 import org.springframework.http.ResponseEntity; 23 import org.springframework.http.ResponseEntity;
@@ -127,6 +129,11 @@ public class FirmwareController extends BaseController { @@ -127,6 +129,11 @@ public class FirmwareController extends BaseController {
127 firmware.setVersion(info.getVersion()); 129 firmware.setVersion(info.getVersion());
128 firmware.setAdditionalInfo(info.getAdditionalInfo()); 130 firmware.setAdditionalInfo(info.getAdditionalInfo());
129 131
  132 + if (StringUtils.isEmpty(checksumAlgorithm)) {
  133 + checksumAlgorithm = "sha256";
  134 + checksum = Hashing.sha256().hashBytes(file.getBytes()).toString();
  135 + }
  136 +
130 firmware.setChecksumAlgorithm(checksumAlgorithm); 137 firmware.setChecksumAlgorithm(checksumAlgorithm);
131 firmware.setChecksum(checksum); 138 firmware.setChecksum(checksum);
132 firmware.setFileName(file.getOriginalFilename()); 139 firmware.setFileName(file.getOriginalFilename());
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.firmware;
  17 +
  18 +import com.google.common.util.concurrent.FutureCallback;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.stereotype.Service;
  21 +import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
  22 +import org.thingsboard.server.common.data.DataConstants;
  23 +import org.thingsboard.server.common.data.Device;
  24 +import org.thingsboard.server.common.data.DeviceProfile;
  25 +import org.thingsboard.server.common.data.Firmware;
  26 +import org.thingsboard.server.common.data.id.DeviceId;
  27 +import org.thingsboard.server.common.data.id.FirmwareId;
  28 +import org.thingsboard.server.common.data.id.TenantId;
  29 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  30 +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
  31 +import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
  32 +import org.thingsboard.server.common.data.kv.LongDataEntry;
  33 +import org.thingsboard.server.common.data.kv.StringDataEntry;
  34 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  35 +import org.thingsboard.server.common.data.page.PageData;
  36 +import org.thingsboard.server.common.data.page.PageLink;
  37 +import org.thingsboard.server.dao.device.DeviceProfileService;
  38 +import org.thingsboard.server.dao.device.DeviceService;
  39 +import org.thingsboard.server.dao.firmware.FirmwareService;
  40 +import org.thingsboard.server.queue.util.TbCoreComponent;
  41 +
  42 +import javax.annotation.Nullable;
  43 +import java.util.ArrayList;
  44 +import java.util.Arrays;
  45 +import java.util.List;
  46 +import java.util.function.Consumer;
  47 +
  48 +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM;
  49 +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM_ALGORITHM;
  50 +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_SIZE;
  51 +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_TITLE;
  52 +import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION;
  53 +
  54 +@Slf4j
  55 +@Service
  56 +@TbCoreComponent
  57 +public class DefaultFirmwareStateService implements FirmwareStateService {
  58 +
  59 + private final FirmwareService firmwareService;
  60 + private final DeviceService deviceService;
  61 + private final DeviceProfileService deviceProfileService;
  62 + private final RuleEngineTelemetryService telemetryService;
  63 +
  64 + public DefaultFirmwareStateService(FirmwareService firmwareService, DeviceService deviceService, DeviceProfileService deviceProfileService, RuleEngineTelemetryService telemetryService) {
  65 + this.firmwareService = firmwareService;
  66 + this.deviceService = deviceService;
  67 + this.deviceProfileService = deviceProfileService;
  68 + this.telemetryService = telemetryService;
  69 + }
  70 +
  71 + @Override
  72 + public void update(Device device, boolean created) {
  73 + FirmwareId firmwareId = device.getFirmwareId();
  74 + if (firmwareId == null) {
  75 + DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId());
  76 + firmwareId = deviceProfile.getFirmwareId();
  77 + }
  78 +
  79 + if (firmwareId == null) {
  80 + if (!created) {
  81 + remove(device);
  82 + }
  83 + } else {
  84 + update(device, firmwareService.findFirmwareById(device.getTenantId(), firmwareId), System.currentTimeMillis());
  85 + }
  86 + }
  87 +
  88 + @Override
  89 + public void update(DeviceProfile deviceProfile) {
  90 + TenantId tenantId = deviceProfile.getTenantId();
  91 +
  92 + Consumer<Device> updateConsumer;
  93 + if (deviceProfile.getFirmwareId() != null) {
  94 + Firmware firmware = firmwareService.findFirmwareById(tenantId, deviceProfile.getFirmwareId());
  95 + long ts = System.currentTimeMillis();
  96 + updateConsumer = d -> update(d, firmware, ts);
  97 + } else {
  98 + updateConsumer = this::remove;
  99 + }
  100 +
  101 + PageLink pageLink = new PageLink(100);
  102 + PageData<Device> pageData;
  103 + do {
  104 + //TODO: create a query which will return devices without firmware
  105 + pageData = deviceService.findDevicesByTenantIdAndType(tenantId, deviceProfile.getName(), pageLink);
  106 +
  107 + pageData.getData().stream().filter(d -> d.getFirmwareId() == null).forEach(updateConsumer);
  108 +
  109 + if (pageData.hasNext()) {
  110 + pageLink = pageLink.nextPageLink();
  111 + }
  112 + } while (pageData.hasNext());
  113 + }
  114 +
  115 + private void update(Device device, Firmware firmware, long ts) {
  116 + TenantId tenantId = device.getTenantId();
  117 + DeviceId deviceId = device.getId();
  118 +
  119 + List<TsKvEntry> telemetry = new ArrayList<>();
  120 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_TITLE, firmware.getTitle())));
  121 + telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_VERSION, firmware.getVersion())));
  122 +
  123 + telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() {
  124 + @Override
  125 + public void onSuccess(@Nullable Void tmp) {
  126 + log.trace("[{}] Success save telemetry with target firmware for device!", deviceId);
  127 + }
  128 +
  129 + @Override
  130 + public void onFailure(Throwable t) {
  131 + log.error("[{}] Failed to save telemetry with target firmware for device!", deviceId, t);
  132 + }
  133 + });
  134 +
  135 + List<AttributeKvEntry> attributes = new ArrayList<>();
  136 +
  137 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_TITLE, firmware.getTitle())));
  138 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_VERSION, firmware.getVersion())));
  139 +
  140 + attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(FIRMWARE_SIZE, (long) firmware.getData().array().length)));
  141 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm())));
  142 + attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM, firmware.getChecksum())));
  143 + telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() {
  144 + @Override
  145 + public void onSuccess(@Nullable Void tmp) {
  146 + log.trace("[{}] Success save attributes with target firmware!", deviceId);
  147 + }
  148 +
  149 + @Override
  150 + public void onFailure(Throwable t) {
  151 + log.error("[{}] Failed to save attributes with target firmware!", deviceId, t);
  152 + }
  153 + });
  154 + }
  155 +
  156 + private void remove(Device device) {
  157 + telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE,
  158 + Arrays.asList(FIRMWARE_TITLE, FIRMWARE_VERSION, FIRMWARE_SIZE, FIRMWARE_CHECKSUM_ALGORITHM, FIRMWARE_CHECKSUM),
  159 + new FutureCallback<>() {
  160 + @Override
  161 + public void onSuccess(@Nullable Void tmp) {
  162 + log.trace("[{}] Success remove target firmware attributes!", device.getId());
  163 + }
  164 +
  165 + @Override
  166 + public void onFailure(Throwable t) {
  167 + log.error("[{}] Failed to remove target firmware attributes!", device.getId(), t);
  168 + }
  169 + });
  170 + }
  171 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.firmware;
  17 +
  18 +import org.thingsboard.server.common.data.Device;
  19 +import org.thingsboard.server.common.data.DeviceProfile;
  20 +
  21 +public interface FirmwareStateService {
  22 +
  23 + void update(Device device, boolean created);
  24 +
  25 + void update(DeviceProfile deviceProfile);
  26 +
  27 +}
@@ -91,4 +91,19 @@ public class DataConstants { @@ -91,4 +91,19 @@ public class DataConstants {
91 public static final String USERNAME = "username"; 91 public static final String USERNAME = "username";
92 public static final String PASSWORD = "password"; 92 public static final String PASSWORD = "password";
93 93
  94 + //firmware
  95 + //telemetry
  96 + public static final String CURRENT_FIRMWARE_TITLE = "cur_fw_title";
  97 + public static final String CURRENT_FIRMWARE_VERSION = "cur_fw_version";
  98 + public static final String TARGET_FIRMWARE_TITLE = "target_fw_title";
  99 + public static final String TARGET_FIRMWARE_VERSION = "target_fw_version";
  100 + public static final String CURRENT_FIRMWARE_STATE = "cur_fw_state";
  101 +
  102 + //attributes
  103 + //telemetry
  104 + public static final String FIRMWARE_TITLE = "fw_title";
  105 + public static final String FIRMWARE_VERSION = "fw_version";
  106 + public static final String FIRMWARE_SIZE = "fw_size";
  107 + public static final String FIRMWARE_CHECKSUM = "fw_checksum";
  108 + public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm";
94 } 109 }
@@ -114,7 +114,8 @@ public class BaseFirmwareService implements FirmwareService { @@ -114,7 +114,8 @@ public class BaseFirmwareService implements FirmwareService {
114 log.trace("Executing findTenantFirmwaresByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink); 114 log.trace("Executing findTenantFirmwaresByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink);
115 validateId(tenantId, INCORRECT_TENANT_ID + tenantId); 115 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
116 validatePageLink(pageLink); 116 validatePageLink(pageLink);
117 - return firmwareInfoDao.findFirmwareInfoByTenantIdAndHasData(tenantId, hasData, pageLink); } 117 + return firmwareInfoDao.findFirmwareInfoByTenantIdAndHasData(tenantId, hasData, pageLink);
  118 + }
118 119
119 @Override 120 @Override
120 public void deleteFirmware(TenantId tenantId, FirmwareId firmwareId) { 121 public void deleteFirmware(TenantId tenantId, FirmwareId firmwareId) {
@@ -211,31 +212,32 @@ public class BaseFirmwareService implements FirmwareService { @@ -211,31 +212,32 @@ public class BaseFirmwareService implements FirmwareService {
211 throw new DataValidationException("Firmware data should be specified!"); 212 throw new DataValidationException("Firmware data should be specified!");
212 } 213 }
213 214
214 - if (firmware.getChecksumAlgorithm() != null) {  
215 - if (StringUtils.isEmpty(firmware.getChecksum())) {  
216 - throw new DataValidationException("Firmware checksum should be specified!");  
217 - } 215 + if (StringUtils.isEmpty(firmware.getChecksumAlgorithm())) {
  216 + throw new DataValidationException("Firmware checksum algorithm should be specified!");
  217 + }
  218 + if (StringUtils.isEmpty(firmware.getChecksum())) {
  219 + throw new DataValidationException("Firmware checksum should be specified!");
  220 + }
218 221
219 - HashFunction hashFunction;  
220 - switch (firmware.getChecksumAlgorithm()) {  
221 - case "sha256":  
222 - hashFunction = Hashing.sha256();  
223 - break;  
224 - case "md5":  
225 - hashFunction = Hashing.md5();  
226 - break;  
227 - case "crc32":  
228 - hashFunction = Hashing.crc32();  
229 - break;  
230 - default:  
231 - throw new DataValidationException("Unknown checksum algorithm!");  
232 - } 222 + HashFunction hashFunction;
  223 + switch (firmware.getChecksumAlgorithm()) {
  224 + case "sha256":
  225 + hashFunction = Hashing.sha256();
  226 + break;
  227 + case "md5":
  228 + hashFunction = Hashing.md5();
  229 + break;
  230 + case "crc32":
  231 + hashFunction = Hashing.crc32();
  232 + break;
  233 + default:
  234 + throw new DataValidationException("Unknown checksum algorithm!");
  235 + }
233 236
234 - String currentChecksum = hashFunction.hashBytes(data.array()).toString(); 237 + String currentChecksum = hashFunction.hashBytes(data.array()).toString();
235 238
236 - if (!currentChecksum.equals(firmware.getChecksum())) {  
237 - throw new DataValidationException("Wrong firmware file!");  
238 - } 239 + if (!currentChecksum.equals(firmware.getChecksum())) {
  240 + throw new DataValidationException("Wrong firmware file!");
239 } 241 }
240 } 242 }
241 243