committed by
GitHub
219 changed files with 6699 additions and 997 deletions
@ -0,0 +1,197 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.controller; |
||||
|
|
||||
|
import com.google.common.hash.Hashing; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.springframework.core.io.ByteArrayResource; |
||||
|
import org.springframework.http.HttpHeaders; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.security.access.prepost.PreAuthorize; |
||||
|
import org.springframework.web.bind.annotation.PathVariable; |
||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMethod; |
||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
import org.springframework.web.bind.annotation.ResponseBody; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
import org.thingsboard.server.common.data.Firmware; |
||||
|
import org.thingsboard.server.common.data.FirmwareInfo; |
||||
|
import org.thingsboard.server.common.data.exception.ThingsboardException; |
||||
|
import org.thingsboard.server.common.data.id.FirmwareId; |
||||
|
import org.thingsboard.server.common.data.page.PageData; |
||||
|
import org.thingsboard.server.common.data.page.PageLink; |
||||
|
import org.thingsboard.server.queue.util.TbCoreComponent; |
||||
|
import org.thingsboard.server.service.security.permission.Operation; |
||||
|
import org.thingsboard.server.service.security.permission.Resource; |
||||
|
|
||||
|
import java.nio.ByteBuffer; |
||||
|
|
||||
|
@Slf4j |
||||
|
@RestController |
||||
|
@TbCoreComponent |
||||
|
@RequestMapping("/api") |
||||
|
public class FirmwareController extends BaseController { |
||||
|
|
||||
|
public static final String FIRMWARE_ID = "firmwareId"; |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmware/{firmwareId}/download", method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public ResponseEntity<org.springframework.core.io.Resource> downloadFirmware(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { |
||||
|
checkParameter(FIRMWARE_ID, strFirmwareId); |
||||
|
try { |
||||
|
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
||||
|
Firmware firmware = checkFirmwareId(firmwareId, Operation.READ); |
||||
|
|
||||
|
ByteArrayResource resource = new ByteArrayResource(firmware.getData().array()); |
||||
|
return ResponseEntity.ok() |
||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + firmware.getFileName()) |
||||
|
.header("x-filename", firmware.getFileName()) |
||||
|
.contentLength(resource.contentLength()) |
||||
|
.contentType(parseMediaType(firmware.getContentType())) |
||||
|
.body(resource); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmware/info/{firmwareId}", method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public FirmwareInfo getFirmwareInfoById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { |
||||
|
checkParameter(FIRMWARE_ID, strFirmwareId); |
||||
|
try { |
||||
|
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
||||
|
return checkFirmwareInfoId(firmwareId, Operation.READ); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public Firmware getFirmwareById(@PathVariable(FIRMWARE_ID) String strFirmwareId) throws ThingsboardException { |
||||
|
checkParameter(FIRMWARE_ID, strFirmwareId); |
||||
|
try { |
||||
|
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
||||
|
return checkFirmwareId(firmwareId, Operation.READ); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmware", method = RequestMethod.POST) |
||||
|
@ResponseBody |
||||
|
public FirmwareInfo saveFirmwareInfo(@RequestBody FirmwareInfo firmwareInfo) throws ThingsboardException { |
||||
|
firmwareInfo.setTenantId(getTenantId()); |
||||
|
checkEntity(firmwareInfo.getId(), firmwareInfo, Resource.FIRMWARE); |
||||
|
try { |
||||
|
return firmwareService.saveFirmwareInfo(firmwareInfo); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.POST) |
||||
|
@ResponseBody |
||||
|
public Firmware saveFirmwareData(@PathVariable(FIRMWARE_ID) String strFirmwareId, |
||||
|
@RequestParam(required = false) String checksum, |
||||
|
@RequestParam(required = false) String checksumAlgorithm, |
||||
|
@RequestBody MultipartFile file) throws ThingsboardException { |
||||
|
checkParameter(FIRMWARE_ID, strFirmwareId); |
||||
|
try { |
||||
|
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
||||
|
FirmwareInfo info = checkFirmwareInfoId(firmwareId, Operation.READ); |
||||
|
|
||||
|
Firmware firmware = new Firmware(firmwareId); |
||||
|
firmware.setCreatedTime(info.getCreatedTime()); |
||||
|
firmware.setTenantId(getTenantId()); |
||||
|
firmware.setTitle(info.getTitle()); |
||||
|
firmware.setVersion(info.getVersion()); |
||||
|
firmware.setAdditionalInfo(info.getAdditionalInfo()); |
||||
|
|
||||
|
byte[] data = file.getBytes(); |
||||
|
if (StringUtils.isEmpty(checksumAlgorithm)) { |
||||
|
checksumAlgorithm = "sha256"; |
||||
|
checksum = Hashing.sha256().hashBytes(data).toString(); |
||||
|
} |
||||
|
|
||||
|
firmware.setChecksumAlgorithm(checksumAlgorithm); |
||||
|
firmware.setChecksum(checksum); |
||||
|
firmware.setFileName(file.getOriginalFilename()); |
||||
|
firmware.setContentType(file.getContentType()); |
||||
|
firmware.setData(ByteBuffer.wrap(data)); |
||||
|
firmware.setDataSize((long) data.length); |
||||
|
return firmwareService.saveFirmware(firmware); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmwares", method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public PageData<FirmwareInfo> getFirmwares(@RequestParam int pageSize, |
||||
|
@RequestParam int page, |
||||
|
@RequestParam(required = false) String textSearch, |
||||
|
@RequestParam(required = false) String sortProperty, |
||||
|
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
||||
|
try { |
||||
|
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
||||
|
return checkNotNull(firmwareService.findTenantFirmwaresByTenantId(getTenantId(), pageLink)); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmwares/{hasData}", method = RequestMethod.GET) |
||||
|
@ResponseBody |
||||
|
public PageData<FirmwareInfo> getFirmwares(@PathVariable("hasData") boolean hasData, |
||||
|
@RequestParam int pageSize, |
||||
|
@RequestParam int page, |
||||
|
@RequestParam(required = false) String textSearch, |
||||
|
@RequestParam(required = false) String sortProperty, |
||||
|
@RequestParam(required = false) String sortOrder) throws ThingsboardException { |
||||
|
try { |
||||
|
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
||||
|
return checkNotNull(firmwareService.findTenantFirmwaresByTenantIdAndHasData(getTenantId(), hasData, pageLink)); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") |
||||
|
@RequestMapping(value = "/firmware/{firmwareId}", method = RequestMethod.DELETE) |
||||
|
@ResponseBody |
||||
|
public void deleteResource(@PathVariable("firmwareId") String strFirmwareId) throws ThingsboardException { |
||||
|
checkParameter(FIRMWARE_ID, strFirmwareId); |
||||
|
try { |
||||
|
FirmwareId firmwareId = new FirmwareId(toUUID(strFirmwareId)); |
||||
|
checkFirmwareInfoId(firmwareId, Operation.DELETE); |
||||
|
firmwareService.deleteFirmware(getTenantId(), firmwareId); |
||||
|
} catch (Exception e) { |
||||
|
throw handleException(e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,148 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.apiusage; |
||||
|
|
||||
|
import lombok.Getter; |
||||
|
import org.springframework.data.util.Pair; |
||||
|
import org.thingsboard.server.common.data.ApiFeature; |
||||
|
import org.thingsboard.server.common.data.ApiUsageRecordKey; |
||||
|
import org.thingsboard.server.common.data.ApiUsageState; |
||||
|
import org.thingsboard.server.common.data.ApiUsageStateValue; |
||||
|
import org.thingsboard.server.common.data.EntityType; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.msg.tools.SchedulerUtils; |
||||
|
|
||||
|
import java.util.Arrays; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.HashSet; |
||||
|
import java.util.Map; |
||||
|
import java.util.Set; |
||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||
|
|
||||
|
public abstract class BaseApiUsageState { |
||||
|
private final Map<ApiUsageRecordKey, Long> currentCycleValues = new ConcurrentHashMap<>(); |
||||
|
private final Map<ApiUsageRecordKey, Long> currentHourValues = new ConcurrentHashMap<>(); |
||||
|
|
||||
|
@Getter |
||||
|
private final ApiUsageState apiUsageState; |
||||
|
@Getter |
||||
|
private volatile long currentCycleTs; |
||||
|
@Getter |
||||
|
private volatile long nextCycleTs; |
||||
|
@Getter |
||||
|
private volatile long currentHourTs; |
||||
|
|
||||
|
public BaseApiUsageState(ApiUsageState apiUsageState) { |
||||
|
this.apiUsageState = apiUsageState; |
||||
|
this.currentCycleTs = SchedulerUtils.getStartOfCurrentMonth(); |
||||
|
this.nextCycleTs = SchedulerUtils.getStartOfNextMonth(); |
||||
|
this.currentHourTs = SchedulerUtils.getStartOfCurrentHour(); |
||||
|
} |
||||
|
|
||||
|
public void put(ApiUsageRecordKey key, Long value) { |
||||
|
currentCycleValues.put(key, value); |
||||
|
} |
||||
|
|
||||
|
public void putHourly(ApiUsageRecordKey key, Long value) { |
||||
|
currentHourValues.put(key, value); |
||||
|
} |
||||
|
|
||||
|
public long add(ApiUsageRecordKey key, long value) { |
||||
|
long result = currentCycleValues.getOrDefault(key, 0L) + value; |
||||
|
currentCycleValues.put(key, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public long get(ApiUsageRecordKey key) { |
||||
|
return currentCycleValues.getOrDefault(key, 0L); |
||||
|
} |
||||
|
|
||||
|
public long addToHourly(ApiUsageRecordKey key, long value) { |
||||
|
long result = currentHourValues.getOrDefault(key, 0L) + value; |
||||
|
currentHourValues.put(key, result); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public void setHour(long currentHourTs) { |
||||
|
this.currentHourTs = currentHourTs; |
||||
|
for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) { |
||||
|
currentHourValues.put(key, 0L); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void setCycles(long currentCycleTs, long nextCycleTs) { |
||||
|
this.currentCycleTs = currentCycleTs; |
||||
|
this.nextCycleTs = nextCycleTs; |
||||
|
for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) { |
||||
|
currentCycleValues.put(key, 0L); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public ApiUsageStateValue getFeatureValue(ApiFeature feature) { |
||||
|
switch (feature) { |
||||
|
case TRANSPORT: |
||||
|
return apiUsageState.getTransportState(); |
||||
|
case RE: |
||||
|
return apiUsageState.getReExecState(); |
||||
|
case DB: |
||||
|
return apiUsageState.getDbStorageState(); |
||||
|
case JS: |
||||
|
return apiUsageState.getJsExecState(); |
||||
|
case EMAIL: |
||||
|
return apiUsageState.getEmailExecState(); |
||||
|
case SMS: |
||||
|
return apiUsageState.getSmsExecState(); |
||||
|
default: |
||||
|
return ApiUsageStateValue.ENABLED; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public boolean setFeatureValue(ApiFeature feature, ApiUsageStateValue value) { |
||||
|
ApiUsageStateValue currentValue = getFeatureValue(feature); |
||||
|
switch (feature) { |
||||
|
case TRANSPORT: |
||||
|
apiUsageState.setTransportState(value); |
||||
|
break; |
||||
|
case RE: |
||||
|
apiUsageState.setReExecState(value); |
||||
|
break; |
||||
|
case DB: |
||||
|
apiUsageState.setDbStorageState(value); |
||||
|
break; |
||||
|
case JS: |
||||
|
apiUsageState.setJsExecState(value); |
||||
|
break; |
||||
|
case EMAIL: |
||||
|
apiUsageState.setEmailExecState(value); |
||||
|
break; |
||||
|
case SMS: |
||||
|
apiUsageState.setSmsExecState(value); |
||||
|
break; |
||||
|
} |
||||
|
return !currentValue.equals(value); |
||||
|
} |
||||
|
|
||||
|
public abstract EntityType getEntityType(); |
||||
|
|
||||
|
public TenantId getTenantId() { |
||||
|
return getApiUsageState().getTenantId(); |
||||
|
} |
||||
|
|
||||
|
public EntityId getEntityId() { |
||||
|
return getApiUsageState().getEntityId(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,260 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.firmware; |
||||
|
|
||||
|
import com.google.common.util.concurrent.FutureCallback; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; |
||||
|
import org.thingsboard.server.common.data.DataConstants; |
||||
|
import org.thingsboard.server.common.data.Device; |
||||
|
import org.thingsboard.server.common.data.DeviceProfile; |
||||
|
import org.thingsboard.server.common.data.Firmware; |
||||
|
import org.thingsboard.server.common.data.FirmwareInfo; |
||||
|
import org.thingsboard.server.common.data.id.DeviceId; |
||||
|
import org.thingsboard.server.common.data.id.FirmwareId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
||||
|
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
||||
|
import org.thingsboard.server.common.data.kv.BasicTsKvEntry; |
||||
|
import org.thingsboard.server.common.data.kv.LongDataEntry; |
||||
|
import org.thingsboard.server.common.data.kv.StringDataEntry; |
||||
|
import org.thingsboard.server.common.data.kv.TsKvEntry; |
||||
|
import org.thingsboard.server.common.data.page.PageData; |
||||
|
import org.thingsboard.server.common.data.page.PageLink; |
||||
|
import org.thingsboard.server.common.msg.queue.TbCallback; |
||||
|
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
||||
|
import org.thingsboard.server.dao.device.DeviceProfileService; |
||||
|
import org.thingsboard.server.dao.device.DeviceService; |
||||
|
import org.thingsboard.server.dao.firmware.FirmwareService; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; |
||||
|
import org.thingsboard.server.queue.TbQueueProducer; |
||||
|
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
||||
|
import org.thingsboard.server.queue.provider.TbCoreQueueFactory; |
||||
|
import org.thingsboard.server.queue.util.TbCoreComponent; |
||||
|
|
||||
|
import javax.annotation.Nullable; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Arrays; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.UUID; |
||||
|
import java.util.function.Consumer; |
||||
|
|
||||
|
import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM; |
||||
|
import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_CHECKSUM_ALGORITHM; |
||||
|
import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_SIZE; |
||||
|
import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_TITLE; |
||||
|
import static org.thingsboard.server.common.data.DataConstants.FIRMWARE_VERSION; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Service |
||||
|
@TbCoreComponent |
||||
|
public class DefaultFirmwareStateService implements FirmwareStateService { |
||||
|
|
||||
|
private final FirmwareService firmwareService; |
||||
|
private final DeviceService deviceService; |
||||
|
private final DeviceProfileService deviceProfileService; |
||||
|
private final RuleEngineTelemetryService telemetryService; |
||||
|
private final TbQueueProducer<TbProtoQueueMsg<ToFirmwareStateServiceMsg>> fwStateMsgProducer; |
||||
|
|
||||
|
public DefaultFirmwareStateService(FirmwareService firmwareService, |
||||
|
DeviceService deviceService, |
||||
|
DeviceProfileService deviceProfileService, |
||||
|
RuleEngineTelemetryService telemetryService, |
||||
|
TbCoreQueueFactory coreQueueFactory) { |
||||
|
this.firmwareService = firmwareService; |
||||
|
this.deviceService = deviceService; |
||||
|
this.deviceProfileService = deviceProfileService; |
||||
|
this.telemetryService = telemetryService; |
||||
|
this.fwStateMsgProducer = coreQueueFactory.createToFirmwareStateServiceMsgProducer(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void update(Device device, Device oldDevice) { |
||||
|
FirmwareId newFirmwareId = device.getFirmwareId(); |
||||
|
if (newFirmwareId == null) { |
||||
|
DeviceProfile newDeviceProfile = deviceProfileService.findDeviceProfileById(device.getTenantId(), device.getDeviceProfileId()); |
||||
|
newFirmwareId = newDeviceProfile.getFirmwareId(); |
||||
|
} |
||||
|
if (oldDevice != null) { |
||||
|
if (newFirmwareId != null) { |
||||
|
FirmwareId oldFirmwareId = oldDevice.getFirmwareId(); |
||||
|
if (oldFirmwareId == null) { |
||||
|
DeviceProfile oldDeviceProfile = deviceProfileService.findDeviceProfileById(oldDevice.getTenantId(), oldDevice.getDeviceProfileId()); |
||||
|
oldFirmwareId = oldDeviceProfile.getFirmwareId(); |
||||
|
} |
||||
|
if (!newFirmwareId.equals(oldFirmwareId)) { |
||||
|
// Device was updated and new firmware is different from previous firmware.
|
||||
|
send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); |
||||
|
} |
||||
|
} else { |
||||
|
// Device was updated and new firmware is not set.
|
||||
|
remove(device); |
||||
|
} |
||||
|
} else if (newFirmwareId != null) { |
||||
|
// Device was created and firmware is defined.
|
||||
|
send(device.getTenantId(), device.getId(), newFirmwareId, System.currentTimeMillis()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void update(DeviceProfile deviceProfile) { |
||||
|
TenantId tenantId = deviceProfile.getTenantId(); |
||||
|
|
||||
|
Consumer<Device> updateConsumer; |
||||
|
if (deviceProfile.getFirmwareId() != null) { |
||||
|
long ts = System.currentTimeMillis(); |
||||
|
updateConsumer = d -> send(d.getTenantId(), d.getId(), deviceProfile.getFirmwareId(), ts); |
||||
|
} else { |
||||
|
updateConsumer = this::remove; |
||||
|
} |
||||
|
|
||||
|
PageLink pageLink = new PageLink(100); |
||||
|
PageData<Device> pageData; |
||||
|
do { |
||||
|
pageData = deviceService.findDevicesByTenantIdAndTypeAndEmptyFirmware(tenantId, deviceProfile.getName(), pageLink); |
||||
|
|
||||
|
pageData.getData().forEach(updateConsumer); |
||||
|
|
||||
|
if (pageData.hasNext()) { |
||||
|
pageLink = pageLink.nextPageLink(); |
||||
|
} |
||||
|
} while (pageData.hasNext()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean process(ToFirmwareStateServiceMsg msg) { |
||||
|
boolean isSuccess = false; |
||||
|
FirmwareId targetFirmwareId = new FirmwareId(new UUID(msg.getFirmwareIdMSB(), msg.getFirmwareIdLSB())); |
||||
|
DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); |
||||
|
TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); |
||||
|
long ts = msg.getTs(); |
||||
|
|
||||
|
Device device = deviceService.findDeviceById(tenantId, deviceId); |
||||
|
if (device == null) { |
||||
|
log.warn("[{}] [{}] Device was removed during firmware update msg was queued!", tenantId, deviceId); |
||||
|
} else { |
||||
|
FirmwareId currentFirmwareId = device.getFirmwareId(); |
||||
|
|
||||
|
if (currentFirmwareId == null) { |
||||
|
currentFirmwareId = deviceProfileService.findDeviceProfileById(tenantId, device.getDeviceProfileId()).getFirmwareId(); |
||||
|
} |
||||
|
|
||||
|
if (targetFirmwareId.equals(currentFirmwareId)) { |
||||
|
update(device, firmwareService.findFirmwareById(device.getTenantId(), targetFirmwareId), ts); |
||||
|
isSuccess = true; |
||||
|
} else { |
||||
|
log.warn("[{}] [{}] Can`t update firmware for the device, target firmwareId: [{}], current firmwareId: [{}]!", tenantId, deviceId, targetFirmwareId, currentFirmwareId); |
||||
|
} |
||||
|
} |
||||
|
return isSuccess; |
||||
|
} |
||||
|
|
||||
|
private void send(TenantId tenantId, DeviceId deviceId, FirmwareId firmwareId, long ts) { |
||||
|
ToFirmwareStateServiceMsg msg = ToFirmwareStateServiceMsg.newBuilder() |
||||
|
.setTenantIdMSB(tenantId.getId().getMostSignificantBits()) |
||||
|
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) |
||||
|
.setDeviceIdMSB(deviceId.getId().getMostSignificantBits()) |
||||
|
.setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) |
||||
|
.setFirmwareIdMSB(firmwareId.getId().getMostSignificantBits()) |
||||
|
.setFirmwareIdLSB(firmwareId.getId().getLeastSignificantBits()) |
||||
|
.setTs(ts) |
||||
|
.build(); |
||||
|
|
||||
|
FirmwareInfo firmware = firmwareService.findFirmwareInfoById(tenantId, firmwareId); |
||||
|
if (firmware == null) { |
||||
|
log.warn("[{}] Failed to send firmware update because firmware was already deleted", firmwareId); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
TopicPartitionInfo tpi = new TopicPartitionInfo(fwStateMsgProducer.getDefaultTopic(), null, null, false); |
||||
|
fwStateMsgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), null); |
||||
|
|
||||
|
List<TsKvEntry> telemetry = new ArrayList<>(); |
||||
|
telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_TITLE, firmware.getTitle()))); |
||||
|
telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.TARGET_FIRMWARE_VERSION, firmware.getVersion()))); |
||||
|
telemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.QUEUED.name()))); |
||||
|
|
||||
|
telemetryService.saveAndNotify(tenantId, deviceId, telemetry, new FutureCallback<>() { |
||||
|
@Override |
||||
|
public void onSuccess(@Nullable Void tmp) { |
||||
|
log.trace("[{}] Success save firmware status!", deviceId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(Throwable t) { |
||||
|
log.error("[{}] Failed to save firmware status!", deviceId, t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private void update(Device device, FirmwareInfo firmware, long ts) { |
||||
|
TenantId tenantId = device.getTenantId(); |
||||
|
DeviceId deviceId = device.getId(); |
||||
|
|
||||
|
BasicTsKvEntry status = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(DataConstants.FIRMWARE_STATE, FirmwareUpdateStatus.INITIATED.name())); |
||||
|
|
||||
|
telemetryService.saveAndNotify(tenantId, deviceId, Collections.singletonList(status), new FutureCallback<>() { |
||||
|
@Override |
||||
|
public void onSuccess(@Nullable Void tmp) { |
||||
|
log.trace("[{}] Success save telemetry with target firmware for device!", deviceId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(Throwable t) { |
||||
|
log.error("[{}] Failed to save telemetry with target firmware for device!", deviceId, t); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
List<AttributeKvEntry> attributes = new ArrayList<>(); |
||||
|
|
||||
|
attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_TITLE, firmware.getTitle()))); |
||||
|
attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_VERSION, firmware.getVersion()))); |
||||
|
|
||||
|
attributes.add(new BaseAttributeKvEntry(ts, new LongDataEntry(FIRMWARE_SIZE, firmware.getDataSize()))); |
||||
|
attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM_ALGORITHM, firmware.getChecksumAlgorithm()))); |
||||
|
attributes.add(new BaseAttributeKvEntry(ts, new StringDataEntry(DataConstants.FIRMWARE_CHECKSUM, firmware.getChecksum()))); |
||||
|
telemetryService.saveAndNotify(tenantId, deviceId, DataConstants.SHARED_SCOPE, attributes, new FutureCallback<>() { |
||||
|
@Override |
||||
|
public void onSuccess(@Nullable Void tmp) { |
||||
|
log.trace("[{}] Success save attributes with target firmware!", deviceId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(Throwable t) { |
||||
|
log.error("[{}] Failed to save attributes with target firmware!", deviceId, t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void remove(Device device) { |
||||
|
telemetryService.deleteAndNotify(device.getTenantId(), device.getId(), DataConstants.SHARED_SCOPE, |
||||
|
Arrays.asList(FIRMWARE_TITLE, FIRMWARE_VERSION, FIRMWARE_SIZE, FIRMWARE_CHECKSUM_ALGORITHM, FIRMWARE_CHECKSUM), |
||||
|
new FutureCallback<>() { |
||||
|
@Override |
||||
|
public void onSuccess(@Nullable Void tmp) { |
||||
|
log.trace("[{}] Success remove target firmware attributes!", device.getId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(Throwable t) { |
||||
|
log.error("[{}] Failed to remove target firmware attributes!", device.getId(), t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.firmware; |
||||
|
|
||||
|
import org.thingsboard.server.common.data.Device; |
||||
|
import org.thingsboard.server.common.data.DeviceProfile; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos.ToFirmwareStateServiceMsg; |
||||
|
|
||||
|
public interface FirmwareStateService { |
||||
|
|
||||
|
void update(Device device, Device oldDevice); |
||||
|
|
||||
|
void update(DeviceProfile deviceProfile); |
||||
|
|
||||
|
boolean process(ToFirmwareStateServiceMsg msg); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.firmware; |
||||
|
|
||||
|
public enum FirmwareUpdateStatus { |
||||
|
QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATING, UPDATED, FAILED |
||||
|
} |
||||
@ -0,0 +1,302 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.controller; |
||||
|
|
||||
|
import com.fasterxml.jackson.core.type.TypeReference; |
||||
|
import org.junit.After; |
||||
|
import org.junit.Assert; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
import org.springframework.mock.web.MockMultipartFile; |
||||
|
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; |
||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; |
||||
|
import org.thingsboard.common.util.JacksonUtil; |
||||
|
import org.thingsboard.server.common.data.Firmware; |
||||
|
import org.thingsboard.server.common.data.FirmwareInfo; |
||||
|
import org.thingsboard.server.common.data.Tenant; |
||||
|
import org.thingsboard.server.common.data.User; |
||||
|
import org.thingsboard.server.common.data.page.PageData; |
||||
|
import org.thingsboard.server.common.data.page.PageLink; |
||||
|
import org.thingsboard.server.common.data.security.Authority; |
||||
|
|
||||
|
import java.nio.ByteBuffer; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
|
||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
||||
|
|
||||
|
public abstract class BaseFirmwareControllerTest extends AbstractControllerTest { |
||||
|
|
||||
|
private IdComparator<FirmwareInfo> idComparator = new IdComparator<>(); |
||||
|
|
||||
|
public static final String TITLE = "My firmware"; |
||||
|
private static final String FILE_NAME = "filename.txt"; |
||||
|
private static final String VERSION = "v1.0"; |
||||
|
private static final String CONTENT_TYPE = "text/plain"; |
||||
|
private static final String CHECKSUM_ALGORITHM = "sha256"; |
||||
|
private static final String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; |
||||
|
private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[]{1}); |
||||
|
|
||||
|
private Tenant savedTenant; |
||||
|
private User tenantAdmin; |
||||
|
|
||||
|
@Before |
||||
|
public void beforeTest() throws Exception { |
||||
|
loginSysAdmin(); |
||||
|
|
||||
|
Tenant tenant = new Tenant(); |
||||
|
tenant.setTitle("My tenant"); |
||||
|
savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
||||
|
Assert.assertNotNull(savedTenant); |
||||
|
|
||||
|
tenantAdmin = new User(); |
||||
|
tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
||||
|
tenantAdmin.setTenantId(savedTenant.getId()); |
||||
|
tenantAdmin.setEmail("tenant2@thingsboard.org"); |
||||
|
tenantAdmin.setFirstName("Joe"); |
||||
|
tenantAdmin.setLastName("Downs"); |
||||
|
|
||||
|
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
||||
|
} |
||||
|
|
||||
|
@After |
||||
|
public void afterTest() throws Exception { |
||||
|
loginSysAdmin(); |
||||
|
|
||||
|
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) |
||||
|
.andExpect(status().isOk()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSaveFirmware() throws Exception { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
Assert.assertNotNull(savedFirmwareInfo); |
||||
|
Assert.assertNotNull(savedFirmwareInfo.getId()); |
||||
|
Assert.assertTrue(savedFirmwareInfo.getCreatedTime() > 0); |
||||
|
Assert.assertEquals(savedTenant.getId(), savedFirmwareInfo.getTenantId()); |
||||
|
Assert.assertEquals(firmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); |
||||
|
Assert.assertEquals(firmwareInfo.getVersion(), savedFirmwareInfo.getVersion()); |
||||
|
|
||||
|
savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode()); |
||||
|
|
||||
|
save(savedFirmwareInfo); |
||||
|
|
||||
|
FirmwareInfo foundFirmwareInfo = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class); |
||||
|
Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSaveFirmwareData() throws Exception { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
Assert.assertNotNull(savedFirmwareInfo); |
||||
|
Assert.assertNotNull(savedFirmwareInfo.getId()); |
||||
|
Assert.assertTrue(savedFirmwareInfo.getCreatedTime() > 0); |
||||
|
Assert.assertEquals(savedTenant.getId(), savedFirmwareInfo.getTenantId()); |
||||
|
Assert.assertEquals(firmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); |
||||
|
Assert.assertEquals(firmwareInfo.getVersion(), savedFirmwareInfo.getVersion()); |
||||
|
|
||||
|
savedFirmwareInfo.setAdditionalInfo(JacksonUtil.newObjectNode()); |
||||
|
|
||||
|
save(savedFirmwareInfo); |
||||
|
|
||||
|
FirmwareInfo foundFirmwareInfo = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class); |
||||
|
Assert.assertEquals(foundFirmwareInfo.getTitle(), savedFirmwareInfo.getTitle()); |
||||
|
|
||||
|
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); |
||||
|
|
||||
|
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); |
||||
|
|
||||
|
Assert.assertEquals(FILE_NAME, savedFirmware.getFileName()); |
||||
|
Assert.assertEquals(CONTENT_TYPE, savedFirmware.getContentType()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testUpdateFirmwareFromDifferentTenant() throws Exception { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
loginDifferentTenant(); |
||||
|
doPost("/api/firmware", savedFirmwareInfo, FirmwareInfo.class, status().isForbidden()); |
||||
|
deleteDifferentTenant(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFindFirmwareInfoById() throws Exception { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
FirmwareInfo foundFirmware = doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString(), FirmwareInfo.class); |
||||
|
Assert.assertNotNull(foundFirmware); |
||||
|
Assert.assertEquals(savedFirmwareInfo, foundFirmware); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFindFirmwareById() throws Exception { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); |
||||
|
|
||||
|
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); |
||||
|
|
||||
|
Firmware foundFirmware = doGet("/api/firmware/" + savedFirmwareInfo.getId().getId().toString(), Firmware.class); |
||||
|
Assert.assertNotNull(foundFirmware); |
||||
|
Assert.assertEquals(savedFirmware, foundFirmware); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDeleteFirmware() throws Exception { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
doDelete("/api/firmware/" + savedFirmwareInfo.getId().getId().toString()) |
||||
|
.andExpect(status().isOk()); |
||||
|
|
||||
|
doGet("/api/firmware/info/" + savedFirmwareInfo.getId().getId().toString()) |
||||
|
.andExpect(status().isNotFound()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFindTenantFirmwares() throws Exception { |
||||
|
List<FirmwareInfo> firmwares = new ArrayList<>(); |
||||
|
for (int i = 0; i < 165; i++) { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION + i); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
if (i > 100) { |
||||
|
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); |
||||
|
|
||||
|
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); |
||||
|
firmwares.add(new FirmwareInfo(savedFirmware)); |
||||
|
} else { |
||||
|
firmwares.add(savedFirmwareInfo); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
List<FirmwareInfo> loadedFirmwares = new ArrayList<>(); |
||||
|
PageLink pageLink = new PageLink(24); |
||||
|
PageData<FirmwareInfo> pageData; |
||||
|
do { |
||||
|
pageData = doGetTypedWithPageLink("/api/firmwares?", |
||||
|
new TypeReference<>() { |
||||
|
}, pageLink); |
||||
|
loadedFirmwares.addAll(pageData.getData()); |
||||
|
if (pageData.hasNext()) { |
||||
|
pageLink = pageLink.nextPageLink(); |
||||
|
} |
||||
|
} while (pageData.hasNext()); |
||||
|
|
||||
|
Collections.sort(firmwares, idComparator); |
||||
|
Collections.sort(loadedFirmwares, idComparator); |
||||
|
|
||||
|
Assert.assertEquals(firmwares, loadedFirmwares); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFindTenantFirmwaresByHasData() throws Exception { |
||||
|
List<FirmwareInfo> firmwaresWithData = new ArrayList<>(); |
||||
|
List<FirmwareInfo> firmwaresWithoutData = new ArrayList<>(); |
||||
|
|
||||
|
for (int i = 0; i < 165; i++) { |
||||
|
FirmwareInfo firmwareInfo = new FirmwareInfo(); |
||||
|
firmwareInfo.setTitle(TITLE); |
||||
|
firmwareInfo.setVersion(VERSION + i); |
||||
|
|
||||
|
FirmwareInfo savedFirmwareInfo = save(firmwareInfo); |
||||
|
|
||||
|
if (i > 100) { |
||||
|
MockMultipartFile testData = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA.array()); |
||||
|
|
||||
|
Firmware savedFirmware = savaData("/api/firmware/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, CHECKSUM_ALGORITHM); |
||||
|
firmwaresWithData.add(new FirmwareInfo(savedFirmware)); |
||||
|
} else { |
||||
|
firmwaresWithoutData.add(savedFirmwareInfo); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
List<FirmwareInfo> loadedFirmwaresWithData = new ArrayList<>(); |
||||
|
PageLink pageLink = new PageLink(24); |
||||
|
PageData<FirmwareInfo> pageData; |
||||
|
do { |
||||
|
pageData = doGetTypedWithPageLink("/api/firmwares/true?", |
||||
|
new TypeReference<>() { |
||||
|
}, pageLink); |
||||
|
loadedFirmwaresWithData.addAll(pageData.getData()); |
||||
|
if (pageData.hasNext()) { |
||||
|
pageLink = pageLink.nextPageLink(); |
||||
|
} |
||||
|
} while (pageData.hasNext()); |
||||
|
|
||||
|
List<FirmwareInfo> loadedFirmwaresWithoutData = new ArrayList<>(); |
||||
|
pageLink = new PageLink(24); |
||||
|
do { |
||||
|
pageData = doGetTypedWithPageLink("/api/firmwares/false?", |
||||
|
new TypeReference<>() { |
||||
|
}, pageLink); |
||||
|
loadedFirmwaresWithoutData.addAll(pageData.getData()); |
||||
|
if (pageData.hasNext()) { |
||||
|
pageLink = pageLink.nextPageLink(); |
||||
|
} |
||||
|
} while (pageData.hasNext()); |
||||
|
|
||||
|
Collections.sort(firmwaresWithData, idComparator); |
||||
|
Collections.sort(firmwaresWithoutData, idComparator); |
||||
|
Collections.sort(loadedFirmwaresWithData, idComparator); |
||||
|
Collections.sort(loadedFirmwaresWithoutData, idComparator); |
||||
|
|
||||
|
Assert.assertEquals(firmwaresWithData, loadedFirmwaresWithData); |
||||
|
Assert.assertEquals(firmwaresWithoutData, loadedFirmwaresWithoutData); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private FirmwareInfo save(FirmwareInfo firmwareInfo) throws Exception { |
||||
|
return doPost("/api/firmware", firmwareInfo, FirmwareInfo.class); |
||||
|
} |
||||
|
|
||||
|
protected Firmware savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception { |
||||
|
MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params); |
||||
|
postRequest.file(content); |
||||
|
setJwtToken(postRequest); |
||||
|
return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), Firmware.class); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.controller.sql; |
||||
|
|
||||
|
import org.thingsboard.server.controller.BaseFirmwareControllerTest; |
||||
|
import org.thingsboard.server.dao.service.DaoSqlTest; |
||||
|
|
||||
|
@DaoSqlTest |
||||
|
public class FirmwareControllerSqlTest extends BaseFirmwareControllerTest { |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.firmware; |
||||
|
|
||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory; |
||||
|
|
||||
|
import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE; |
||||
|
|
||||
|
public abstract class AbstractRedisFirmwareCache { |
||||
|
|
||||
|
protected final RedisConnectionFactory redisConnectionFactory; |
||||
|
|
||||
|
protected AbstractRedisFirmwareCache(RedisConnectionFactory redisConnectionFactory) { |
||||
|
this.redisConnectionFactory = redisConnectionFactory; |
||||
|
} |
||||
|
|
||||
|
protected byte[] toFirmwareCacheKey(String key) { |
||||
|
return String.format("%s::%s", FIRMWARE_CACHE, key).getBytes(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.firmware; |
||||
|
|
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
||||
|
import org.springframework.cache.CacheManager; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE; |
||||
|
|
||||
|
@Service |
||||
|
@ConditionalOnExpression("(('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport') && ('${cache.type:null}'=='caffeine' || '${cache.type:null}'=='null')") |
||||
|
public class CaffeineFirmwareCacheReader implements FirmwareCacheReader { |
||||
|
|
||||
|
private final CacheManager cacheManager; |
||||
|
|
||||
|
public CaffeineFirmwareCacheReader(CacheManager cacheManager) { |
||||
|
this.cacheManager = cacheManager; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public byte[] get(String key) { |
||||
|
return get(key, 0, 0); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public byte[] get(String key, int chunkSize, int chunk) { |
||||
|
byte[] data = cacheManager.getCache(FIRMWARE_CACHE).get(key, byte[].class); |
||||
|
|
||||
|
if (chunkSize < 1) { |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
if (data != null && data.length > 0) { |
||||
|
int startIndex = chunkSize * chunk; |
||||
|
|
||||
|
int size = Math.min(data.length - startIndex, chunkSize); |
||||
|
|
||||
|
if (startIndex < data.length && size > 0) { |
||||
|
byte[] result = new byte[size]; |
||||
|
System.arraycopy(data, startIndex, result, 0, size); |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
return new byte[0]; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.firmware; |
||||
|
|
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
||||
|
import org.springframework.cache.CacheManager; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import static org.thingsboard.server.common.data.CacheConstants.FIRMWARE_CACHE; |
||||
|
|
||||
|
@Service |
||||
|
@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && ('${cache.type:null}'=='caffeine' || '${cache.type:null}'=='null')") |
||||
|
public class CaffeineFirmwareCacheWriter implements FirmwareCacheWriter { |
||||
|
|
||||
|
private final CacheManager cacheManager; |
||||
|
|
||||
|
public CaffeineFirmwareCacheWriter(CacheManager cacheManager) { |
||||
|
this.cacheManager = cacheManager; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void put(String key, byte[] value) { |
||||
|
cacheManager.getCache(FIRMWARE_CACHE).putIfAbsent(key, value); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.firmware; |
||||
|
|
||||
|
public interface FirmwareCacheReader { |
||||
|
byte[] get(String key); |
||||
|
|
||||
|
byte[] get(String key, int chunkSize, int chunk); |
||||
|
} |
||||
@ -0,0 +1,20 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.firmware; |
||||
|
|
||||
|
public interface FirmwareCacheWriter { |
||||
|
void put(String key, byte[] value); |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.firmware; |
||||
|
|
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
||||
|
import org.springframework.data.redis.connection.RedisConnection; |
||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
@Service |
||||
|
@ConditionalOnExpression("(('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true') || '${service.type:null}'=='tb-transport') && '${cache.type:null}'=='redis'") |
||||
|
public class RedisFirmwareCacheReader extends AbstractRedisFirmwareCache implements FirmwareCacheReader { |
||||
|
|
||||
|
public RedisFirmwareCacheReader(RedisConnectionFactory redisConnectionFactory) { |
||||
|
super(redisConnectionFactory); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public byte[] get(String key) { |
||||
|
return get(key, 0, 0); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public byte[] get(String key, int chunkSize, int chunk) { |
||||
|
try (RedisConnection connection = redisConnectionFactory.getConnection()) { |
||||
|
if (chunkSize == 0) { |
||||
|
return connection.get(toFirmwareCacheKey(key)); |
||||
|
} |
||||
|
|
||||
|
int startIndex = chunkSize * chunk; |
||||
|
int endIndex = startIndex + chunkSize - 1; |
||||
|
return connection.getRange(toFirmwareCacheKey(key), startIndex, endIndex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.cache.firmware; |
||||
|
|
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
||||
|
import org.springframework.data.redis.connection.RedisConnection; |
||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
@Service |
||||
|
@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${cache.type:null}'=='redis'") |
||||
|
public class RedisFirmwareCacheWriter extends AbstractRedisFirmwareCache implements FirmwareCacheWriter { |
||||
|
|
||||
|
public RedisFirmwareCacheWriter(RedisConnectionFactory redisConnectionFactory) { |
||||
|
super(redisConnectionFactory); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void put(String key, byte[] value) { |
||||
|
try (RedisConnection connection = redisConnectionFactory.getConnection()) { |
||||
|
connection.set(toFirmwareCacheKey(key), value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.dao.firmware; |
||||
|
|
||||
|
import org.thingsboard.server.common.data.Firmware; |
||||
|
import org.thingsboard.server.common.data.FirmwareInfo; |
||||
|
import org.thingsboard.server.common.data.id.FirmwareId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.common.data.page.PageData; |
||||
|
import org.thingsboard.server.common.data.page.PageLink; |
||||
|
|
||||
|
public interface FirmwareService { |
||||
|
|
||||
|
FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo); |
||||
|
|
||||
|
Firmware saveFirmware(Firmware firmware); |
||||
|
|
||||
|
Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId); |
||||
|
|
||||
|
FirmwareInfo findFirmwareInfoById(TenantId tenantId, FirmwareId firmwareId); |
||||
|
|
||||
|
PageData<FirmwareInfo> findTenantFirmwaresByTenantId(TenantId tenantId, PageLink pageLink); |
||||
|
|
||||
|
PageData<FirmwareInfo> findTenantFirmwaresByTenantIdAndHasData(TenantId tenantId, boolean hasData, PageLink pageLink); |
||||
|
|
||||
|
void deleteFirmware(TenantId tenantId, FirmwareId firmwareId); |
||||
|
|
||||
|
void deleteFirmwaresByTenantId(TenantId tenantId); |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import org.thingsboard.server.common.data.id.FirmwareId; |
||||
|
|
||||
|
import java.nio.ByteBuffer; |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class Firmware extends FirmwareInfo { |
||||
|
|
||||
|
private static final long serialVersionUID = 3091601761339422546L; |
||||
|
|
||||
|
private transient ByteBuffer data; |
||||
|
|
||||
|
public Firmware() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public Firmware(FirmwareId id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
public Firmware(Firmware firmware) { |
||||
|
super(firmware); |
||||
|
this.data = firmware.getData(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,67 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.thingsboard.server.common.data.id.FirmwareId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
|
||||
|
@Slf4j |
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class FirmwareInfo extends SearchTextBasedWithAdditionalInfo<FirmwareId> implements HasTenantId { |
||||
|
|
||||
|
private static final long serialVersionUID = 3168391583570815419L; |
||||
|
|
||||
|
private TenantId tenantId; |
||||
|
private String title; |
||||
|
private String version; |
||||
|
private boolean hasData; |
||||
|
private String fileName; |
||||
|
private String contentType; |
||||
|
private String checksumAlgorithm; |
||||
|
private String checksum; |
||||
|
private Long dataSize; |
||||
|
|
||||
|
|
||||
|
public FirmwareInfo() { |
||||
|
super(); |
||||
|
} |
||||
|
|
||||
|
public FirmwareInfo(FirmwareId id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
public FirmwareInfo(FirmwareInfo firmwareInfo) { |
||||
|
super(firmwareInfo); |
||||
|
this.tenantId = firmwareInfo.getTenantId(); |
||||
|
this.title = firmwareInfo.getTitle(); |
||||
|
this.version = firmwareInfo.getVersion(); |
||||
|
this.hasData = firmwareInfo.isHasData(); |
||||
|
this.fileName = firmwareInfo.getFileName(); |
||||
|
this.contentType = firmwareInfo.getContentType(); |
||||
|
this.checksumAlgorithm = firmwareInfo.getChecksumAlgorithm(); |
||||
|
this.checksum = firmwareInfo.getChecksum(); |
||||
|
this.dataSize = firmwareInfo.getDataSize(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getSearchText() { |
||||
|
return title; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2021 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.id; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
|
import com.fasterxml.jackson.annotation.JsonIgnore; |
||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||
|
import org.thingsboard.server.common.data.EntityType; |
||||
|
|
||||
|
import java.util.UUID; |
||||
|
|
||||
|
public class FirmwareId extends UUIDBased implements EntityId { |
||||
|
|
||||
|
private static final long serialVersionUID = 1L; |
||||
|
|
||||
|
@JsonCreator |
||||
|
public FirmwareId(@JsonProperty("id") UUID id) { |
||||
|
super(id); |
||||
|
} |
||||
|
|
||||
|
public static FirmwareId fromString(String firmwareId) { |
||||
|
return new FirmwareId(UUID.fromString(firmwareId)); |
||||
|
} |
||||
|
|
||||
|
@JsonIgnore |
||||
|
@Override |
||||
|
public EntityType getEntityType() { |
||||
|
return EntityType.FIRMWARE; |
||||
|
} |
||||
|
|
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue