Browse Source

firmware

pull/7062/head
AnastasiiaKomar 4 years ago
parent
commit
b047ccfd7e
  1. 76
      application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
  2. 18
      application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java
  3. 7
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  4. 4
      common/cache/pom.xml
  5. 163
      common/cache/src/main/java/org/thingsboard/server/cache/ota/service/FileCacheService.java
  6. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java
  7. 3
      common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java
  8. 7
      dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java
  9. 79
      dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java
  10. 21
      dao/src/main/java/org/thingsboard/server/dao/service/validator/OtaPackageDataValidator.java

76
application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java

@ -17,9 +17,11 @@ package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ByteArrayResource;
import org.hibernate.engine.jdbc.BlobProxy;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
@ -39,15 +41,20 @@ import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
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.cache.ota.service.FileCacheService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.nio.ByteBuffer;
import javax.transaction.Transactional;
import java.io.InputStream;
import java.sql.Blob;
import java.util.UUID;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES;
@ -69,32 +76,35 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@Slf4j
@RestController
@TbCoreComponent
@RequiredArgsConstructor
@RequestMapping("/api")
public class OtaPackageController extends BaseController {
public static final String OTA_PACKAGE_ID = "otaPackageId";
public static final String CHECKSUM_ALGORITHM = "checksumAlgorithm";
private final FileCacheService fileCacheService;
@ApiOperation(value = "Download OTA Package (downloadOtaPackage)", notes = "Download OTA Package based on the provided OTA Package Id." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority( 'TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}/download", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<org.springframework.core.io.Resource> downloadOtaPackage(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@Transactional
public ResponseEntity<InputStreamResource> downloadOtaPackage(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackage otaPackage = checkOtaPackageId(otaPackageId, Operation.READ);
// OtaPackage otaPackage = checkOtaPackageId(otaPackageId, Operation.READ);
OtaPackage otaPackage = otaPackageService.findOtaPackageById(new TenantId(UUID.fromString("b04858a0-b646-11ec-8d4d-f5c10326c05e")), otaPackageId);
if (otaPackage.hasUrl()) {
return ResponseEntity.badRequest().build();
}
ByteArrayResource resource = new ByteArrayResource(otaPackage.getData().array());
InputStreamResource resource = fileCacheService.getOtaResourceById(new TenantId(UUID.fromString("b04858a0-b646-11ec-8d4d-f5c10326c05e")), otaPackageId);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + otaPackage.getFileName())
.header("x-filename", otaPackage.getFileName())
.contentLength(resource.contentLength())
.contentLength(otaPackage.getDataSize())
.contentType(parseMediaType(otaPackage.getContentType()))
.body(resource);
} catch (Exception e) {
@ -184,32 +194,12 @@ public class OtaPackageController extends BaseController {
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
try {
OtaPackageId otaPackageId = new OtaPackageId(toUUID(strOtaPackageId));
OtaPackageInfo info = checkOtaPackageInfoId(otaPackageId, Operation.READ);
OtaPackage otaPackage = new OtaPackage(otaPackageId);
otaPackage.setCreatedTime(info.getCreatedTime());
otaPackage.setTenantId(getTenantId());
otaPackage.setDeviceProfileId(info.getDeviceProfileId());
otaPackage.setType(info.getType());
otaPackage.setTitle(info.getTitle());
otaPackage.setVersion(info.getVersion());
otaPackage.setTag(info.getTag());
otaPackage.setAdditionalInfo(info.getAdditionalInfo());
ChecksumAlgorithm checksumAlgorithm = ChecksumAlgorithm.valueOf(checksumAlgorithmStr.toUpperCase());
byte[] bytes = file.getBytes();
if (StringUtils.isEmpty(checksum)) {
checksum = otaPackageService.generateChecksum(checksumAlgorithm, ByteBuffer.wrap(bytes));
checksum = otaPackageService.generateChecksum(checksumAlgorithm, file.getInputStream());
}
otaPackage.setChecksumAlgorithm(checksumAlgorithm);
otaPackage.setChecksum(checksum);
otaPackage.setFileName(file.getOriginalFilename());
otaPackage.setContentType(file.getContentType());
otaPackage.setData(ByteBuffer.wrap(bytes));
otaPackage.setDataSize((long) bytes.length);
OtaPackageInfo savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage);
OtaPackageInfo savedOtaPackage = saveOtaPackageWithData(otaPackageId, file, checksum, checksumAlgorithm);
logEntityAction(savedOtaPackage.getId(), savedOtaPackage, null, ActionType.UPDATED, null);
return savedOtaPackage;
} catch (Exception e) {
@ -218,6 +208,32 @@ public class OtaPackageController extends BaseController {
}
}
private OtaPackage saveOtaPackageWithData(OtaPackageId otaPackageId, MultipartFile file, String checksum, ChecksumAlgorithm checksumAlgorithm) throws ThingsboardException {
OtaPackageInfo info = checkOtaPackageInfoId(otaPackageId, Operation.READ);
OtaPackage otaPackage = new OtaPackage(otaPackageId);
otaPackage.setCreatedTime(info.getCreatedTime());
otaPackage.setTenantId(info.getTenantId());
otaPackage.setDeviceProfileId(info.getDeviceProfileId());
otaPackage.setType(info.getType());
otaPackage.setTitle(info.getTitle());
otaPackage.setVersion(info.getVersion());
otaPackage.setTag(info.getTag());
otaPackage.setAdditionalInfo(info.getAdditionalInfo());
otaPackage.setChecksumAlgorithm(checksumAlgorithm);
otaPackage.setChecksum(checksum);
try(InputStream inputStream = file.getInputStream()) {
otaPackage.setFileName(file.getOriginalFilename());
otaPackage.setContentType(file.getContentType());
otaPackage.setDataSize(file.getSize());
Blob blob = BlobProxy.generateProxy(inputStream, file.getSize());
otaPackage.setData(blob);
return otaPackageService.saveOtaPackage(otaPackage);
} catch (Exception e){
log.error("Failed to save ota package {} with data {}",otaPackageId, file.getName(), e);
return null;
}
}
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,

18
application/src/main/java/org/thingsboard/server/service/action/EntityActionService.java

@ -22,11 +22,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
@ -159,9 +155,15 @@ public class EntityActionService {
}
ObjectNode entityNode;
if (entity != null) {
entityNode = json.valueToTree(entity);
if (entityId.getEntityType() == EntityType.DASHBOARD) {
entityNode.put("configuration", "");
if (entity instanceof OtaPackage) {
OtaPackage otaPackage = (OtaPackage) entity;
otaPackage.setData(null);
entityNode = json.valueToTree(otaPackage); //todo
} else {
entityNode = json.valueToTree(entity);
if (entityId.getEntityType() == EntityType.DASHBOARD) {
entityNode.put("configuration", "");
}
}
} else {
entityNode = json.createObjectNode();

7
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -99,6 +99,7 @@ import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.resource.TbResourceService;
import java.sql.SQLException;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@ -596,7 +597,11 @@ public class DefaultTransportApiService implements TransportApiService {
builder.setContentType(otaPackageInfo.getContentType());
if (!otaPackageDataCache.has(otaPackageId.toString())) {
OtaPackage otaPackage = otaPackageService.findOtaPackageById(tenantId, otaPackageId);
otaPackageDataCache.put(otaPackageId.toString(), otaPackage.getData().array());
try {
otaPackageDataCache.put(otaPackageId.toString(), otaPackage.getData().getBytes(100L, 0));//todo
} catch (SQLException e) {
log.error("ERROR", e); // todo
}
}
}
}

4
common/cache/pom.xml

@ -40,6 +40,10 @@
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>dao-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>

163
common/cache/src/main/java/org/thingsboard/server/cache/ota/service/FileCacheService.java

@ -0,0 +1,163 @@
/**
* Copyright © 2016-2022 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.ota.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.ota.OtaPackageService;
import javax.annotation.PostConstruct;
import java.io.*;
import java.sql.Blob;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
@Component
public class FileCacheService {
private final static String PATH = "files/%s";
private final static String FILE_NAME_TEMPLATE = "%s.tmp";
private final static long TEMPORARY_FILE_INACTIVITY_TIME = 300;
private final ConcurrentMap<OtaPackageId, CountDownLatch> files = new ConcurrentHashMap<>();
private final ConcurrentMap<OtaPackageId, Long> lastActivityTimes = new ConcurrentHashMap<>();
private final OtaPackageService otaPackageService;
private void deleteUnusedTemporaryFiles() {
long currentTime = System.currentTimeMillis();
List<OtaPackageId> toBeDeleted = lastActivityTimes.entrySet()
.stream()
.filter(entry -> currentTime - entry.getValue() > TEMPORARY_FILE_INACTIVITY_TIME)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
try {
toBeDeleted.forEach(otaId -> {
deleteFile(otaId.getId().toString());
lastActivityTimes.remove(otaId);
});
}catch (Exception e){
log.error(",,", e);
}
log.info("Deleted {} unused temporary files", toBeDeleted.size());
}
private void deleteFile(String otaId) {
if (exist(otaId)) {
String fileName = String.format(FILE_NAME_TEMPLATE, otaId);
File file = new File(String.format(PATH, fileName));
file.delete();
}
}
private void cleanDirectoryWithTemporaryFiles() {
File directory = new File(String.format(PATH, ""));
if (directory.isDirectory()) {
try {
FileUtils.cleanDirectory(directory);
log.info("Directory with temporary files cleaned");
} catch (IOException e) {
log.error("Failed to clean directory with temporary files", e);
throw new RuntimeException(e);
}
}
}
@PostConstruct
private void createScheduledTaskToClear() {
cleanDirectoryWithTemporaryFiles();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(this::deleteUnusedTemporaryFiles, 3, 3, TimeUnit.MINUTES);
}
public InputStreamResource getOtaResourceById(TenantId tenantId, OtaPackageId otaPackageId) {
try {
String fileName = String.format(FILE_NAME_TEMPLATE, otaPackageId.getId().toString());
if (exist(fileName)) {
lastActivityTimes.put(otaPackageId, System.currentTimeMillis());
return new InputStreamResource(new FileInputStream(String.format(PATH, fileName)));
}
InputStreamResource resource = load(tenantId, otaPackageId);
lastActivityTimes.put(otaPackageId, System.currentTimeMillis());
files.remove(otaPackageId);
return resource;
} catch (FileNotFoundException e) {
log.error("Failed to find resource for otaPackage {}", otaPackageId, e);
throw new RuntimeException(e);
}
}
private InputStreamResource load(TenantId tenantId, OtaPackageId otaPackageId) throws FileNotFoundException {
CountDownLatch latch = files.computeIfAbsent(otaPackageId, ota -> processFileSaving(tenantId, ota));
String fileName = String.format(FILE_NAME_TEMPLATE, otaPackageId.getId().toString());
if (latch.getCount() == 0) {
return new InputStreamResource(new FileInputStream(String.format(PATH, fileName)));
} else {
try {
latch.await();
return new InputStreamResource(new FileInputStream(String.format(PATH, fileName)));
} catch (InterruptedException e) {
log.error("Failed to save file {} to file system", fileName, e);
throw new RuntimeException(e);
}
}
}
private CountDownLatch processFileSaving(TenantId tenantId, OtaPackageId otaPackageId) {
CountDownLatch latch = new CountDownLatch(1);
OtaPackage otaPackage = otaPackageService.findOtaPackageById(tenantId, otaPackageId);
if (otaPackage == null) {
latch.countDown();
log.error("Can't find otaPackage to download file {}", otaPackage);
throw new RuntimeException("No such OtaPackageId");
}
try {
Blob data = otaPackage.getData();
InputStream binaryStream = data.getBinaryStream();
String fileName = String.format(FILE_NAME_TEMPLATE, otaPackageId.getId().toString());
saveAsSystemFile(fileName, binaryStream);
latch.countDown();
return latch;
} catch (SQLException e) {
log.error("Failed to get binary data from otaPackage {}", otaPackageId, e);
throw new RuntimeException("Failed to get binary data from database");
}
}
private void saveAsSystemFile(String fileName, InputStream inputStream) {
try {
File file = new File(String.format(PATH, fileName));
FileUtils.copyInputStreamToFile(inputStream, file);
} catch (IOException e) {
log.error("Failed to copy stream to system file {}", fileName, e);
throw new RuntimeException("Failed to save file");
}
}
private boolean exist(String name) {
File file = new File(String.format(PATH, name));
return file.exists();
}
}

2
common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java

@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import java.io.InputStream;
import java.nio.ByteBuffer;
public interface OtaPackageService {
@ -51,4 +52,5 @@ public interface OtaPackageService {
void deleteOtaPackagesByTenantId(TenantId tenantId);
long sumDataSizeByTenantId(TenantId tenantId);
String generateChecksum(ChecksumAlgorithm checksumAlgorithm, InputStream fileData);
}

3
common/data/src/main/java/org/thingsboard/server/common/data/OtaPackage.java

@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.id.OtaPackageId;
import java.nio.ByteBuffer;
import java.sql.Blob;
@ApiModel
@Data
@ -31,7 +32,7 @@ public class OtaPackage extends OtaPackageInfo {
private static final long serialVersionUID = 3091601761339422546L;
@ApiModelProperty(position = 16, value = "OTA Package data.", readOnly = true)
private transient ByteBuffer data;
private transient Blob data;
public OtaPackage() {
super();

7
dao/src/main/java/org/thingsboard/server/dao/model/sql/OtaPackageEntity.java

@ -38,6 +38,7 @@ import javax.persistence.Enumerated;
import javax.persistence.Lob;
import javax.persistence.Table;
import java.nio.ByteBuffer;
import java.sql.Blob;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_COLUMN;
@ -100,7 +101,7 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc
@Lob
@Column(name = OTA_PACKAGE_DATA_COLUMN, columnDefinition = "BINARY")
private byte[] data;
private Blob data;
@Column(name = OTA_PACKAGE_DATA_SIZE_COLUMN)
private Long dataSize;
@ -132,7 +133,7 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc
this.contentType = otaPackage.getContentType();
this.checksumAlgorithm = otaPackage.getChecksumAlgorithm();
this.checksum = otaPackage.getChecksum();
this.data = otaPackage.getData().array();
this.data = otaPackage.getData();
this.dataSize = otaPackage.getDataSize();
this.additionalInfo = otaPackage.getAdditionalInfo();
}
@ -166,7 +167,7 @@ public class OtaPackageEntity extends BaseSqlEntity<OtaPackage> implements Searc
otaPackage.setChecksum(checksum);
otaPackage.setDataSize(dataSize);
if (data != null) {
otaPackage.setData(ByteBuffer.wrap(data));
otaPackage.setData(data);
otaPackage.setHasData(true);
}
otaPackage.setAdditionalInfo(additionalInfo);

79
dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java

@ -20,6 +20,8 @@ import com.google.common.hash.Hashing;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.hibernate.engine.jdbc.BlobProxy;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
@ -40,10 +42,15 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import java.io.*;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.thingsboard.server.common.data.CacheConstants.OTA_PACKAGE_CACHE;
import static org.thingsboard.server.dao.service.Validator.validateId;
@ -56,6 +63,8 @@ public class BaseOtaPackageService implements OtaPackageService {
public static final String INCORRECT_OTA_PACKAGE_ID = "Incorrect otaPackageId ";
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
private static final int ONE_MEGA_BYTE = 1_000_000;
private final OtaPackageDao otaPackageDao;
private final OtaPackageInfoDao otaPackageInfoDao;
private final CacheManager cacheManager;
@ -91,15 +100,28 @@ public class BaseOtaPackageService implements OtaPackageService {
@Override
public OtaPackage saveOtaPackage(OtaPackage otaPackage) {
log.trace("Executing saveOtaPackage [{}]", otaPackage);
otaPackageValidator.validate(otaPackage, OtaPackageInfo::getTenantId);
try {
File tempFile = saveDataToTemporaryFile(otaPackage.getData().getBinaryStream());
otaPackage.setData(BlobProxy.generateProxy(new FileInputStream(tempFile), otaPackage.getDataSize()));
try {
otaPackageValidator.validate(otaPackage, OtaPackageInfo::getTenantId);
}catch (RuntimeException e){
deleteTempFile(tempFile);
throw e;
}
otaPackage.setData(BlobProxy.generateProxy(new FileInputStream(tempFile), otaPackage.getDataSize()));
OtaPackageId otaPackageId = otaPackage.getId();
if (otaPackageId != null) {
Cache cache = cacheManager.getCache(OTA_PACKAGE_CACHE);
cache.evict(toOtaPackageInfoKey(otaPackageId));
otaPackageDataCache.evict(otaPackageId.toString());
}
return otaPackageDao.save(otaPackage.getTenantId(), otaPackage);
OtaPackage save = otaPackageDao.save(otaPackage.getTenantId(), otaPackage);
deleteTempFile(tempFile);
return save;
} catch (FileNotFoundException | SQLException e){
log.error("Failed to validate ota package {}",otaPackage.getId(), e);
throw new RuntimeException(e);
} catch (Exception t) {
ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("ota_package_tenant_title_version_unq_key")) {
@ -110,6 +132,30 @@ public class BaseOtaPackageService implements OtaPackageService {
}
}
public void deleteTempFile(File file) {
try {
if(file.exists()) {
FileUtils.delete(file);
log.info("System file {} was deleted", file.getName());
}
} catch (IOException e) {
log.error("Failed to delete file {}", file.getName(), e);
}
}
public File saveDataToTemporaryFile(InputStream inputStream){
File path = new File("files/");
try {
File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp", path);
FileUtils.copyInputStreamToFile(inputStream, tempFile);
return tempFile;
}catch (IOException e){
log.error("Failed to create temp file", e);
throw new RuntimeException("Failed to create temp file for input stream");
}
}
@Override
public String generateChecksum(ChecksumAlgorithm checksumAlgorithm, ByteBuffer data) {
if (data == null || !data.hasArray() || data.array().length == 0) {
@ -244,4 +290,33 @@ public class BaseOtaPackageService implements OtaPackageService {
return Collections.singletonList(otaPackageId);
}
public String generateChecksum(ChecksumAlgorithm checksumAlgorithm, InputStream fileData) {
try {
MessageDigest md = MessageDigest.getInstance(checksumAlgorithm.name());
return checksum(fileData, md);
} catch (NoSuchAlgorithmException e) {
log.error("No such checksum algorithm {}", checksumAlgorithm, e);
throw new RuntimeException(e);
} catch (IOException e) {
log.error("Failed to calculate checksum", e);
throw new RuntimeException(e);
} catch (Exception e) {
log.error("ff", e);
throw new RuntimeException(e);
}
}
private String checksum(InputStream inputStream, MessageDigest md) throws IOException {
byte[] buffer = new byte[ONE_MEGA_BYTE];
int count = 0;
while ((count = inputStream.read(buffer)) != -1) {
md.update(buffer, 0, count);
}
StringBuilder result = new StringBuilder();
for (byte b : md.digest()) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}

21
dao/src/main/java/org/thingsboard/server/dao/service/validator/OtaPackageDataValidator.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.dao.service.validator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -27,9 +28,14 @@ import org.thingsboard.server.dao.ota.OtaPackageDao;
import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import java.sql.SQLException;
import static org.thingsboard.server.common.data.EntityType.OTA_PACKAGE;
@Component
@Slf4j
public class OtaPackageDataValidator extends BaseOtaPackageDataValidator<OtaPackage> {
@Autowired
@ -70,13 +76,14 @@ public class OtaPackageDataValidator extends BaseOtaPackageDataValidator<OtaPack
if (StringUtils.isEmpty(otaPackage.getChecksum())) {
throw new DataValidationException("OtaPackage checksum should be specified!");
}
String currentChecksum;
currentChecksum = otaPackageService.generateChecksum(otaPackage.getChecksumAlgorithm(), otaPackage.getData());
if (!currentChecksum.equals(otaPackage.getChecksum())) {
throw new DataValidationException("Wrong otaPackage file!");
try {
String currentChecksum = otaPackageService.generateChecksum(otaPackage.getChecksumAlgorithm(), otaPackage.getData().getBinaryStream());
if (!currentChecksum.equals(otaPackage.getChecksum())) {
throw new DataValidationException("Wrong otaPackage file!");
}
}catch (SQLException e){
log.error("Failed to check ota package data {}",otaPackage.getId(), e);
throw new RuntimeException("otaPackage file can't be validated");
}
} else {
if (otaPackage.getData() != null) {

Loading…
Cancel
Save