From f7af8e298ccf8eb82093172ed581bc5f5136914f Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 7 Dec 2023 17:41:29 +0200 Subject: [PATCH] added fixes after review --- .../install/SqlDatabaseUpgradeService.java | 4 + .../org/thingsboard/server/dao/DaoUtil.java | 24 ++--- .../dao/asset/AssetProfileServiceImpl.java | 6 +- .../server/dao/asset/BaseAssetService.java | 15 ++- .../dao/device/DeviceProfileServiceImpl.java | 6 +- .../server/dao/device/DeviceServiceImpl.java | 7 +- .../dao/sql/asset/AssetProfileRepository.java | 5 +- .../sql/device/DeviceProfileRepository.java | 5 +- .../resources/sql/schema-entities-idx.sql | 2 + .../dao/service/AssetProfileServiceTest.java | 97 +++++++++++++++++++ .../dao/service/DeviceProfileServiceTest.java | 94 ++++++++++++++++++ 11 files changed, 223 insertions(+), 42 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index f404edb8b1..c2444390f6 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -766,6 +766,10 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService } catch (Exception e) { log.warn("Failed to execute update script for save attributes rule nodes due to: ", e); } + try { + connection.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_asset_profile_id ON asset(tenant_id, asset_profile_id);"); + } catch (Exception e) { + } }); break; default: diff --git a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java index e7c2c9d42d..1d9b276f65 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java @@ -153,28 +153,24 @@ public abstract class DaoUtil { } } - public static List convertTenantEntityTypesToDto(UUID tenantId, EntityType entityType, List types) { + public static List convertTenantEntityTypesToDto(UUID tenantUUID, EntityType entityType, List types) { if (CollectionUtils.isEmpty(types)) { return Collections.emptyList(); } - - List list = new ArrayList<>(types.size()); - for (String type : types) { - list.add(new EntitySubtype(TenantId.fromUUID(tenantId), entityType, type)); - } - return list; + TenantId tenantId = TenantId.fromUUID(tenantUUID); + return types.stream() + .map(type -> new EntitySubtype(tenantId, entityType, type)) + .collect(Collectors.toList()); } - public static List convertTenantEntityInfosToDto(UUID tenantId, EntityType entityType, List entityInfos) { + public static List convertTenantEntityInfosToDto(UUID tenantUUID, EntityType entityType, List entityInfos) { if (CollectionUtils.isEmpty(entityInfos)) { return Collections.emptyList(); } - - List list = new ArrayList<>(entityInfos.size()); - for (var info : entityInfos) { - list.add(new EntitySubtype(TenantId.fromUUID(tenantId), entityType, info.getName())); - } - return list; + var tenantId = TenantId.fromUUID(tenantUUID); + return entityInfos.stream() + .map(info -> new EntitySubtype(tenantId, entityType, info.getName())) + .collect(Collectors.toList()); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index 0b9e949c7c..a46978bec1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -43,11 +43,9 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -325,9 +323,7 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService findAssetProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) { log.trace("Executing findAssetProfileNamesByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - return assetProfileDao.findTenantAssetProfileNames(tenantId.getId(), activeOnly) - .stream().sorted(Comparator.comparing(EntityInfo::getName)) - .collect(Collectors.toList()); + return assetProfileDao.findTenantAssetProfileNames(tenantId.getId(), activeOnly); } private final PaginatedRemover tenantAssetProfilesRemover = diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index 0431b48cea..6de1158cf6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -56,7 +56,6 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -363,7 +362,12 @@ public class BaseAssetService extends AbstractCachedEntityService - assetList == null ? Collections.emptyList() : assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()), MoreExecutors.directExecutor() + assetList == null ? + Collections.emptyList() : + assetList.stream() + .filter(asset -> query.getAssetTypes().contains(asset.getType())) + .collect(Collectors.toList()), + MoreExecutors.directExecutor() ); return assets; } @@ -372,12 +376,7 @@ public class BaseAssetService extends AbstractCachedEntityService> findAssetTypesByTenantId(TenantId tenantId) { log.trace("Executing findAssetTypesByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - ListenableFuture> tenantAssetTypes = assetDao.findTenantAssetTypesAsync(tenantId.getId()); - return Futures.transform(tenantAssetTypes, - assetTypes -> { - assetTypes.sort(Comparator.comparing(EntitySubtype::getType)); - return assetTypes; - }, MoreExecutors.directExecutor()); + return assetDao.findTenantAssetTypesAsync(tenantId.getId()); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 7e3567c888..c67babdab0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -58,13 +58,11 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateString; @@ -380,9 +378,7 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService findDeviceProfileNamesByTenantId(TenantId tenantId, boolean activeOnly) { log.trace("Executing findDeviceProfileNamesByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - return deviceProfileDao.findTenantDeviceProfileNames(tenantId.getId(), activeOnly) - .stream().sorted(Comparator.comparing(EntityInfo::getName)) - .collect(Collectors.toList()); + return deviceProfileDao.findTenantDeviceProfileNames(tenantId.getId(), activeOnly); } private final PaginatedRemover tenantDeviceProfilesRemover = diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index cfc30ccd8f..fcedc94c9c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -486,12 +486,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService> findDeviceTypesByTenantId(TenantId tenantId) { log.trace("Executing findDeviceTypesByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - ListenableFuture> tenantDeviceTypes = deviceDao.findTenantDeviceTypesAsync(tenantId.getId()); - return Futures.transform(tenantDeviceTypes, - deviceTypes -> { - deviceTypes.sort(Comparator.comparing(EntitySubtype::getType)); - return deviceTypes; - }, MoreExecutors.directExecutor()); + return deviceDao.findTenantDeviceTypesAsync(tenantId.getId()); } @Transactional diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java index 08ea3c0872..faf4510879 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetProfileRepository.java @@ -73,11 +73,12 @@ public interface AssetProfileRepository extends JpaRepository findAllByImageNotNull(Pageable pageable); @Query("SELECT new org.thingsboard.server.common.data.EntityInfo(ap.id, 'ASSET_PROFILE', ap.name) " + - "FROM AssetProfileEntity ap WHERE ap.tenantId = :tenantId AND EXISTS (SELECT 1 FROM AssetEntity a WHERE a.tenantId = :tenantId AND a.assetProfileId = ap.id)") + "FROM AssetProfileEntity ap WHERE ap.tenantId = :tenantId AND EXISTS " + + "(SELECT 1 FROM AssetEntity a WHERE a.tenantId = :tenantId AND a.assetProfileId = ap.id) ORDER BY ap.name ASC") List findActiveTenantAssetProfileNames(@Param("tenantId") UUID tenantId); @Query("SELECT new org.thingsboard.server.common.data.EntityInfo(a.id, 'ASSET_PROFILE', a.name) " + - "FROM AssetProfileEntity a WHERE a.tenantId = :tenantId") + "FROM AssetProfileEntity a WHERE a.tenantId = :tenantId ORDER BY a.name ASC") List findAllTenantAssetProfileNames(@Param("tenantId") UUID tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java index 2093404bb0..cc50b06e6e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/device/DeviceProfileRepository.java @@ -84,11 +84,12 @@ public interface DeviceProfileRepository extends JpaRepository findAllByImageNotNull(Pageable pageable); @Query("SELECT new org.thingsboard.server.common.data.EntityInfo(dp.id, 'DEVICE_PROFILE', dp.name) " + - "FROM DeviceProfileEntity dp WHERE dp.tenantId = :tenantId AND EXISTS (SELECT 1 FROM DeviceEntity dv WHERE dv.tenantId = :tenantId AND dv.deviceProfileId = dp.id)") + "FROM DeviceProfileEntity dp WHERE dp.tenantId = :tenantId AND EXISTS " + + "(SELECT 1 FROM DeviceEntity dv WHERE dv.tenantId = :tenantId AND dv.deviceProfileId = dp.id) ORDER BY dp.name ASC") List findActiveTenantDeviceProfileNames(@Param("tenantId") UUID tenantId); @Query("SELECT new org.thingsboard.server.common.data.EntityInfo(d.id, 'DEVICE_PROFILE', d.name) " + - "FROM DeviceProfileEntity d WHERE d.tenantId = :tenantId") + "FROM DeviceProfileEntity d WHERE d.tenantId = :tenantId ORDER BY d.name ASC") List findAllTenantDeviceProfileNames(@Param("tenantId") UUID tenantId); } diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 472c0f601e..91f3eff713 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -57,6 +57,8 @@ CREATE INDEX IF NOT EXISTS idx_asset_customer_id_and_type ON asset(tenant_id, cu CREATE INDEX IF NOT EXISTS idx_asset_type ON asset(tenant_id, type); +CREATE INDEX IF NOT EXISTS idx_asset_profile_id ON asset(tenant_id, asset_profile_id); + CREATE INDEX IF NOT EXISTS idx_attribute_kv_by_key_and_last_update_ts ON attribute_kv(entity_id, attribute_key, last_update_ts desc); CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_id_and_created_time ON audit_log(tenant_id, created_time DESC); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java index 391c00fa49..0d6f0d8075 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AssetProfileServiceTest.java @@ -24,6 +24,7 @@ import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfileInfo; @@ -35,11 +36,14 @@ import org.thingsboard.server.dao.exception.DataValidationException; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.stream.Collectors; +import static org.assertj.core.api.Assertions.assertThat; + @DaoSqlTest public class AssetProfileServiceTest extends AbstractServiceTest { @@ -272,4 +276,97 @@ public class AssetProfileServiceTest extends AbstractServiceTest { Assert.assertEquals(1, pageData.getTotalElements()); } + @Test + public void testFindAllassetProfilesByTenantId() { + int assetProfilesCount = 4; // 3 created + default + var assetProfiles = new ArrayList(4); + + var profileC = assetProfileService.saveAssetProfile( + createAssetProfile(tenantId, "profile C")); + assetProfiles.add(assetProfileService.saveAssetProfile(profileC)); + + + var profileA = assetProfileService.saveAssetProfile( + createAssetProfile(tenantId, "profile A")); + assetProfiles.add(assetProfileService.saveAssetProfile(profileA)); + + + var profileB = assetProfileService.saveAssetProfile( + createAssetProfile(tenantId, "profile B")); + assetProfiles.add(assetProfileService.saveAssetProfile(profileB)); + + + assetProfiles.add(assetProfileService.findDefaultAssetProfile(tenantId)); + + List sortedProfileInfos = assetProfiles.stream() + .map(profile -> new EntityInfo(profile.getId(), profile.getName())) + .sorted(Comparator.comparing(EntityInfo::getName)) + .collect(Collectors.toList()); + + var assetProfileInfos = assetProfileService + .findAssetProfileNamesByTenantId(tenantId, false); + + assertThat(assetProfileInfos).isNotNull(); + assertThat(assetProfileInfos).hasSize(assetProfilesCount); + assertThat(assetProfileInfos).isEqualTo(sortedProfileInfos); + } + + @Test + public void testFindActiveOnlyassetProfilesByTenantId() { + + String profileCName = "profile C"; + assetProfileService.saveAssetProfile( + createAssetProfile(tenantId, profileCName)); + + String profileAName = "profile A"; + assetProfileService.saveAssetProfile( + createAssetProfile(tenantId, profileAName)); + + String profileBName = "profile B"; + assetProfileService.saveAssetProfile( + createAssetProfile(tenantId, profileBName)); + + + var assetProfileInfos = assetProfileService + .findAssetProfileNamesByTenantId(tenantId, true); + + assertThat(assetProfileInfos).isNotNull(); + assertThat(assetProfileInfos).isEmpty(); + + var assetC = new Asset(); + assetC.setName("Test asset C"); + assetC.setType(profileCName); + assetC.setTenantId(tenantId); + + assetC = assetService.saveAsset(assetC); + + var assetA = new Asset(); + assetA.setName("Test asset A"); + assetA.setType(profileAName); + assetA.setTenantId(tenantId); + + assetA = assetService.saveAsset(assetA); + + var assetB = new Asset(); + assetB.setName("Test asset B"); + assetB.setType(profileBName); + assetB.setTenantId(tenantId); + + assetB = assetService.saveAsset(assetB); + + assetProfileInfos = assetProfileService + .findAssetProfileNamesByTenantId(tenantId, true); + + var expected = List.of( + new EntityInfo(assetA.getAssetProfileId(), profileAName), + new EntityInfo(assetB.getAssetProfileId(), profileBName), + new EntityInfo(assetC.getAssetProfileId(), profileCName) + ); + + assertThat(assetProfileInfos).isNotEmpty(); + assertThat(assetProfileInfos).hasSize(3); + assertThat(assetProfileInfos).isEqualTo(expected); + } + + } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java index 16a80e438d..ac3b603f13 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/DeviceProfileServiceTest.java @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.page.PageData; @@ -41,6 +42,7 @@ import org.thingsboard.server.dao.ota.OtaPackageService; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; @@ -372,4 +374,96 @@ public class DeviceProfileServiceTest extends AbstractServiceTest { Assert.assertEquals(1, pageData.getTotalElements()); } + @Test + public void testFindAllDeviceProfilesByTenantId() { + int deviceProfilesCount = 4; // 3 created + default + var deviceProfiles = new ArrayList(4); + + var profileC = deviceProfileService.saveDeviceProfile( + createDeviceProfile(tenantId, "profile C")); + deviceProfiles.add(deviceProfileService.saveDeviceProfile(profileC)); + + + var profileA = deviceProfileService.saveDeviceProfile( + createDeviceProfile(tenantId, "profile A")); + deviceProfiles.add(deviceProfileService.saveDeviceProfile(profileA)); + + + var profileB = deviceProfileService.saveDeviceProfile( + createDeviceProfile(tenantId, "profile B")); + deviceProfiles.add(deviceProfileService.saveDeviceProfile(profileB)); + + + deviceProfiles.add(deviceProfileService.findDefaultDeviceProfile(tenantId)); + + List sortedProfileInfos = deviceProfiles.stream() + .map(profile -> new EntityInfo(profile.getId(), profile.getName())) + .sorted(Comparator.comparing(EntityInfo::getName)) + .collect(Collectors.toList()); + + var deviceProfileInfos = deviceProfileService + .findDeviceProfileNamesByTenantId(tenantId, false); + + assertThat(deviceProfileInfos).isNotNull(); + assertThat(deviceProfileInfos).hasSize(deviceProfilesCount); + assertThat(deviceProfileInfos).isEqualTo(sortedProfileInfos); + } + + @Test + public void testFindActiveOnlyDeviceProfilesByTenantId() { + + String profileCName = "profile C"; + deviceProfileService.saveDeviceProfile( + createDeviceProfile(tenantId, profileCName)); + + String profileAName = "profile A"; + deviceProfileService.saveDeviceProfile( + createDeviceProfile(tenantId, profileAName)); + + String profileBName = "profile B"; + deviceProfileService.saveDeviceProfile( + createDeviceProfile(tenantId, profileBName)); + + + var deviceProfileInfos = deviceProfileService + .findDeviceProfileNamesByTenantId(tenantId, true); + + assertThat(deviceProfileInfos).isNotNull(); + assertThat(deviceProfileInfos).isEmpty(); + + var deviceC = new Device(); + deviceC.setName("Test Device C"); + deviceC.setType(profileCName); + deviceC.setTenantId(tenantId); + + deviceC = deviceService.saveDevice(deviceC); + + var deviceA = new Device(); + deviceA.setName("Test Device A"); + deviceA.setType(profileAName); + deviceA.setTenantId(tenantId); + + deviceA = deviceService.saveDevice(deviceA); + + var deviceB = new Device(); + deviceB.setName("Test Device B"); + deviceB.setType(profileBName); + deviceB.setTenantId(tenantId); + + deviceB = deviceService.saveDevice(deviceB); + + deviceProfileInfos = deviceProfileService + .findDeviceProfileNamesByTenantId(tenantId, true); + + var expected = List.of( + new EntityInfo(deviceA.getDeviceProfileId(), profileAName), + new EntityInfo(deviceB.getDeviceProfileId(), profileBName), + new EntityInfo(deviceC.getDeviceProfileId(), profileCName) + ); + + assertThat(deviceProfileInfos).isNotEmpty(); + assertThat(deviceProfileInfos).hasSize(3); + assertThat(deviceProfileInfos).isEqualTo(expected); + } + }