Commit d6f451ccca90ce6cd7c56d46f3b75ab804680b5e

Authored by YevhenBondarenko
1 parent 81b203ef

created FirmwareStateService

... ... @@ -119,6 +119,7 @@ import org.thingsboard.server.queue.discovery.PartitionService;
119 119 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
120 120 import org.thingsboard.server.queue.util.TbCoreComponent;
121 121 import org.thingsboard.server.service.component.ComponentDiscoveryService;
  122 +import org.thingsboard.server.service.firmware.FirmwareStateService;
122 123 import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository;
123 124 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
124 125 import org.thingsboard.server.service.queue.TbClusterService;
... ... @@ -241,6 +242,9 @@ public abstract class BaseController {
241 242 protected FirmwareService firmwareService;
242 243
243 244 @Autowired
  245 + protected FirmwareStateService firmwareStateService;
  246 +
  247 + @Autowired
244 248 protected TbQueueProducerProvider producerProvider;
245 249
246 250 @Autowired
... ...
... ... @@ -70,6 +70,7 @@ import javax.annotation.Nullable;
70 70 import java.io.IOException;
71 71 import java.util.ArrayList;
72 72 import java.util.List;
  73 +import java.util.Objects;
73 74 import java.util.stream.Collectors;
74 75
75 76 @RestController
... ... @@ -117,13 +118,25 @@ public class DeviceController extends BaseController {
117 118
118 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 134 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
121 135
122 136 tbClusterService.onDeviceChange(savedDevice, null);
123 137 tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),
124 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 141 logEntityAction(savedDevice.getId(), savedDevice,
129 142 savedDevice.getCustomerId(),
... ... @@ -134,12 +147,19 @@ public class DeviceController extends BaseController {
134 147 } else {
135 148 deviceStateService.onDeviceUpdated(savedDevice);
136 149 }
  150 +
  151 + if (isFirmwareChanged) {
  152 + firmwareStateService.update(savedDevice, created);
  153 + }
  154 +
137 155 return savedDevice;
138   - } catch (Exception e) {
  156 + } catch (
  157 + Exception e) {
139 158 logEntityAction(emptyId(EntityType.DEVICE), device,
140 159 null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
141 160 throw handleException(e);
142 161 }
  162 +
143 163 }
144 164
145 165 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
... ...
... ... @@ -43,6 +43,7 @@ import org.thingsboard.server.service.security.permission.Operation;
43 43 import org.thingsboard.server.service.security.permission.Resource;
44 44
45 45 import java.util.List;
  46 +import java.util.Objects;
46 47 import java.util.UUID;
47 48
48 49 @RestController
... ... @@ -143,6 +144,15 @@ public class DeviceProfileController extends BaseController {
143 144
144 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 156 DeviceProfile savedDeviceProfile = checkNotNull(deviceProfileService.saveDeviceProfile(deviceProfile));
147 157
148 158 tbClusterService.onDeviceProfileChange(savedDeviceProfile, null);
... ... @@ -153,6 +163,10 @@ public class DeviceProfileController extends BaseController {
153 163 null,
154 164 created ? ActionType.ADDED : ActionType.UPDATED, null);
155 165
  166 + if (isFirmwareChanged) {
  167 + firmwareStateService.update(savedDeviceProfile);
  168 + }
  169 +
156 170 return savedDeviceProfile;
157 171 } catch (Exception e) {
158 172 logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile,
... ...
... ... @@ -15,7 +15,9 @@
15 15 */
16 16 package org.thingsboard.server.controller;
17 17
  18 +import com.google.common.hash.Hashing;
18 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.apache.commons.lang3.StringUtils;
19 21 import org.springframework.core.io.ByteArrayResource;
20 22 import org.springframework.http.HttpHeaders;
21 23 import org.springframework.http.ResponseEntity;
... ... @@ -127,6 +129,11 @@ public class FirmwareController extends BaseController {
127 129 firmware.setVersion(info.getVersion());
128 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 137 firmware.setChecksumAlgorithm(checksumAlgorithm);
131 138 firmware.setChecksum(checksum);
132 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 91 public static final String USERNAME = "username";
92 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 114 log.trace("Executing findTenantFirmwaresByTenantIdAndHasData, tenantId [{}], hasData [{}] pageLink [{}]", tenantId, hasData, pageLink);
115 115 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
116 116 validatePageLink(pageLink);
117   - return firmwareInfoDao.findFirmwareInfoByTenantIdAndHasData(tenantId, hasData, pageLink); }
  117 + return firmwareInfoDao.findFirmwareInfoByTenantIdAndHasData(tenantId, hasData, pageLink);
  118 + }
118 119
119 120 @Override
120 121 public void deleteFirmware(TenantId tenantId, FirmwareId firmwareId) {
... ... @@ -211,31 +212,32 @@ public class BaseFirmwareService implements FirmwareService {
211 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
... ...