From 653a1225aa92c50c3ef850bc6ccd7ddab71c9af3 Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 12 Jan 2022 14:57:45 +0200 Subject: [PATCH 01/41] refactor services to use tenantService.getTenantById instead of tenantDao.getById --- .../server/dao/alarm/BaseAlarmService.java | 6 +++--- .../server/dao/asset/BaseAssetService.java | 7 ++++--- .../server/dao/customer/CustomerServiceImpl.java | 9 +++------ .../server/dao/dashboard/DashboardServiceImpl.java | 7 ++++--- .../server/dao/device/DeviceProfileServiceImpl.java | 6 +++--- .../server/dao/device/DeviceServiceImpl.java | 6 +++--- .../server/dao/edge/EdgeServiceImpl.java | 6 +++--- .../server/dao/entity/AbstractEntityService.java | 1 + .../dao/entityview/EntityViewServiceImpl.java | 6 +++--- .../server/dao/ota/BaseOtaPackageService.java | 7 ++++--- .../server/dao/resource/BaseResourceService.java | 11 ++++++----- .../server/dao/rule/BaseRuleChainService.java | 7 ++++--- .../server/dao/tenant/TenantServiceImpl.java | 9 +++++---- .../dao/usagerecord/ApiUsageStateServiceImpl.java | 13 +++++++------ .../server/dao/user/UserServiceImpl.java | 11 ++++++----- .../server/dao/widget/WidgetTypeServiceImpl.java | 7 ++++--- .../server/dao/widget/WidgetsBundleServiceImpl.java | 7 ++++--- 17 files changed, 67 insertions(+), 59 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index eb6d5c778e..e2e1d54935 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -51,7 +51,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import javax.annotation.Nullable; import javax.annotation.PostConstruct; @@ -81,7 +81,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private AlarmDao alarmDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private EntityService entityService; @@ -430,7 +430,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getTenantId() == null) { throw new DataValidationException("Alarm should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(alarm.getTenantId(), alarm.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(alarm.getTenantId()); if (tenant == null) { throw new DataValidationException("Alarm is referencing to non-existent tenant!"); } 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 d88494c6e1..d9f337841b 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 @@ -55,7 +55,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import java.util.ArrayList; import java.util.Arrays; @@ -86,7 +86,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ private AssetDao assetDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private CustomerDao customerDao; @@ -416,7 +416,8 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ if (asset.getTenantId() == null) { throw new DataValidationException("Asset should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(tenantId, asset.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(asset.getTenantId()); + // FIXME: 12.01.22 if (tenant == null) { throw new DataValidationException("Asset is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 89690e5a3b..3b2376f98d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -42,7 +42,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.dao.user.UserService; @@ -66,7 +66,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom private UserService userService; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private AssetService assetService; @@ -74,9 +74,6 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom @Autowired private DeviceService deviceService; - @Autowired - private EntityViewService entityViewService; - @Autowired private DashboardService dashboardService; @@ -213,7 +210,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom if (customer.getTenantId() == null) { throw new DataValidationException("Customer should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(tenantId, customer.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(customer.getTenantId()); if (tenant == null) { throw new DataValidationException("Customer is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index d460fef60b..c2a6813eda 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -45,7 +45,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -62,7 +62,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb private DashboardInfoDao dashboardInfoDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private CustomerDao customerDao; @@ -308,7 +308,8 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb if (dashboard.getTenantId() == null) { throw new DataValidationException("Dashboard should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(tenantId, dashboard.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(dashboard.getTenantId()); + // FIXME: 12.01.22 if (tenant == null) { throw new DataValidationException("Dashboard is referencing to non-existent tenant!"); } 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 18a8a1ecde..254b84889b 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 @@ -81,7 +81,7 @@ import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.queue.QueueService; import java.util.Arrays; @@ -127,7 +127,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D private DeviceService deviceService; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private CacheManager cacheManager; @@ -375,7 +375,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (deviceProfile.getTenantId() == null) { throw new DataValidationException("Device profile should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(deviceProfile.getTenantId(), deviceProfile.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(deviceProfile.getTenantId()); if (tenant == null) { throw new DataValidationException("Device profile is referencing to non-existent tenant!"); } 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 f70d1c1ffe..fbc7f5a23a 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 @@ -81,7 +81,7 @@ import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import javax.annotation.Nullable; import java.util.ArrayList; @@ -117,7 +117,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe private DeviceDao deviceDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private CustomerDao customerDao; @@ -741,7 +741,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe if (device.getTenantId() == null) { throw new DataValidationException("Device should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(device.getTenantId(), device.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(device.getTenantId()); if (tenant == null) { throw new DataValidationException("Device is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index e77e24fb93..281848a68d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -60,7 +60,7 @@ import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserService; import javax.annotation.Nullable; @@ -96,7 +96,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic private EdgeDao edgeDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private CustomerDao customerDao; @@ -413,7 +413,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic if (edge.getTenantId() == null) { throw new DataValidationException("Edge should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(edge.getTenantId(), edge.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(edge.getTenantId()); if (tenant == null) { throw new DataValidationException("Edge is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index 970712fc19..a71c1e8ec6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -40,6 +40,7 @@ public abstract class AbstractEntityService { public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; public static final String INCORRECT_PAGE_LINK = "Incorrect page link "; + @Lazy @Autowired protected RelationService relationService; diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 33ea3d635f..f2aa6423fa 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -52,7 +52,7 @@ import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import javax.annotation.Nullable; import java.util.ArrayList; @@ -87,7 +87,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti private EntityViewDao entityViewDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private CustomerDao customerDao; @@ -432,7 +432,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti if (entityView.getTenantId() == null) { throw new DataValidationException("Entity view should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(tenantId, entityView.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(entityView.getTenantId()); if (tenant == null) { throw new DataValidationException("Entity view is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index 205b2c447b..734c96b1c7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -46,7 +46,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import java.nio.ByteBuffer; import java.util.Collections; @@ -66,7 +66,7 @@ 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 final TenantDao tenantDao; + private final TenantService tenantService; private final DeviceProfileDao deviceProfileDao; private final OtaPackageDao otaPackageDao; private final OtaPackageInfoDao otaPackageInfoDao; @@ -357,7 +357,8 @@ public class BaseOtaPackageService implements OtaPackageService { if (otaPackageInfo.getTenantId() == null) { throw new DataValidationException("OtaPackage should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(otaPackageInfo.getTenantId(), otaPackageInfo.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(otaPackageInfo.getTenantId()); + // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("OtaPackage is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index f442f5acea..d8f8976dcb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -36,7 +36,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import java.util.List; import java.util.Optional; @@ -52,13 +52,13 @@ public class BaseResourceService implements ResourceService { public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId "; private final TbResourceDao resourceDao; private final TbResourceInfoDao resourceInfoDao; - private final TenantDao tenantDao; + private final TenantService tenantService; private final TbTenantProfileCache tenantProfileCache; - public BaseResourceService(TbResourceDao resourceDao, TbResourceInfoDao resourceInfoDao, TenantDao tenantDao, @Lazy TbTenantProfileCache tenantProfileCache) { + public BaseResourceService(TbResourceDao resourceDao, TbResourceInfoDao resourceInfoDao, TenantService tenantService, @Lazy TbTenantProfileCache tenantProfileCache) { this.resourceDao = resourceDao; this.resourceInfoDao = resourceInfoDao; - this.tenantDao = tenantDao; + this.tenantService = tenantService; this.tenantProfileCache = tenantProfileCache; } @@ -183,7 +183,8 @@ public class BaseResourceService implements ResourceService { resource.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantDao.findById(tenantId, resource.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(resource.getTenantId()); + // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Resource is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 6b990a7c6c..f649dc9a0a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -59,7 +59,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import java.util.ArrayList; import java.util.Collection; @@ -94,7 +94,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC private RuleNodeDao ruleNodeDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired @Lazy @@ -726,7 +726,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (ruleChain.getTenantId() == null || ruleChain.getTenantId().isNullUid()) { throw new DataValidationException("Rule chain should be assigned to tenant!"); } - Tenant tenant = tenantDao.findById(tenantId, ruleChain.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(ruleChain.getTenantId()); + // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Rule chain is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 7314f54b39..6f5189b4ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -21,6 +21,8 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.context.annotation.Lazy; +import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; @@ -34,7 +36,6 @@ import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.entity.AbstractEntityService; -import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.resource.ResourceService; @@ -66,6 +67,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe private TenantProfileService tenantProfileService; @Autowired + @Lazy private UserService userService; @Autowired @@ -83,9 +85,6 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Autowired private ApiUsageStateService apiUsageStateService; - @Autowired - private EntityViewService entityViewService; - @Autowired private WidgetsBundleService widgetsBundleService; @@ -126,6 +125,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe } @Override + @Transactional public Tenant saveTenant(Tenant tenant) { log.trace("Executing saveTenant [{}]", tenant); tenant.setRegion(DEFAULT_TENANT_REGION); @@ -143,6 +143,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe } @Override + @Transactional public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index 880f507b44..d9cedb5b77 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfigurat import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.tenant.TenantProfileDao; import org.thingsboard.server.dao.timeseries.TimeseriesService; @@ -52,11 +52,11 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A private final ApiUsageStateDao apiUsageStateDao; private final TenantProfileDao tenantProfileDao; - private final TenantDao tenantDao; + private final TenantService tenantService; private final TimeseriesService tsService; - public ApiUsageStateServiceImpl(TenantDao tenantDao, ApiUsageStateDao apiUsageStateDao, TenantProfileDao tenantProfileDao, TimeseriesService tsService) { - this.tenantDao = tenantDao; + public ApiUsageStateServiceImpl(TenantService tenantService, ApiUsageStateDao apiUsageStateDao, TenantProfileDao tenantProfileDao, TimeseriesService tsService) { + this.tenantService = tenantService; this.apiUsageStateDao = apiUsageStateDao; this.tenantProfileDao = tenantProfileDao; this.tsService = tsService; @@ -114,7 +114,7 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A if (entityId.getEntityType() == EntityType.TENANT && !entityId.equals(TenantId.SYS_TENANT_ID)) { tenantId = (TenantId) entityId; - Tenant tenant = tenantDao.findById(tenantId, tenantId.getId()); + Tenant tenant = tenantService.findTenantById(tenantId); TenantProfile tenantProfile = tenantProfileDao.findById(tenantId, tenant.getTenantProfileId().getId()); TenantProfileConfiguration configuration = tenantProfile.getProfileData().getConfiguration(); @@ -164,7 +164,8 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A if (apiUsageState.getTenantId() == null) { throw new DataValidationException("ApiUsageState should be assigned to tenant!"); } else { - Tenant tenant = tenantDao.findById(requestTenantId, apiUsageState.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(apiUsageState.getTenantId()); + // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null && !requestTenantId.equals(TenantId.SYS_TENANT_ID)) { throw new DataValidationException("ApiUsageState is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 1ed5811ffa..171cb5fbd1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -51,7 +51,7 @@ import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import java.util.HashMap; import java.util.Map; @@ -80,20 +80,20 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private final UserDao userDao; private final UserCredentialsDao userCredentialsDao; - private final TenantDao tenantDao; + private final TenantService tenantService; private final CustomerDao customerDao; private final TbTenantProfileCache tenantProfileCache; private final ApplicationEventPublisher eventPublisher; public UserServiceImpl(UserDao userDao, UserCredentialsDao userCredentialsDao, - TenantDao tenantDao, + @Lazy TenantService tenantService, CustomerDao customerDao, @Lazy TbTenantProfileCache tenantProfileCache, ApplicationEventPublisher eventPublisher) { this.userDao = userDao; this.userCredentialsDao = userCredentialsDao; - this.tenantDao = tenantDao; + this.tenantService = tenantService; this.customerDao = customerDao; this.tenantProfileCache = tenantProfileCache; this.eventPublisher = eventPublisher; @@ -448,7 +448,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic + " already present in database!"); } if (!tenantId.getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantDao.findById(tenantId, user.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(user.getTenantId()); + // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("User is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index d8a8ea3e35..6952f4a7d2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -30,7 +30,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.Validator; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import java.util.List; @@ -44,7 +44,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { private WidgetTypeDao widgetTypeDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private WidgetsBundleDao widgetsBundleService; @@ -138,7 +138,8 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { widgetTypeDetails.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!widgetTypeDetails.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantDao.findById(tenantId, widgetTypeDetails.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(widgetTypeDetails.getTenantId()); + // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Widget type is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 4f7bd93eca..559481df74 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -31,7 +31,7 @@ import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import java.util.ArrayList; import java.util.List; @@ -48,7 +48,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { private WidgetsBundleDao widgetsBundleDao; @Autowired - private TenantDao tenantDao; + private TenantService tenantService; @Autowired private WidgetTypeService widgetTypeService; @@ -162,7 +162,8 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { widgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantDao.findById(tenantId, widgetsBundle.getTenantId().getId()); + Tenant tenant = tenantService.findTenantById(widgetsBundle.getTenantId()); + // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Widgets bundle is referencing to non-existent tenant!"); } From 2a93edbac48e398dfc4fd95a8e6a23f49fbf1552 Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 13 Jan 2022 12:35:01 +0200 Subject: [PATCH 02/41] add cache support for TenantService --- application/src/main/resources/thingsboard.yml | 3 +++ .../org/thingsboard/server/common/data/CacheConstants.java | 1 + .../thingsboard/server/dao/tenant/TenantServiceImpl.java | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index a502afb297..6ff108968d 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -407,6 +407,9 @@ caffeine: tenantProfiles: timeToLiveInMinutes: "${CACHE_SPECS_TENANT_PROFILES_TTL:1440}" maxSize: "${CACHE_SPECS_TENANT_PROFILES_MAX_SIZE:10000}" + tenants: + timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" + maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" deviceProfiles: timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_PROFILES_TTL:1440}" maxSize: "${CACHE_SPECS_DEVICE_PROFILES_MAX_SIZE:10000}" diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index ced7a64a0f..19c2a76561 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -26,6 +26,7 @@ public class CacheConstants { public static final String CLAIM_DEVICES_CACHE = "claimDevices"; public static final String SECURITY_SETTINGS_CACHE = "securitySettings"; public static final String TENANT_PROFILE_CACHE = "tenantProfiles"; + public static final String TENANTS_CACHE = "tenants"; public static final String DEVICE_PROFILE_CACHE = "deviceProfiles"; public static final String ATTRIBUTES_CACHE = "attributes"; public static final String TOKEN_OUTDATAGE_TIME_CACHE = "tokensOutdatageTime"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 6f5189b4ca..47179049a1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -20,6 +20,8 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.context.annotation.Lazy; import org.springframework.transaction.annotation.Transactional; @@ -48,6 +50,7 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.widget.WidgetsBundleService; +import static org.thingsboard.server.common.data.CacheConstants.TENANTS_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; @Service @@ -104,6 +107,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe private RpcService rpcService; @Override + @Cacheable(cacheNames = TENANTS_CACHE, key = "#tenantId", condition = "#tenantId!=null") public Tenant findTenantById(TenantId tenantId) { log.trace("Executing findTenantById [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); @@ -126,6 +130,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional + @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenant.id", condition = "#tenant.id!=null") public Tenant saveTenant(Tenant tenant) { log.trace("Executing saveTenant [{}]", tenant); tenant.setRegion(DEFAULT_TENANT_REGION); @@ -144,6 +149,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional + @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenantId", condition = "#tenantId!=null") public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); From cc84069c683798e85a9d40bf4ea23ffe998cae6f Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 13 Jan 2022 13:42:13 +0200 Subject: [PATCH 03/41] add corresponding tests for caching in TenantService --- .../dao/service/BaseTenantServiceTest.java | 83 ++++++++++++++++++- .../resources/application-test.properties | 3 + 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 29b0558c71..066857f500 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -18,6 +18,12 @@ package org.thingsboard.server.dao.service; import org.apache.commons.lang3.RandomStringUtils; import org.junit.Assert; import org.junit.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; @@ -27,16 +33,26 @@ import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.tenant.TenantDao; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; +import java.util.Objects; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; public abstract class BaseTenantServiceTest extends AbstractServiceTest { private IdComparator idComparator = new IdComparator<>(); + @SpyBean + protected TenantDao tenantDao; + + @Autowired + CacheManager cacheManager; + @Test public void testSaveTenant() { Tenant tenant = new Tenant(); @@ -275,4 +291,69 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTenantProfileId(isolatedTenantProfile.getId()); tenantService.saveTenant(tenant); } + + @Test + public void testGettingTenantAddItToCache() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + + Mockito.reset(tenantDao); + Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Tenant cache manager is null").evict(savedTenant.getId()); + + Mockito.verify(tenantDao, Mockito.times(0)).findById(any(), any()); + tenantService.findTenantById(savedTenant.getId()); + Mockito.verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + + Cache.ValueWrapper cachedTenant = + Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedTenant); + + for (int i = 0; i < 100; i++) { + tenantService.findTenantById(savedTenant.getId()); + } + Mockito.verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + + tenantService.deleteTenant(savedTenant.getId()); + } + + @Test + public void testUpdatingExistingTenantEvictCache() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + + Cache.ValueWrapper cachedTenant = + Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); + + savedTenant.setTitle("My new tenant"); + savedTenant = tenantService.saveTenant(savedTenant); + + Mockito.reset(tenantDao); + + cachedTenant = Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); + + Mockito.verify(tenantDao, Mockito.times(0)).findById(any(), any()); + tenantService.findTenantById(savedTenant.getId()); + Mockito.verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + + tenantService.deleteTenant(savedTenant.getId()); + } + + @Test + public void testRemovingTenantEvictCache() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + + Cache.ValueWrapper cachedTenant = + Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); + + tenantService.deleteTenant(savedTenant.getId()); + cachedTenant = Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant); + } } diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index a257c8fbce..4165523701 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -34,6 +34,9 @@ caffeine.specs.claimDevices.maxSize=100000 caffeine.specs.tenantProfiles.timeToLiveInMinutes=1440 caffeine.specs.tenantProfiles.maxSize=100000 +caffeine.specs.tenants.timeToLiveInMinutes=1440 +caffeine.specs.tenants.maxSize=100000 + caffeine.specs.deviceProfiles.timeToLiveInMinutes=1440 caffeine.specs.deviceProfiles.maxSize=100000 From ba030b07b16805372025433159f871e5b153f821 Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 13 Jan 2022 14:12:59 +0200 Subject: [PATCH 04/41] add todo notes --- .../java/org/thingsboard/server/dao/alarm/BaseAlarmService.java | 1 + .../java/org/thingsboard/server/dao/asset/BaseAssetService.java | 2 +- .../thingsboard/server/dao/customer/CustomerServiceImpl.java | 1 + .../thingsboard/server/dao/dashboard/DashboardServiceImpl.java | 2 +- .../thingsboard/server/dao/device/DeviceProfileServiceImpl.java | 1 + .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 1 + .../java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java | 1 + .../server/dao/entityview/EntityViewServiceImpl.java | 1 + 8 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index e2e1d54935..e6df02c854 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -431,6 +431,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ throw new DataValidationException("Alarm should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(alarm.getTenantId()); + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Alarm is referencing to non-existent tenant!"); } 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 d9f337841b..94477635af 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 @@ -417,7 +417,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ throw new DataValidationException("Asset should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(asset.getTenantId()); - // FIXME: 12.01.22 + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Asset is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 3b2376f98d..f8726e9d16 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -211,6 +211,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom throw new DataValidationException("Customer should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(customer.getTenantId()); + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Customer is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index c2a6813eda..aaf5e5d584 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -309,7 +309,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb throw new DataValidationException("Dashboard should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(dashboard.getTenantId()); - // FIXME: 12.01.22 + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Dashboard is referencing to non-existent tenant!"); } 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 254b84889b..b71822907d 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 @@ -376,6 +376,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D throw new DataValidationException("Device profile should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(deviceProfile.getTenantId()); + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Device profile is referencing to non-existent tenant!"); } 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 fbc7f5a23a..0f1f830a4d 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 @@ -742,6 +742,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe throw new DataValidationException("Device should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(device.getTenantId()); + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Device is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 281848a68d..7e9bd64741 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -414,6 +414,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic throw new DataValidationException("Edge should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(edge.getTenantId()); + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Edge is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index f2aa6423fa..7c3d16dd1a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -433,6 +433,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti throw new DataValidationException("Entity view should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(entityView.getTenantId()); + // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Entity view is referencing to non-existent tenant!"); } From 279389bbdfff2180a2b5be8b20fda8b663b33b1f Mon Sep 17 00:00:00 2001 From: desoliture Date: Fri, 14 Jan 2022 16:09:02 +0200 Subject: [PATCH 05/41] refactor async methods used in tenant deletion transaction tenant deleting should be transactional, but some services use async methods, what corrupting transaction execution. Withal most of the refactored methods are using instant .get() after getting future, and it is the same if we use non-async methods. Add non-async methods in interfaces of services and dao and use it for tenant deletion process --- .../dao/entityview/EntityViewService.java | 2 ++ .../server/dao/asset/BaseAssetService.java | 11 +++------- .../server/dao/device/DeviceServiceImpl.java | 22 +++++-------------- .../dao/entity/AbstractEntityService.java | 2 +- .../server/dao/entityview/EntityViewDao.java | 1 + .../dao/entityview/EntityViewServiceImpl.java | 21 ++++++++++++++++++ .../dao/sql/entityview/JpaEntityViewDao.java | 8 +++++++ 7 files changed, 42 insertions(+), 25 deletions(-) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index 832a7822ee..abb79e48fa 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -72,6 +72,8 @@ public interface EntityViewService { ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId); + List findEntityViewsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId); + void deleteEntityView(TenantId tenantId, EntityViewId entityViewId); void deleteEntityViewsByTenantId(TenantId tenantId); 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 94477635af..3e178919f6 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 @@ -168,14 +168,9 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ deleteEntityRelations(tenantId, assetId); Asset asset = assetDao.findById(tenantId, assetId.getId()); - try { - List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(asset.getTenantId(), assetId).get(); - if (entityViews != null && !entityViews.isEmpty()) { - throw new DataValidationException("Can't delete asset that has entity views!"); - } - } catch (ExecutionException | InterruptedException e) { - log.error("Exception while finding entity views for assetId [{}]", assetId, e); - throw new RuntimeException("Exception while finding entity views for assetId [" + assetId + "]", e); + List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(asset.getTenantId(), assetId); + if (entityViews != null && !entityViews.isEmpty()) { + throw new DataValidationException("Can't delete asset that has entity views!"); } removeAssetFromCacheByName(asset.getTenantId(), asset.getName()); 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 0f1f830a4d..778ee3e789 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 @@ -344,14 +344,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe Device device = deviceDao.findById(tenantId, deviceId.getId()); final String deviceName = device.getName(); - try { - List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get(); - if (entityViews != null && !entityViews.isEmpty()) { - throw new DataValidationException("Can't delete device that has entity views!"); - } - } catch (ExecutionException | InterruptedException e) { - log.error("Exception while finding entity views for deviceId [{}]", deviceId, e); - throw new RuntimeException("Exception while finding entity views for deviceId [" + deviceId + "]", e); + List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(device.getTenantId(), deviceId); + if (entityViews != null && !entityViews.isEmpty()) { + throw new DataValidationException("Can't delete device that has entity views!"); } DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId); @@ -568,14 +563,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe public Device assignDeviceToTenant(TenantId tenantId, Device device) { log.trace("Executing assignDeviceToTenant [{}][{}]", tenantId, device); - try { - List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), device.getId()).get(); - if (!CollectionUtils.isEmpty(entityViews)) { - throw new DataValidationException("Can't assign device that has entity views to another tenant!"); - } - } catch (ExecutionException | InterruptedException e) { - log.error("Exception while finding entity views for deviceId [{}]", device.getId(), e); - throw new RuntimeException("Exception while finding entity views for deviceId [" + device.getId() + "]", e); + List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(device.getTenantId(), device.getId()); + if (!CollectionUtils.isEmpty(entityViews)) { + throw new DataValidationException("Can't assign device that has entity views to another tenant!"); } eventService.removeEvents(device.getTenantId(), device.getId()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index a71c1e8ec6..acb49bb730 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -83,7 +83,7 @@ public abstract class AbstractEntityService { protected void checkAssignedEntityViewsToEdge(TenantId tenantId, EntityId entityId, EdgeId edgeId) { try { - List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId).get(); + List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(tenantId, entityId); if (entityViews != null && !entityViews.isEmpty()) { EntityView entityView = entityViews.get(0); // TODO: @voba - refactor this blocking operation diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java index c4a9e0d871..b7c65e7c8b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java @@ -179,4 +179,5 @@ public interface EntityViewDao extends Dao { String type, PageLink pageLink); + List findEntityViewsByTenantIdAndEntityId(UUID tenantId, UUID entityId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 7c3d16dd1a..30b32e4caf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -302,6 +302,27 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti } } + @Override + public List findEntityViewsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId) { + log.trace("Executing findEntityViewsByTenantIdAndEntityId, tenantId [{}], entityId [{}]", tenantId, entityId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(entityId.getId(), "Incorrect entityId" + entityId); + + List tenantIdAndEntityId = new ArrayList<>(); + tenantIdAndEntityId.add(tenantId); + tenantIdAndEntityId.add(entityId); + + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + List fromCache = cache.get(tenantIdAndEntityId, List.class); + if (fromCache != null) { + return fromCache; + } else { + List result = entityViewDao.findEntityViewsByTenantIdAndEntityId(tenantId.getId(), entityId.getId()); + cache.putIfAbsent(tenantIdAndEntityId, result); + return result; + } + } + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public void deleteEntityView(TenantId tenantId, EntityViewId entityViewId) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index 35f81a860c..676caed2ed 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -200,4 +200,12 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao findEntityViewsByTenantIdAndEntityId(UUID tenantId, UUID entityId) { + return DaoUtil.convertDataList( + entityViewRepository.findAllByTenantIdAndEntityId( + tenantId, entityId) + ); + } } From 3d4503945594427291240a2889a81b02ccf251ae Mon Sep 17 00:00:00 2001 From: desoliture Date: Fri, 14 Jan 2022 18:14:49 +0200 Subject: [PATCH 06/41] add test for tenant deletion method add corresponding test to make sure all related entities are also deleted when tenant is deleted --- .../dao/service/AbstractServiceTest.java | 4 + .../dao/service/BaseTenantServiceTest.java | 289 +++++++++++++++++- 2 files changed, 292 insertions(+), 1 deletion(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index 2d4fd72179..fd497b7c50 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -59,6 +59,7 @@ import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.resource.ResourceService; +import org.thingsboard.server.dao.rpc.RpcService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.tenant.TenantProfileService; @@ -163,6 +164,9 @@ public abstract class AbstractServiceTest { @Autowired protected OtaPackageService otaPackageService; + @Autowired + protected RpcService rpcService; + public class IdComparator implements Comparator { @Override public int compare(D o1, D o2) { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 066857f500..1a716fdac3 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -23,28 +23,70 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.DashboardInfo; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.DeviceProfileType; +import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.OtaPackage; +import org.thingsboard.server.common.data.OtaPackageInfo; +import org.thingsboard.server.common.data.ResourceType; +import org.thingsboard.server.common.data.TbResource; +import org.thingsboard.server.common.data.TbResourceInfo; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.device.profile.DeviceProfileData; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.edge.Edge; +import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.rpc.Rpc; +import org.thingsboard.server.common.data.rpc.RpcStatus; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainType; +import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; +import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.tenant.TenantDao; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Set; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseTenantServiceTest extends AbstractServiceTest { - + + 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 ChecksumAlgorithm CHECKSUM_ALGORITHM = ChecksumAlgorithm.SHA256; + private static final String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; + private static final long DATA_SIZE = 1L; + private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[]{(int) DATA_SIZE}); + private static final String URL = "http://firmware.test.org"; + + private IdComparator idComparator = new IdComparator<>(); @SpyBean @@ -356,4 +398,249 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { cachedTenant = Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant); } + + @Test + public void testDeleteTenantDeletingAllRelatedEntities() throws Exception { + TenantProfile tenantProfile = new TenantProfile(); + tenantProfile.setName("Test tenant profile"); + TenantProfile savedProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + tenant.setTenantProfileId(savedProfile.getId()); + Tenant savedTenant = tenantService.saveTenant(tenant); + + User user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setEmail("tenantAdmin@test.com"); + user.setFirstName("tenantAdmin"); + user.setLastName("tenantAdmin"); + user.setTenantId(savedTenant.getId()); + User savedUser = userService.saveUser(user); + + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer.setTenantId(savedTenant.getId()); + customer.setEmail("testCustomer@test.com"); + Customer savedCustomer = customerService.saveCustomer(customer); + + WidgetsBundle widgetsBundle = new WidgetsBundle(); + widgetsBundle.setTenantId(savedTenant.getId()); + widgetsBundle.setTitle("Test widgets bundle"); + widgetsBundle.setAlias("TestWidgetsBundle"); + widgetsBundle.setDescription("Just a simple widgets bundle"); + WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); + + DeviceProfile deviceProfile = new DeviceProfile(); + deviceProfile.setTenantId(savedTenant.getId()); + deviceProfile.setTransportType(DeviceTransportType.MQTT); + deviceProfile.setName("Test device profile"); + deviceProfile.setType(DeviceProfileType.DEFAULT); + + DeviceProfileData profileData = new DeviceProfileData(); + profileData.setTransportConfiguration(new MqttDeviceProfileTransportConfiguration()); + deviceProfile.setProfileData(profileData); + DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); + + + Device device = new Device(); + device.setCustomerId(savedCustomer.getId()); + device.setTenantId(savedTenant.getId()); + device.setType("Test type"); + device.setName("TestType"); + device.setLabel("Test type"); + device.setDeviceProfileId(savedDeviceProfile.getId()); + Device savedDevice = deviceService.saveDevice(device); + + EntityView entityView = new EntityView(); + entityView.setEntityId(savedDevice.getId()); + entityView.setTenantId(savedTenant.getId()); + entityView.setCustomerId(savedCustomer.getId()); + entityView.setType("Test type"); + entityView.setName("Test entity view"); + entityView.setStartTimeMs(0); + entityView.setEndTimeMs(840000); + EntityView savedEntityView = entityViewService.saveEntityView(entityView); + + Asset asset = new Asset(); + asset.setTenantId(savedTenant.getId()); + asset.setCustomerId(savedCustomer.getId()); + asset.setType("Test asset type"); + asset.setName("Test asset type"); + asset.setLabel("Test asset type"); + Asset savedAsset = assetService.saveAsset(asset); + + Dashboard dashboard = new Dashboard(); + dashboard.setTenantId(savedTenant.getId()); + dashboard.setTitle("Test dashboard"); + dashboard.setAssignedCustomers(Set.of(savedCustomer.toShortCustomerInfo())); + Dashboard savedDashboard = dashboardService.saveDashboard(dashboard); + + RuleChain ruleChain = new RuleChain(); + ruleChain.setTenantId(savedTenant.getId()); + ruleChain.setName("Test rule chain"); + ruleChain.setType(RuleChainType.CORE); + RuleChain savedRuleChain = ruleChainService.saveRuleChain(ruleChain); + + Edge edge = constructEdge(savedTenant.getId(), "Test edge", "Simple"); + Edge savedEdge = edgeService.saveEdge(edge, false); + + OtaPackage otaPackage = createFirmware(savedTenant.getId(), "1", savedDeviceProfile.getId()); + OtaPackage savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage); + + + TbResource resource = new TbResource(); + resource.setTenantId(savedTenant.getId()); + resource.setTitle("Test resource"); + resource.setResourceType(ResourceType.LWM2M_MODEL); + resource.setFileName(FILE_NAME); + resource.setResourceKey("Test resource key"); + resource.setData("Some super test data"); + TbResource savedResource = resourceService.saveResource(resource); + + ApiUsageState defaultApiUsageState = apiUsageStateService + .createDefaultApiUsageState(savedTenant.getId(), savedCustomer.getId()); + + Rpc rpc = new Rpc(); + rpc.setTenantId(savedTenant.getId()); + rpc.setDeviceId(savedDevice.getId()); + rpc.setStatus(RpcStatus.QUEUED); + rpc.setRequest(JacksonUtil.toJsonNode("{}")); + Rpc savedRpc = rpcService.save(rpc); + + + tenantService.deleteTenant(savedTenant.getId()); + + Assert.assertNull(tenantService.findTenantById(savedTenant.getId())); + Assert.assertNull(tenantService.findTenantById(savedTenant.getId())); + Assert.assertNull(customerService.findCustomerById(savedTenant.getId(), savedCustomer.getId())); + + + PageLink pageLinkCustomer = new PageLink(1000); + PageData pageDataCustomer = customerService + .findCustomersByTenantId(savedTenant.getId(), pageLinkCustomer); + Assert.assertFalse(pageDataCustomer.hasNext()); + Assert.assertEquals(0, pageDataCustomer.getTotalElements()); + + + Assert.assertNull( + widgetsBundleService.findWidgetsBundleById(savedTenant.getId(), savedWidgetsBundle.getId()) + ); + List widgetsBundlesByTenantId = + widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(savedTenant.getId()); + Assert.assertTrue(widgetsBundlesByTenantId.isEmpty()); + + + Assert.assertNull(entityViewService.findEntityViewById( + savedTenant.getId(), savedEntityView.getId() + )); + List entityViews = + entityViewService.findEntityViewsByTenantIdAndEntityId( + savedTenant.getId(), savedDevice.getId()); + Assert.assertTrue(entityViews.isEmpty()); + + + Assert.assertNull(assetService.findAssetById( + savedTenant.getId(), savedAsset.getId() + )); + PageLink pageLinkAssets = new PageLink(1000); + PageData assets = + assetService.findAssetsByTenantId(savedTenant.getId(), pageLinkAssets); + Assert.assertFalse(assets.hasNext()); + Assert.assertEquals(0, assets.getTotalElements()); + + + Assert.assertNull(deviceService.findDeviceById( + savedTenant.getId(), savedDevice.getId() + )); + PageLink pageLinkDevices = new PageLink(1000); + PageData devices = + deviceService.findDevicesByTenantId(savedTenant.getId(), pageLinkDevices); + Assert.assertFalse(devices.hasNext()); + Assert.assertEquals(0, devices.getTotalElements()); + + + Assert.assertNull(deviceProfileService.findDeviceProfileById( + savedTenant.getId(), savedDeviceProfile.getId() + )); + PageLink pageLinkDeviceProfiles = new PageLink(1000); + PageData profiles = + deviceProfileService.findDeviceProfiles(savedTenant.getId(), pageLinkDeviceProfiles); + Assert.assertFalse(profiles.hasNext()); + Assert.assertEquals(0, profiles.getTotalElements()); + + + Assert.assertNull(dashboardService.findDashboardById( + savedTenant.getId(), savedDashboard.getId() + )); + PageLink pageLinkDashboards = new PageLink(1000); + PageData dashboards = + dashboardService.findDashboardsByTenantId(savedTenant.getId(), pageLinkDashboards); + Assert.assertFalse(dashboards.hasNext()); + Assert.assertEquals(0, dashboards.getTotalElements()); + + + Assert.assertNull(edgeService.findEdgeById(savedTenant.getId(), savedEdge.getId())); + PageLink pageLinkEdges = new PageLink(1000); + PageData edges = edgeService.findEdgesByTenantId(savedTenant.getId(), pageLinkEdges); + Assert.assertFalse(edges.hasNext()); + Assert.assertEquals(0, edges.getTotalElements()); + + + PageLink pageLinkTenantAdmins = new PageLink(1000); + PageData tenantAdmins = + userService.findTenantAdmins(savedTenant.getId(), pageLinkTenantAdmins); + Assert.assertFalse(tenantAdmins.hasNext()); + Assert.assertEquals(0, tenantAdmins.getTotalElements()); + + + Assert.assertNull(userService.findUserById(savedTenant.getId(), savedUser.getId())); + PageLink pageLinkUsers = new PageLink(1000); + PageData users = + userService.findUsersByTenantId(savedTenant.getId(), pageLinkUsers); + Assert.assertFalse(users.hasNext()); + Assert.assertEquals(0, users.getTotalElements()); + + + Assert.assertNull(ruleChainService.findRuleChainById(savedTenant.getId(), savedRuleChain.getId())); + Assert.assertNull(apiUsageStateService.findTenantApiUsageState(savedTenant.getId())); + + + Assert.assertNull(resourceService.findResourceById(savedTenant.getId(), savedResource.getId())); + PageLink pageLinkResources = new PageLink(1000); + PageData tenantResources = + resourceService.findAllTenantResourcesByTenantId(savedTenant.getId(), pageLinkResources); + Assert.assertFalse(tenantResources.hasNext()); + Assert.assertEquals(0, tenantResources.getTotalElements()); + + + Assert.assertNull( + otaPackageService.findOtaPackageById( + savedTenant.getId(), savedOtaPackage.getId() + ) + ); + PageLink pageLinkOta = new PageLink(1000); + PageData pageDataOta = otaPackageService.findTenantOtaPackagesByTenantId(savedTenant.getId(), pageLinkOta); + Assert.assertFalse(pageDataOta.hasNext()); + Assert.assertEquals(0, pageDataOta.getTotalElements()); + + + Assert.assertNull(rpcService.findById(savedTenant.getId(), savedRpc.getId())); + } + + private OtaPackage createFirmware(TenantId tenantId, String version, DeviceProfileId deviceProfileId) { + OtaPackage firmware = new OtaPackage(); + firmware.setTenantId(tenantId); + firmware.setDeviceProfileId(deviceProfileId); + firmware.setType(FIRMWARE); + firmware.setTitle(TITLE); + firmware.setVersion(version); + firmware.setFileName(FILE_NAME); + firmware.setContentType(CONTENT_TYPE); + firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); + firmware.setChecksum(CHECKSUM); + firmware.setData(DATA); + firmware.setDataSize(DATA_SIZE); + return otaPackageService.saveOtaPackage(firmware); + } } From a0a658c3a4e44fc7a37127549eaef50e462d27a6 Mon Sep 17 00:00:00 2001 From: desoliture Date: Mon, 17 Jan 2022 12:19:05 +0200 Subject: [PATCH 07/41] refactor test for Tenant deletion --- .../dao/service/BaseTenantServiceTest.java | 456 ++++++++++-------- 1 file changed, 251 insertions(+), 205 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 1a716fdac3..7644ee86e7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -24,7 +24,6 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; @@ -76,17 +75,6 @@ import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseTenantServiceTest extends AbstractServiceTest { - 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 ChecksumAlgorithm CHECKSUM_ALGORITHM = ChecksumAlgorithm.SHA256; - private static final String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; - private static final long DATA_SIZE = 1L; - private static final ByteBuffer DATA = ByteBuffer.wrap(new byte[]{(int) DATA_SIZE}); - private static final String URL = "http://firmware.test.org"; - - private IdComparator idComparator = new IdComparator<>(); @SpyBean @@ -401,155 +389,111 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { @Test public void testDeleteTenantDeletingAllRelatedEntities() throws Exception { - TenantProfile tenantProfile = new TenantProfile(); - tenantProfile.setName("Test tenant profile"); - TenantProfile savedProfile = tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); - - Tenant tenant = new Tenant(); - tenant.setTitle("My tenant"); - tenant.setTenantProfileId(savedProfile.getId()); - Tenant savedTenant = tenantService.saveTenant(tenant); - - User user = new User(); - user.setAuthority(Authority.TENANT_ADMIN); - user.setEmail("tenantAdmin@test.com"); - user.setFirstName("tenantAdmin"); - user.setLastName("tenantAdmin"); - user.setTenantId(savedTenant.getId()); - User savedUser = userService.saveUser(user); - - Customer customer = new Customer(); - customer.setTitle("Test customer"); - customer.setTenantId(savedTenant.getId()); - customer.setEmail("testCustomer@test.com"); - Customer savedCustomer = customerService.saveCustomer(customer); - - WidgetsBundle widgetsBundle = new WidgetsBundle(); - widgetsBundle.setTenantId(savedTenant.getId()); - widgetsBundle.setTitle("Test widgets bundle"); - widgetsBundle.setAlias("TestWidgetsBundle"); - widgetsBundle.setDescription("Just a simple widgets bundle"); - WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); - - DeviceProfile deviceProfile = new DeviceProfile(); - deviceProfile.setTenantId(savedTenant.getId()); - deviceProfile.setTransportType(DeviceTransportType.MQTT); - deviceProfile.setName("Test device profile"); - deviceProfile.setType(DeviceProfileType.DEFAULT); - - DeviceProfileData profileData = new DeviceProfileData(); - profileData.setTransportConfiguration(new MqttDeviceProfileTransportConfiguration()); - deviceProfile.setProfileData(profileData); - DeviceProfile savedDeviceProfile = deviceProfileService.saveDeviceProfile(deviceProfile); - - - Device device = new Device(); - device.setCustomerId(savedCustomer.getId()); - device.setTenantId(savedTenant.getId()); - device.setType("Test type"); - device.setName("TestType"); - device.setLabel("Test type"); - device.setDeviceProfileId(savedDeviceProfile.getId()); - Device savedDevice = deviceService.saveDevice(device); - - EntityView entityView = new EntityView(); - entityView.setEntityId(savedDevice.getId()); - entityView.setTenantId(savedTenant.getId()); - entityView.setCustomerId(savedCustomer.getId()); - entityView.setType("Test type"); - entityView.setName("Test entity view"); - entityView.setStartTimeMs(0); - entityView.setEndTimeMs(840000); - EntityView savedEntityView = entityViewService.saveEntityView(entityView); - - Asset asset = new Asset(); - asset.setTenantId(savedTenant.getId()); - asset.setCustomerId(savedCustomer.getId()); - asset.setType("Test asset type"); - asset.setName("Test asset type"); - asset.setLabel("Test asset type"); - Asset savedAsset = assetService.saveAsset(asset); - - Dashboard dashboard = new Dashboard(); - dashboard.setTenantId(savedTenant.getId()); - dashboard.setTitle("Test dashboard"); - dashboard.setAssignedCustomers(Set.of(savedCustomer.toShortCustomerInfo())); - Dashboard savedDashboard = dashboardService.saveDashboard(dashboard); - - RuleChain ruleChain = new RuleChain(); - ruleChain.setTenantId(savedTenant.getId()); - ruleChain.setName("Test rule chain"); - ruleChain.setType(RuleChainType.CORE); - RuleChain savedRuleChain = ruleChainService.saveRuleChain(ruleChain); - - Edge edge = constructEdge(savedTenant.getId(), "Test edge", "Simple"); - Edge savedEdge = edgeService.saveEdge(edge, false); - - OtaPackage otaPackage = createFirmware(savedTenant.getId(), "1", savedDeviceProfile.getId()); - OtaPackage savedOtaPackage = otaPackageService.saveOtaPackage(otaPackage); - - - TbResource resource = new TbResource(); - resource.setTenantId(savedTenant.getId()); - resource.setTitle("Test resource"); - resource.setResourceType(ResourceType.LWM2M_MODEL); - resource.setFileName(FILE_NAME); - resource.setResourceKey("Test resource key"); - resource.setData("Some super test data"); - TbResource savedResource = resourceService.saveResource(resource); - - ApiUsageState defaultApiUsageState = apiUsageStateService - .createDefaultApiUsageState(savedTenant.getId(), savedCustomer.getId()); - - Rpc rpc = new Rpc(); - rpc.setTenantId(savedTenant.getId()); - rpc.setDeviceId(savedDevice.getId()); - rpc.setStatus(RpcStatus.QUEUED); - rpc.setRequest(JacksonUtil.toJsonNode("{}")); - Rpc savedRpc = rpcService.save(rpc); - + TenantProfile savedProfile = createAndSaveTenantProfile(); + Tenant savedTenant = createAndSaveTenant(savedProfile); + User savedUser = createAndSaveUserFor(savedTenant); + Customer savedCustomer = createAndSaveCustomerFor(savedTenant); + WidgetsBundle savedWidgetsBundle = createAndSaveWidgetBundleFor(savedTenant); + DeviceProfile savedDeviceProfile = createAndSaveDeviceProfileWithProfileDataFor(savedTenant); + Device savedDevice = createAndSaveDeviceFor(savedTenant, savedCustomer, savedDeviceProfile); + EntityView savedEntityView = createAndSaveEntityViewFor(savedTenant, savedCustomer, savedDevice); + Asset savedAsset = createAndSaveAssetFor(savedTenant, savedCustomer); + Dashboard savedDashboard = createAndSaveDashboardFor(savedTenant, savedCustomer); + RuleChain savedRuleChain = createAndSaveRuleChainFor(savedTenant); + Edge savedEdge = createAndSaveEdgeFor(savedTenant); + OtaPackage savedOtaPackage = createAndSaveOtaPackageFor(savedTenant, savedDeviceProfile); + TbResource savedResource = createAndSaveResourceFor(savedTenant); + Rpc savedRpc = createAndSaveRpcFor(savedTenant, savedDevice); tenantService.deleteTenant(savedTenant.getId()); Assert.assertNull(tenantService.findTenantById(savedTenant.getId())); - Assert.assertNull(tenantService.findTenantById(savedTenant.getId())); - Assert.assertNull(customerService.findCustomerById(savedTenant.getId(), savedCustomer.getId())); - - - PageLink pageLinkCustomer = new PageLink(1000); - PageData pageDataCustomer = customerService - .findCustomersByTenantId(savedTenant.getId(), pageLinkCustomer); - Assert.assertFalse(pageDataCustomer.hasNext()); - Assert.assertEquals(0, pageDataCustomer.getTotalElements()); - + assertCustomerIsDeleted(savedTenant, savedCustomer); + assertWidgetsBundleIsDeleted(savedTenant, savedWidgetsBundle); + assertEntityViewIsDeleted(savedTenant, savedDevice, savedEntityView); + assertAssetIsDeleted(savedTenant, savedAsset); + assertDeviceIsDeleted(savedTenant, savedDevice); + assertDeviceProfileIsDeleted(savedTenant, savedDeviceProfile); + assertDashboardIsDeleted(savedTenant, savedDashboard); + assertEdgeIsDeletd(savedTenant, savedEdge); + assertTenantAdminIsDeleted(savedTenant); + assertUserIsDeleted(savedTenant, savedUser); + Assert.assertNull(ruleChainService.findRuleChainById(savedTenant.getId(), savedRuleChain.getId())); + Assert.assertNull(apiUsageStateService.findTenantApiUsageState(savedTenant.getId())); + assertResourceIsDeleted(savedTenant, savedResource); + assertOtaPAckageIsDeleted(savedTenant, savedOtaPackage); + Assert.assertNull(rpcService.findById(savedTenant.getId(), savedRpc.getId())); + } + private void assertOtaPAckageIsDeleted(Tenant savedTenant, OtaPackage savedOtaPackage) { Assert.assertNull( - widgetsBundleService.findWidgetsBundleById(savedTenant.getId(), savedWidgetsBundle.getId()) + otaPackageService.findOtaPackageById( + savedTenant.getId(), savedOtaPackage.getId() + ) ); - List widgetsBundlesByTenantId = - widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(savedTenant.getId()); - Assert.assertTrue(widgetsBundlesByTenantId.isEmpty()); + PageLink pageLinkOta = new PageLink(1000); + PageData pageDataOta = otaPackageService.findTenantOtaPackagesByTenantId(savedTenant.getId(), pageLinkOta); + Assert.assertFalse(pageDataOta.hasNext()); + Assert.assertEquals(0, pageDataOta.getTotalElements()); + } + private void assertResourceIsDeleted(Tenant savedTenant, TbResource savedResource) { + Assert.assertNull(resourceService.findResourceById(savedTenant.getId(), savedResource.getId())); + PageLink pageLinkResources = new PageLink(1000); + PageData tenantResources = + resourceService.findAllTenantResourcesByTenantId(savedTenant.getId(), pageLinkResources); + Assert.assertFalse(tenantResources.hasNext()); + Assert.assertEquals(0, tenantResources.getTotalElements()); + } - Assert.assertNull(entityViewService.findEntityViewById( - savedTenant.getId(), savedEntityView.getId() - )); - List entityViews = - entityViewService.findEntityViewsByTenantIdAndEntityId( - savedTenant.getId(), savedDevice.getId()); - Assert.assertTrue(entityViews.isEmpty()); + private void assertUserIsDeleted(Tenant savedTenant, User savedUser) { + Assert.assertNull(userService.findUserById(savedTenant.getId(), savedUser.getId())); + PageLink pageLinkUsers = new PageLink(1000); + PageData users = + userService.findUsersByTenantId(savedTenant.getId(), pageLinkUsers); + Assert.assertFalse(users.hasNext()); + Assert.assertEquals(0, users.getTotalElements()); + } + private void assertTenantAdminIsDeleted(Tenant savedTenant) { + PageLink pageLinkTenantAdmins = new PageLink(1000); + PageData tenantAdmins = + userService.findTenantAdmins(savedTenant.getId(), pageLinkTenantAdmins); + Assert.assertFalse(tenantAdmins.hasNext()); + Assert.assertEquals(0, tenantAdmins.getTotalElements()); + } - Assert.assertNull(assetService.findAssetById( - savedTenant.getId(), savedAsset.getId() + private void assertEdgeIsDeletd(Tenant savedTenant, Edge savedEdge) { + Assert.assertNull(edgeService.findEdgeById(savedTenant.getId(), savedEdge.getId())); + PageLink pageLinkEdges = new PageLink(1000); + PageData edges = edgeService.findEdgesByTenantId(savedTenant.getId(), pageLinkEdges); + Assert.assertFalse(edges.hasNext()); + Assert.assertEquals(0, edges.getTotalElements()); + } + + private void assertDashboardIsDeleted(Tenant savedTenant, Dashboard savedDashboard) { + Assert.assertNull(dashboardService.findDashboardById( + savedTenant.getId(), savedDashboard.getId() )); - PageLink pageLinkAssets = new PageLink(1000); - PageData assets = - assetService.findAssetsByTenantId(savedTenant.getId(), pageLinkAssets); - Assert.assertFalse(assets.hasNext()); - Assert.assertEquals(0, assets.getTotalElements()); + PageLink pageLinkDashboards = new PageLink(1000); + PageData dashboards = + dashboardService.findDashboardsByTenantId(savedTenant.getId(), pageLinkDashboards); + Assert.assertFalse(dashboards.hasNext()); + Assert.assertEquals(0, dashboards.getTotalElements()); + } + private void assertDeviceProfileIsDeleted(Tenant savedTenant, DeviceProfile savedDeviceProfile) { + Assert.assertNull(deviceProfileService.findDeviceProfileById( + savedTenant.getId(), savedDeviceProfile.getId() + )); + PageLink pageLinkDeviceProfiles = new PageLink(1000); + PageData profiles = + deviceProfileService.findDeviceProfiles(savedTenant.getId(), pageLinkDeviceProfiles); + Assert.assertFalse(profiles.hasNext()); + Assert.assertEquals(0, profiles.getTotalElements()); + } + private void assertDeviceIsDeleted(Tenant savedTenant, Device savedDevice) { Assert.assertNull(deviceService.findDeviceById( savedTenant.getId(), savedDevice.getId() )); @@ -558,89 +502,191 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { deviceService.findDevicesByTenantId(savedTenant.getId(), pageLinkDevices); Assert.assertFalse(devices.hasNext()); Assert.assertEquals(0, devices.getTotalElements()); + } + private void assertAssetIsDeleted(Tenant savedTenant, Asset savedAsset) { + Assert.assertNull(assetService.findAssetById( + savedTenant.getId(), savedAsset.getId() + )); + PageLink pageLinkAssets = new PageLink(1000); + PageData assets = + assetService.findAssetsByTenantId(savedTenant.getId(), pageLinkAssets); + Assert.assertFalse(assets.hasNext()); + Assert.assertEquals(0, assets.getTotalElements()); + } - Assert.assertNull(deviceProfileService.findDeviceProfileById( - savedTenant.getId(), savedDeviceProfile.getId() + private void assertEntityViewIsDeleted(Tenant savedTenant, Device savedDevice, EntityView savedEntityView) { + Assert.assertNull(entityViewService.findEntityViewById( + savedTenant.getId(), savedEntityView.getId() )); - PageLink pageLinkDeviceProfiles = new PageLink(1000); - PageData profiles = - deviceProfileService.findDeviceProfiles(savedTenant.getId(), pageLinkDeviceProfiles); - Assert.assertFalse(profiles.hasNext()); - Assert.assertEquals(0, profiles.getTotalElements()); + List entityViews = + entityViewService.findEntityViewsByTenantIdAndEntityId( + savedTenant.getId(), savedDevice.getId()); + Assert.assertTrue(entityViews.isEmpty()); + } + private void assertWidgetsBundleIsDeleted(Tenant savedTenant, WidgetsBundle savedWidgetsBundle) { + Assert.assertNull( + widgetsBundleService.findWidgetsBundleById(savedTenant.getId(), savedWidgetsBundle.getId()) + ); + List widgetsBundlesByTenantId = + widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(savedTenant.getId()); + Assert.assertTrue(widgetsBundlesByTenantId.isEmpty()); + } - Assert.assertNull(dashboardService.findDashboardById( - savedTenant.getId(), savedDashboard.getId() - )); - PageLink pageLinkDashboards = new PageLink(1000); - PageData dashboards = - dashboardService.findDashboardsByTenantId(savedTenant.getId(), pageLinkDashboards); - Assert.assertFalse(dashboards.hasNext()); - Assert.assertEquals(0, dashboards.getTotalElements()); + private void assertCustomerIsDeleted(Tenant savedTenant, Customer savedCustomer) { + Assert.assertNull(customerService.findCustomerById(savedTenant.getId(), savedCustomer.getId())); + PageLink pageLinkCustomer = new PageLink(1000); + PageData pageDataCustomer = customerService + .findCustomersByTenantId(savedTenant.getId(), pageLinkCustomer); + Assert.assertFalse(pageDataCustomer.hasNext()); + Assert.assertEquals(0, pageDataCustomer.getTotalElements()); + } + private Rpc createAndSaveRpcFor(Tenant savedTenant, Device savedDevice) { + Rpc rpc = new Rpc(); + rpc.setTenantId(savedTenant.getId()); + rpc.setDeviceId(savedDevice.getId()); + rpc.setStatus(RpcStatus.QUEUED); + rpc.setRequest(JacksonUtil.toJsonNode("{}")); + return rpcService.save(rpc); + } - Assert.assertNull(edgeService.findEdgeById(savedTenant.getId(), savedEdge.getId())); - PageLink pageLinkEdges = new PageLink(1000); - PageData edges = edgeService.findEdgesByTenantId(savedTenant.getId(), pageLinkEdges); - Assert.assertFalse(edges.hasNext()); - Assert.assertEquals(0, edges.getTotalElements()); + private TbResource createAndSaveResourceFor(Tenant savedTenant) { + TbResource resource = new TbResource(); + resource.setTenantId(savedTenant.getId()); + resource.setTitle("Test resource"); + resource.setResourceType(ResourceType.LWM2M_MODEL); + resource.setFileName("filename.txt"); + resource.setResourceKey("Test resource key"); + resource.setData("Some super test data"); + return resourceService.saveResource(resource); + } + private OtaPackage createAndSaveOtaPackageFor(Tenant savedTenant, DeviceProfile savedDeviceProfile) { + OtaPackage otaPackage = createFirmware(savedTenant.getId(), savedDeviceProfile.getId()); + return otaPackageService.saveOtaPackage(otaPackage); + } - PageLink pageLinkTenantAdmins = new PageLink(1000); - PageData tenantAdmins = - userService.findTenantAdmins(savedTenant.getId(), pageLinkTenantAdmins); - Assert.assertFalse(tenantAdmins.hasNext()); - Assert.assertEquals(0, tenantAdmins.getTotalElements()); + private Edge createAndSaveEdgeFor(Tenant savedTenant) { + Edge edge = constructEdge(savedTenant.getId(), "Test edge", "Simple"); + return edgeService.saveEdge(edge, false); + } + private RuleChain createAndSaveRuleChainFor(Tenant savedTenant) { + RuleChain ruleChain = new RuleChain(); + ruleChain.setTenantId(savedTenant.getId()); + ruleChain.setName("Test rule chain"); + ruleChain.setType(RuleChainType.CORE); + return ruleChainService.saveRuleChain(ruleChain); + } - Assert.assertNull(userService.findUserById(savedTenant.getId(), savedUser.getId())); - PageLink pageLinkUsers = new PageLink(1000); - PageData users = - userService.findUsersByTenantId(savedTenant.getId(), pageLinkUsers); - Assert.assertFalse(users.hasNext()); - Assert.assertEquals(0, users.getTotalElements()); + private Dashboard createAndSaveDashboardFor(Tenant savedTenant, Customer savedCustomer) { + Dashboard dashboard = new Dashboard(); + dashboard.setTenantId(savedTenant.getId()); + dashboard.setTitle("Test dashboard"); + dashboard.setAssignedCustomers(Set.of(savedCustomer.toShortCustomerInfo())); + return dashboardService.saveDashboard(dashboard); + } + private Asset createAndSaveAssetFor(Tenant savedTenant, Customer savedCustomer) { + Asset asset = new Asset(); + asset.setTenantId(savedTenant.getId()); + asset.setCustomerId(savedCustomer.getId()); + asset.setType("Test asset type"); + asset.setName("Test asset type"); + asset.setLabel("Test asset type"); + return assetService.saveAsset(asset); + } - Assert.assertNull(ruleChainService.findRuleChainById(savedTenant.getId(), savedRuleChain.getId())); - Assert.assertNull(apiUsageStateService.findTenantApiUsageState(savedTenant.getId())); + private EntityView createAndSaveEntityViewFor(Tenant savedTenant, Customer savedCustomer, Device savedDevice) { + EntityView entityView = new EntityView(); + entityView.setEntityId(savedDevice.getId()); + entityView.setTenantId(savedTenant.getId()); + entityView.setCustomerId(savedCustomer.getId()); + entityView.setType("Test type"); + entityView.setName("Test entity view"); + entityView.setStartTimeMs(0); + entityView.setEndTimeMs(840000); + return entityViewService.saveEntityView(entityView); + } + private Device createAndSaveDeviceFor(Tenant savedTenant, Customer savedCustomer, DeviceProfile savedDeviceProfile) { + Device device = new Device(); + device.setCustomerId(savedCustomer.getId()); + device.setTenantId(savedTenant.getId()); + device.setType("Test type"); + device.setName("TestType"); + device.setLabel("Test type"); + device.setDeviceProfileId(savedDeviceProfile.getId()); + return deviceService.saveDevice(device); + } - Assert.assertNull(resourceService.findResourceById(savedTenant.getId(), savedResource.getId())); - PageLink pageLinkResources = new PageLink(1000); - PageData tenantResources = - resourceService.findAllTenantResourcesByTenantId(savedTenant.getId(), pageLinkResources); - Assert.assertFalse(tenantResources.hasNext()); - Assert.assertEquals(0, tenantResources.getTotalElements()); + private DeviceProfile createAndSaveDeviceProfileWithProfileDataFor(Tenant savedTenant) { + DeviceProfile deviceProfile = new DeviceProfile(); + deviceProfile.setTenantId(savedTenant.getId()); + deviceProfile.setTransportType(DeviceTransportType.MQTT); + deviceProfile.setName("Test device profile"); + deviceProfile.setType(DeviceProfileType.DEFAULT); + DeviceProfileData profileData = new DeviceProfileData(); + profileData.setTransportConfiguration(new MqttDeviceProfileTransportConfiguration()); + deviceProfile.setProfileData(profileData); + return deviceProfileService.saveDeviceProfile(deviceProfile); + } + private WidgetsBundle createAndSaveWidgetBundleFor(Tenant savedTenant) { + WidgetsBundle widgetsBundle = new WidgetsBundle(); + widgetsBundle.setTenantId(savedTenant.getId()); + widgetsBundle.setTitle("Test widgets bundle"); + widgetsBundle.setAlias("TestWidgetsBundle"); + widgetsBundle.setDescription("Just a simple widgets bundle"); + return widgetsBundleService.saveWidgetsBundle(widgetsBundle); + } - Assert.assertNull( - otaPackageService.findOtaPackageById( - savedTenant.getId(), savedOtaPackage.getId() - ) - ); - PageLink pageLinkOta = new PageLink(1000); - PageData pageDataOta = otaPackageService.findTenantOtaPackagesByTenantId(savedTenant.getId(), pageLinkOta); - Assert.assertFalse(pageDataOta.hasNext()); - Assert.assertEquals(0, pageDataOta.getTotalElements()); + private Customer createAndSaveCustomerFor(Tenant savedTenant) { + Customer customer = new Customer(); + customer.setTitle("Test customer"); + customer.setTenantId(savedTenant.getId()); + customer.setEmail("testCustomer@test.com"); + return customerService.saveCustomer(customer); + } + private User createAndSaveUserFor(Tenant savedTenant) { + User user = new User(); + user.setAuthority(Authority.TENANT_ADMIN); + user.setEmail("tenantAdmin@test.com"); + user.setFirstName("tenantAdmin"); + user.setLastName("tenantAdmin"); + user.setTenantId(savedTenant.getId()); + return userService.saveUser(user); + } - Assert.assertNull(rpcService.findById(savedTenant.getId(), savedRpc.getId())); + private Tenant createAndSaveTenant(TenantProfile savedProfile) { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + tenant.setTenantProfileId(savedProfile.getId()); + return tenantService.saveTenant(tenant); + } + + private TenantProfile createAndSaveTenantProfile() { + TenantProfile tenantProfile = new TenantProfile(); + tenantProfile.setName("Test tenant profile"); + return tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); } - private OtaPackage createFirmware(TenantId tenantId, String version, DeviceProfileId deviceProfileId) { + private OtaPackage createFirmware(TenantId tenantId, DeviceProfileId deviceProfileId) { OtaPackage firmware = new OtaPackage(); firmware.setTenantId(tenantId); firmware.setDeviceProfileId(deviceProfileId); firmware.setType(FIRMWARE); - firmware.setTitle(TITLE); - firmware.setVersion(version); - firmware.setFileName(FILE_NAME); - firmware.setContentType(CONTENT_TYPE); - firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); - firmware.setChecksum(CHECKSUM); - firmware.setData(DATA); - firmware.setDataSize(DATA_SIZE); + firmware.setTitle("My firmware"); + firmware.setVersion("1"); + firmware.setFileName("filename.txt"); + firmware.setContentType("text/plain"); + firmware.setChecksumAlgorithm(ChecksumAlgorithm.SHA256); + firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"); + firmware.setData(ByteBuffer.wrap(new byte[]{(int) 1L})); + firmware.setDataSize(1L); return otaPackageService.saveOtaPackage(firmware); } } From 801e747b02f88a2e95ff3ff51d4784f1a26b2ee6 Mon Sep 17 00:00:00 2001 From: desoliture Date: Mon, 17 Jan 2022 12:52:04 +0200 Subject: [PATCH 08/41] fix names in test for Tenant deletion --- .../server/dao/service/BaseTenantServiceTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 7644ee86e7..06aaaff43d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -415,17 +415,17 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { assertDeviceIsDeleted(savedTenant, savedDevice); assertDeviceProfileIsDeleted(savedTenant, savedDeviceProfile); assertDashboardIsDeleted(savedTenant, savedDashboard); - assertEdgeIsDeletd(savedTenant, savedEdge); + assertEdgeIsDeleted(savedTenant, savedEdge); assertTenantAdminIsDeleted(savedTenant); assertUserIsDeleted(savedTenant, savedUser); Assert.assertNull(ruleChainService.findRuleChainById(savedTenant.getId(), savedRuleChain.getId())); Assert.assertNull(apiUsageStateService.findTenantApiUsageState(savedTenant.getId())); assertResourceIsDeleted(savedTenant, savedResource); - assertOtaPAckageIsDeleted(savedTenant, savedOtaPackage); + assertOtaPackageIsDeleted(savedTenant, savedOtaPackage); Assert.assertNull(rpcService.findById(savedTenant.getId(), savedRpc.getId())); } - private void assertOtaPAckageIsDeleted(Tenant savedTenant, OtaPackage savedOtaPackage) { + private void assertOtaPackageIsDeleted(Tenant savedTenant, OtaPackage savedOtaPackage) { Assert.assertNull( otaPackageService.findOtaPackageById( savedTenant.getId(), savedOtaPackage.getId() @@ -463,7 +463,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Assert.assertEquals(0, tenantAdmins.getTotalElements()); } - private void assertEdgeIsDeletd(Tenant savedTenant, Edge savedEdge) { + private void assertEdgeIsDeleted(Tenant savedTenant, Edge savedEdge) { Assert.assertNull(edgeService.findEdgeById(savedTenant.getId(), savedEdge.getId())); PageLink pageLinkEdges = new PageLink(1000); PageData edges = edgeService.findEdgesByTenantId(savedTenant.getId(), pageLinkEdges); From bbf02b5f39ad5ed035a24884f211201a564fbeb8 Mon Sep 17 00:00:00 2001 From: desoliture Date: Mon, 17 Jan 2022 13:21:23 +0200 Subject: [PATCH 09/41] add timeout for tenant deletion transaction and fix test for tenant deletion --- .../thingsboard/server/dao/tenant/TenantServiceImpl.java | 6 +++--- .../server/dao/service/BaseTenantServiceTest.java | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 47179049a1..d9cfd8647d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -107,7 +107,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe private RpcService rpcService; @Override - @Cacheable(cacheNames = TENANTS_CACHE, key = "#tenantId", condition = "#tenantId!=null") + @Cacheable(cacheNames = TENANTS_CACHE, key = "#tenantId") public Tenant findTenantById(TenantId tenantId) { log.trace("Executing findTenantById [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); @@ -148,8 +148,8 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe } @Override - @Transactional - @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenantId", condition = "#tenantId!=null") + @Transactional(timeout = 60 * 60) + @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenantId") public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 06aaaff43d..21bbddde9b 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -423,6 +423,8 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { assertResourceIsDeleted(savedTenant, savedResource); assertOtaPackageIsDeleted(savedTenant, savedOtaPackage); Assert.assertNull(rpcService.findById(savedTenant.getId(), savedRpc.getId())); + + tenantProfileService.deleteTenantProfile(TenantId.SYS_TENANT_ID, savedProfile.getId()); } private void assertOtaPackageIsDeleted(Tenant savedTenant, OtaPackage savedOtaPackage) { From d9dbd273641ffa17aff9e50c6298d8b8162368f3 Mon Sep 17 00:00:00 2001 From: desoliture Date: Mon, 17 Jan 2022 13:34:28 +0200 Subject: [PATCH 10/41] refactor test for tenant deletion --- .../dao/service/BaseTenantServiceTest.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 21bbddde9b..9ad900fb1a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -71,6 +71,8 @@ import java.util.Set; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; public abstract class BaseTenantServiceTest extends AbstractServiceTest { @@ -328,12 +330,12 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); - Mockito.reset(tenantDao); + reset(tenantDao); Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Tenant cache manager is null").evict(savedTenant.getId()); - Mockito.verify(tenantDao, Mockito.times(0)).findById(any(), any()); + verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); - Mockito.verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); Cache.ValueWrapper cachedTenant = Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); @@ -342,7 +344,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { for (int i = 0; i < 100; i++) { tenantService.findTenantById(savedTenant.getId()); } - Mockito.verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); tenantService.deleteTenant(savedTenant.getId()); } @@ -360,14 +362,14 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { savedTenant.setTitle("My new tenant"); savedTenant = tenantService.saveTenant(savedTenant); - Mockito.reset(tenantDao); + reset(tenantDao); cachedTenant = Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); - Mockito.verify(tenantDao, Mockito.times(0)).findById(any(), any()); + verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); - Mockito.verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); tenantService.deleteTenant(savedTenant.getId()); } From a39b56c93cbe0e6c69eec1cfa6070fc0498c5b0c Mon Sep 17 00:00:00 2001 From: desoliture Date: Mon, 17 Jan 2022 13:35:28 +0200 Subject: [PATCH 11/41] replace remained tenantDao usages to tenantService --- .../server/service/ttl/AlarmsCleanUpService.java | 6 +++--- .../server/service/ttl/rpc/RpcCleanUpService.java | 6 +++--- .../org/thingsboard/server/dao/tenant/TenantService.java | 2 ++ .../thingsboard/server/dao/tenant/TenantServiceImpl.java | 7 +++++++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java index 1dfb4a67bf..5182b6ffe5 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java @@ -32,7 +32,7 @@ import org.thingsboard.server.dao.alarm.AlarmDao; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.action.EntityActionService; @@ -50,7 +50,7 @@ public class AlarmsCleanUpService { @Value("${sql.ttl.alarms.removal_batch_size}") private Integer removalBatchSize; - private final TenantDao tenantDao; + private final TenantService tenantService; private final AlarmDao alarmDao; private final AlarmService alarmService; private final RelationService relationService; @@ -64,7 +64,7 @@ public class AlarmsCleanUpService { PageLink removalBatchRequest = new PageLink(removalBatchSize, 0 ); PageData tenantsIds; do { - tenantsIds = tenantDao.findTenantsIds(tenantsBatchRequest); + tenantsIds = tenantService.findTenantsIds(tenantsBatchRequest); for (TenantId tenantId : tenantsIds.getData()) { if (!partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) { continue; diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/rpc/RpcCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/rpc/RpcCleanUpService.java index c0985eb4c1..3252d3df1a 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/rpc/RpcCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/rpc/RpcCleanUpService.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileCon import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.dao.rpc.RpcDao; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; +import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.util.TbCoreComponent; @@ -43,7 +43,7 @@ public class RpcCleanUpService { @Value("${sql.ttl.rpc.enabled}") private boolean ttlTaskExecutionEnabled; - private final TenantDao tenantDao; + private final TenantService tenantService; private final PartitionService partitionService; private final TbTenantProfileCache tenantProfileCache; private final RpcDao rpcDao; @@ -54,7 +54,7 @@ public class RpcCleanUpService { PageLink tenantsBatchRequest = new PageLink(10_000, 0); PageData tenantsIds; do { - tenantsIds = tenantDao.findTenantsIds(tenantsBatchRequest); + tenantsIds = tenantService.findTenantsIds(tenantsBatchRequest); for (TenantId tenantId : tenantsIds.getData()) { if (!partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) { continue; diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index 95236ad8a3..01c4d9b4e2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -39,4 +39,6 @@ public interface TenantService { PageData findTenantInfos(PageLink pageLink); void deleteTenants(); + + PageData findTenantsIds(PageLink pageLink); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index d9cfd8647d..ecca39b93c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -191,6 +191,13 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe tenantsRemover.removeEntities(new TenantId(EntityId.NULL_UUID), DEFAULT_TENANT_REGION); } + @Override + public PageData findTenantsIds(PageLink pageLink) { + log.trace("Executing deleteTenants"); + Validator.validatePageLink(pageLink); + return tenantDao.findTenantsIds(pageLink); + } + private DataValidator tenantValidator = new DataValidator() { @Override From 83ae5ba26284beaf97f69644ae365c03d0186d89 Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 19 Jan 2022 16:37:51 +0200 Subject: [PATCH 12/41] refactor --- .../org/thingsboard/server/dao/tenant/TenantServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index ecca39b93c..50fe23f22b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -123,7 +123,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override public ListenableFuture findTenantByIdAsync(TenantId callerId, TenantId tenantId) { - log.trace("Executing TenantIdAsync [{}]", tenantId); + log.trace("Executing findTenantByIdAsync [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); return tenantDao.findByIdAsync(callerId, tenantId.getId()); } @@ -193,7 +193,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override public PageData findTenantsIds(PageLink pageLink) { - log.trace("Executing deleteTenants"); + log.trace("Executing findTenantsIds"); Validator.validatePageLink(pageLink); return tenantDao.findTenantsIds(pageLink); } From 16753d2f624a13b768758f7e2736c63591a06e85 Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 20 Jan 2022 16:50:40 +0200 Subject: [PATCH 13/41] refactor relation service and dao(*), remove redundant todo's, refactor tests (*): resolve immediate .get() invocation, which producing blocking (checkRelation method), by adding sync checkRelation method and refactor the usages of checkRelationAsync --- .../rpc/sync/DefaultEdgeRequestsService.java | 2 +- .../server/dao/relation/RelationService.java | 4 +- .../server/dao/alarm/BaseAlarmService.java | 1 - .../server/dao/asset/BaseAssetService.java | 1 - .../dao/customer/CustomerServiceImpl.java | 1 - .../dao/dashboard/DashboardServiceImpl.java | 1 - .../dao/device/DeviceProfileServiceImpl.java | 1 - .../server/dao/device/DeviceServiceImpl.java | 1 - .../server/dao/edge/EdgeServiceImpl.java | 1 - .../dao/entity/AbstractEntityService.java | 22 +- .../dao/entityview/EntityViewServiceImpl.java | 17 +- .../dao/relation/BaseRelationService.java | 12 +- .../server/dao/relation/RelationDao.java | 4 +- .../dao/resource/BaseResourceService.java | 1 - .../server/dao/rule/BaseRuleChainService.java | 1 - .../sql/entityview/EntityViewRepository.java | 1 - .../dao/sql/relation/JpaRelationDao.java | 8 +- .../usagerecord/ApiUsageStateServiceImpl.java | 1 - .../dao/widget/WidgetTypeServiceImpl.java | 1 - .../dao/widget/WidgetsBundleServiceImpl.java | 1 - .../service/BaseOtaPackageServiceTest.java | 36 +- .../dao/service/BaseRelationServiceTest.java | 16 +- .../dao/service/BaseTenantServiceTest.java | 320 ++++++++---------- .../engine/action/TbCreateRelationNode.java | 2 +- .../engine/action/TbDeleteRelationNode.java | 2 +- .../engine/filter/TbCheckRelationNode.java | 2 +- .../action/TbCreateRelationNodeTest.java | 6 +- 27 files changed, 218 insertions(+), 248 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java index a1f8fc89ec..80320a94c0 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java @@ -348,7 +348,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { if (entityViews != null && !entityViews.isEmpty()) { List> futures = new ArrayList<>(); for (EntityView entityView : entityViews) { - ListenableFuture future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(), + ListenableFuture future = relationService.checkRelationAsync(tenantId, edge.getId(), entityView.getId(), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); futures.add(future); Futures.addCallback(future, new FutureCallback<>() { diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index 87ac26b41e..364eb2653b 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -34,7 +34,9 @@ import java.util.List; */ public interface RelationService { - ListenableFuture checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + + Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); EntityRelation getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index e6df02c854..e2e1d54935 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -431,7 +431,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ throw new DataValidationException("Alarm should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(alarm.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Alarm is referencing to non-existent tenant!"); } 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 3e178919f6..2610aff3e3 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 @@ -412,7 +412,6 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ throw new DataValidationException("Asset should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(asset.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Asset is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index f8726e9d16..3b2376f98d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -211,7 +211,6 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom throw new DataValidationException("Customer should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(customer.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Customer is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index aaf5e5d584..a27d69f7ee 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -309,7 +309,6 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb throw new DataValidationException("Dashboard should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(dashboard.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Dashboard is referencing to non-existent tenant!"); } 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 b71822907d..254b84889b 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 @@ -376,7 +376,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D throw new DataValidationException("Device profile should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(deviceProfile.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Device profile is referencing to non-existent tenant!"); } 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 778ee3e789..00d393c4bd 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 @@ -732,7 +732,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe throw new DataValidationException("Device should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(device.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Device is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 7e9bd64741..281848a68d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -414,7 +414,6 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic throw new DataValidationException("Edge should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(edge.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Edge is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java index acb49bb730..759ff937a1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java @@ -82,20 +82,16 @@ public abstract class AbstractEntityService { } protected void checkAssignedEntityViewsToEdge(TenantId tenantId, EntityId entityId, EdgeId edgeId) { - try { - List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(tenantId, entityId); - if (entityViews != null && !entityViews.isEmpty()) { - EntityView entityView = entityViews.get(0); - // TODO: @voba - refactor this blocking operation - Boolean relationExists = relationService.checkRelation(tenantId, edgeId, entityView.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE).get(); - if (relationExists) { - throw new DataValidationException("Can't unassign device/asset from edge that is related to entity view and entity view is assigned to edge!"); - } + List entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(tenantId, entityId); + if (entityViews != null && !entityViews.isEmpty()) { + EntityView entityView = entityViews.get(0); + Boolean relationExists = relationService.checkRelation( + tenantId, edgeId, entityView.getId(), + EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE + ); + if (relationExists) { + throw new DataValidationException("Can't unassign device/asset from edge that is related to entity view and entity view is assigned to edge!"); } - } catch (Exception e) { - log.error("[{}] Exception while finding entity views for entityId [{}]", tenantId, entityId, e); - throw new RuntimeException("Exception while finding entity views for entityId [" + entityId + "]", e); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 30b32e4caf..17bccd93c3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -308,9 +308,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(entityId.getId(), "Incorrect entityId" + entityId); - List tenantIdAndEntityId = new ArrayList<>(); - tenantIdAndEntityId.add(tenantId); - tenantIdAndEntityId.add(entityId); + List tenantIdAndEntityId = List.of(tenantId, entityId); Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); List fromCache = cache.get(tenantIdAndEntityId, List.class); @@ -366,15 +364,10 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti throw new DataValidationException("Can't assign entityView to edge from different tenant!"); } - try { - Boolean relationExists = relationService.checkRelation(tenantId, edgeId, entityView.getEntityId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE).get(); - if (!relationExists) { - throw new DataValidationException("Can't assign entity view to edge because related device/asset doesn't assigned to edge!"); - } - } catch (ExecutionException | InterruptedException e) { - log.error("Exception during relation check", e); - throw new RuntimeException("Exception during relation check", e); + Boolean relationExists = relationService.checkRelation(tenantId, edgeId, entityView.getEntityId(), + EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); + if (!relationExists) { + throw new DataValidationException("Can't assign entity view to edge because related device/asset doesn't assigned to edge!"); } try { diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 996c0801ff..1f5f4ffbe2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -30,11 +30,8 @@ import org.springframework.cache.annotation.Caching; import org.springframework.dao.ConcurrencyFailureException; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -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.data.page.PageData; -import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; @@ -77,10 +74,15 @@ public class BaseRelationService implements RelationService { private CacheManager cacheManager; @Override - public ListenableFuture checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + public ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup); validate(from, to, relationType, typeGroup); - return relationDao.checkRelation(tenantId, from, to, relationType, typeGroup); + return relationDao.checkRelationAsync(tenantId, from, to, relationType, typeGroup); + } + + @Override + public Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + return null; } @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType, #typeGroup}") diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index 85d333b04a..5df4f0420a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -41,7 +41,9 @@ public interface RelationDao { ListenableFuture> findAllByToAndType(TenantId tenantId, EntityId to, String relationType, RelationTypeGroup typeGroup); - ListenableFuture checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + + Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); ListenableFuture getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index d8f8976dcb..2511a7ec6a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -184,7 +184,6 @@ public class BaseResourceService implements ResourceService { } if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { Tenant tenant = tenantService.findTenantById(resource.getTenantId()); - // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Resource is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index f649dc9a0a..1ef88f5450 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -727,7 +727,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC throw new DataValidationException("Rule chain should be assigned to tenant!"); } Tenant tenant = tenantService.findTenantById(ruleChain.getTenantId()); - // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Rule chain is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java index 45c5886d7c..05989f3a83 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java @@ -20,7 +20,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.query.Param; -import org.thingsboard.server.dao.model.sql.DeviceEntity; import org.thingsboard.server.dao.model.sql.EntityViewEntity; import org.thingsboard.server.dao.model.sql.EntityViewInfoEntity; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index fbedef6c4e..268abd58e9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -101,11 +101,17 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple } @Override - public ListenableFuture checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + public ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup); return service.submit(() -> relationRepository.existsById(key)); } + @Override + public Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup); + return relationRepository.existsById(key); + } + @Override public ListenableFuture getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup); diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index d9cedb5b77..8cb4e17598 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -165,7 +165,6 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A throw new DataValidationException("ApiUsageState should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(apiUsageState.getTenantId()); - // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null && !requestTenantId.equals(TenantId.SYS_TENANT_ID)) { throw new DataValidationException("ApiUsageState is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 6952f4a7d2..e2fe57ca74 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -139,7 +139,6 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { } if (!widgetTypeDetails.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { Tenant tenant = tenantService.findTenantById(widgetTypeDetails.getTenantId()); - // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Widget type is referencing to non-existent tenant!"); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 559481df74..2bea7f3ade 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -163,7 +163,6 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { } if (!widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { Tenant tenant = tenantService.findTenantById(widgetsBundle.getTenantId()); - // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Widgets bundle is referencing to non-existent tenant!"); } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java index 8fcadcd812..2e937ed164 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java @@ -97,26 +97,26 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { Assert.assertEquals(0, otaPackageService.sumDataSizeByTenantId(tenantId)); - createFirmware(tenantId, "1"); + createAndSaveFirmware(tenantId, "1"); Assert.assertEquals(1, otaPackageService.sumDataSizeByTenantId(tenantId)); thrown.expect(DataValidationException.class); thrown.expectMessage(String.format("Failed to create the ota package, files size limit is exhausted %d bytes!", DATA_SIZE)); - createFirmware(tenantId, "2"); + createAndSaveFirmware(tenantId, "2"); } @Test public void sumDataSizeByTenantId() { Assert.assertEquals(0, otaPackageService.sumDataSizeByTenantId(tenantId)); - createFirmware(tenantId, "0.1"); + createAndSaveFirmware(tenantId, "0.1"); Assert.assertEquals(1, otaPackageService.sumDataSizeByTenantId(tenantId)); int maxSumDataSize = 8; List packages = new ArrayList<>(maxSumDataSize); for (int i = 2; i <= maxSumDataSize; i++) { - packages.add(createFirmware(tenantId, "0." + i)); + packages.add(createAndSaveFirmware(tenantId, "0." + i)); Assert.assertEquals(i, otaPackageService.sumDataSizeByTenantId(tenantId)); } @@ -419,15 +419,15 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @Test public void testSaveFirmwareWithExistingTitleAndVersion() { - createFirmware(tenantId, VERSION); + createAndSaveFirmware(tenantId, VERSION); thrown.expect(DataValidationException.class); thrown.expectMessage("OtaPackage with such title and version already exists!"); - createFirmware(tenantId, VERSION); + createAndSaveFirmware(tenantId, VERSION); } @Test public void testDeleteFirmwareWithReferenceByDevice() { - OtaPackage savedFirmware = createFirmware(tenantId, VERSION); + OtaPackage savedFirmware = createAndSaveFirmware(tenantId, VERSION); Device device = new Device(); device.setTenantId(tenantId); @@ -448,7 +448,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @Test public void testUpdateDeviceProfileId() { - OtaPackage savedFirmware = createFirmware(tenantId, VERSION); + OtaPackage savedFirmware = createAndSaveFirmware(tenantId, VERSION); try { thrown.expect(DataValidationException.class); @@ -494,7 +494,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @Test public void testFindFirmwareById() { - OtaPackage savedFirmware = createFirmware(tenantId, VERSION); + OtaPackage savedFirmware = createAndSaveFirmware(tenantId, VERSION); OtaPackage foundFirmware = otaPackageService.findOtaPackageById(tenantId, savedFirmware.getId()); Assert.assertNotNull(foundFirmware); @@ -520,7 +520,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { @Test public void testDeleteFirmware() { - OtaPackage savedFirmware = createFirmware(tenantId, VERSION); + OtaPackage savedFirmware = createAndSaveFirmware(tenantId, VERSION); OtaPackage foundFirmware = otaPackageService.findOtaPackageById(tenantId, savedFirmware.getId()); Assert.assertNotNull(foundFirmware); @@ -533,7 +533,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { public void testFindTenantFirmwaresByTenantId() { List firmwares = new ArrayList<>(); for (int i = 0; i < 165; i++) { - OtaPackageInfo info = new OtaPackageInfo(createFirmware(tenantId, VERSION + i)); + OtaPackageInfo info = new OtaPackageInfo(createAndSaveFirmware(tenantId, VERSION + i)); info.setHasData(true); firmwares.add(info); } @@ -580,7 +580,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { public void testFindTenantFirmwaresByTenantIdAndHasData() { List firmwares = new ArrayList<>(); for (int i = 0; i < 165; i++) { - firmwares.add(new OtaPackageInfo(otaPackageService.saveOtaPackage(createFirmware(tenantId, VERSION + i)))); + firmwares.add(new OtaPackageInfo(otaPackageService.saveOtaPackage(createAndSaveFirmware(tenantId, VERSION + i)))); } OtaPackageInfo firmwareWithUrl = new OtaPackageInfo(); @@ -696,7 +696,15 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { otaPackageService.saveOtaPackageInfo(firmwareInfo, true); } - private OtaPackage createFirmware(TenantId tenantId, String version) { + private OtaPackage createAndSaveFirmware(TenantId tenantId, String version) { + return otaPackageService.saveOtaPackage(createFirmware(tenantId, version, deviceProfileId)); + } + + public static OtaPackage createFirmware( + TenantId tenantId, + String version, + DeviceProfileId deviceProfileId + ) { OtaPackage firmware = new OtaPackage(); firmware.setTenantId(tenantId); firmware.setDeviceProfileId(deviceProfileId); @@ -709,6 +717,6 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { firmware.setChecksum(CHECKSUM); firmware.setData(DATA); firmware.setDataSize(DATA_SIZE); - return otaPackageService.saveOtaPackage(firmware); + return firmware; } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java index 27dc7f812a..4e7dd0a784 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java @@ -57,13 +57,13 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest { Assert.assertTrue(saveRelation(relation)); - Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); + Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); - Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, "NOT_EXISTING_TYPE", RelationTypeGroup.COMMON).get()); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, "NOT_EXISTING_TYPE", RelationTypeGroup.COMMON)); - Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, parentId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, parentId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); - Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, parentId, "NOT_EXISTING_TYPE", RelationTypeGroup.COMMON).get()); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, parentId, "NOT_EXISTING_TYPE", RelationTypeGroup.COMMON)); } @Test @@ -80,9 +80,9 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest { Assert.assertTrue(relationService.deleteRelationAsync(SYSTEM_TENANT_ID, relationA).get()); - Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); - Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); + Assert.assertTrue(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); Assert.assertTrue(relationService.deleteRelationAsync(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); } @@ -118,9 +118,9 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest { Assert.assertNull(relationService.deleteEntityRelationsAsync(SYSTEM_TENANT_ID, childId).get()); - Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, parentId, childId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); - Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON).get()); + Assert.assertFalse(relationService.checkRelation(SYSTEM_TENANT_ID, childId, subChildId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.COMMON)); } @Test diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 9ad900fb1a..b36467a307 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.service; import org.apache.commons.lang3.RandomStringUtils; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; @@ -46,9 +47,7 @@ import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; -import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rpc.Rpc; @@ -62,7 +61,6 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.tenant.TenantDao; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -71,9 +69,8 @@ import java.util.Set; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; -import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; +import static org.assertj.core.api.Assertions.assertThat; public abstract class BaseTenantServiceTest extends AbstractServiceTest { @@ -85,6 +82,13 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { @Autowired CacheManager cacheManager; + private Cache tenantCache; + + @Before + public void setup() { + tenantCache = cacheManager.getCache(CacheConstants.TENANTS_CACHE); + } + @Test public void testSaveTenant() { Tenant tenant = new Tenant(); @@ -330,15 +334,15 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); - reset(tenantDao); - Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Tenant cache manager is null").evict(savedTenant.getId()); + Mockito.reset(tenantDao); + Objects.requireNonNull(tenantCache, "Tenant cache manager is null").evict(savedTenant.getId()); verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedTenant); for (int i = 0; i < 100; i++) { @@ -356,15 +360,15 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); savedTenant.setTitle("My new tenant"); savedTenant = tenantService.saveTenant(savedTenant); - reset(tenantDao); + Mockito.reset(tenantDao); - cachedTenant = Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); verify(tenantDao, Mockito.times(0)).findById(any(), any()); @@ -381,184 +385,168 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); tenantService.deleteTenant(savedTenant.getId()); - cachedTenant = Objects.requireNonNull(cacheManager.getCache(CacheConstants.TENANTS_CACHE), "Cache manager is null!").get(savedTenant.getId()); + cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant); } @Test public void testDeleteTenantDeletingAllRelatedEntities() throws Exception { - TenantProfile savedProfile = createAndSaveTenantProfile(); - Tenant savedTenant = createAndSaveTenant(savedProfile); - User savedUser = createAndSaveUserFor(savedTenant); - Customer savedCustomer = createAndSaveCustomerFor(savedTenant); - WidgetsBundle savedWidgetsBundle = createAndSaveWidgetBundleFor(savedTenant); - DeviceProfile savedDeviceProfile = createAndSaveDeviceProfileWithProfileDataFor(savedTenant); - Device savedDevice = createAndSaveDeviceFor(savedTenant, savedCustomer, savedDeviceProfile); - EntityView savedEntityView = createAndSaveEntityViewFor(savedTenant, savedCustomer, savedDevice); - Asset savedAsset = createAndSaveAssetFor(savedTenant, savedCustomer); - Dashboard savedDashboard = createAndSaveDashboardFor(savedTenant, savedCustomer); - RuleChain savedRuleChain = createAndSaveRuleChainFor(savedTenant); - Edge savedEdge = createAndSaveEdgeFor(savedTenant); - OtaPackage savedOtaPackage = createAndSaveOtaPackageFor(savedTenant, savedDeviceProfile); - TbResource savedResource = createAndSaveResourceFor(savedTenant); - Rpc savedRpc = createAndSaveRpcFor(savedTenant, savedDevice); - - tenantService.deleteTenant(savedTenant.getId()); - - Assert.assertNull(tenantService.findTenantById(savedTenant.getId())); - assertCustomerIsDeleted(savedTenant, savedCustomer); - assertWidgetsBundleIsDeleted(savedTenant, savedWidgetsBundle); - assertEntityViewIsDeleted(savedTenant, savedDevice, savedEntityView); - assertAssetIsDeleted(savedTenant, savedAsset); - assertDeviceIsDeleted(savedTenant, savedDevice); - assertDeviceProfileIsDeleted(savedTenant, savedDeviceProfile); - assertDashboardIsDeleted(savedTenant, savedDashboard); - assertEdgeIsDeleted(savedTenant, savedEdge); - assertTenantAdminIsDeleted(savedTenant); - assertUserIsDeleted(savedTenant, savedUser); - Assert.assertNull(ruleChainService.findRuleChainById(savedTenant.getId(), savedRuleChain.getId())); - Assert.assertNull(apiUsageStateService.findTenantApiUsageState(savedTenant.getId())); - assertResourceIsDeleted(savedTenant, savedResource); - assertOtaPackageIsDeleted(savedTenant, savedOtaPackage); - Assert.assertNull(rpcService.findById(savedTenant.getId(), savedRpc.getId())); - - tenantProfileService.deleteTenantProfile(TenantId.SYS_TENANT_ID, savedProfile.getId()); - } - - private void assertOtaPackageIsDeleted(Tenant savedTenant, OtaPackage savedOtaPackage) { - Assert.assertNull( - otaPackageService.findOtaPackageById( - savedTenant.getId(), savedOtaPackage.getId() - ) - ); - PageLink pageLinkOta = new PageLink(1000); - PageData pageDataOta = otaPackageService.findTenantOtaPackagesByTenantId(savedTenant.getId(), pageLinkOta); - Assert.assertFalse(pageDataOta.hasNext()); + TenantProfile profile = createAndSaveTenantProfile(); + Tenant tenant = createAndSaveTenant(profile); + User user = createAndSaveUserFor(tenant); + Customer customer = createAndSaveCustomerFor(tenant); + WidgetsBundle widgetsBundle = createAndSaveWidgetBundleFor(tenant); + DeviceProfile deviceProfile = createAndSaveDeviceProfileWithProfileDataFor(tenant); + Device device = createAndSaveDeviceFor(tenant, customer, deviceProfile); + EntityView entityView = createAndSaveEntityViewFor(tenant, customer, device); + Asset asset = createAndSaveAssetFor(tenant, customer); + Dashboard dashboard = createAndSaveDashboardFor(tenant, customer); + RuleChain ruleChain = createAndSaveRuleChainFor(tenant); + Edge edge = createAndSaveEdgeFor(tenant); + OtaPackage otaPackage = createAndSaveOtaPackageFor(tenant, deviceProfile); + TbResource resource = createAndSaveResourceFor(tenant); + Rpc rpc = createAndSaveRpcFor(tenant, device); + + tenantService.deleteTenant(tenant.getId()); + + Assert.assertNull(tenantService.findTenantById(tenant.getId())); + assertCustomerIsDeleted(tenant, customer); + assertWidgetsBundleIsDeleted(tenant, widgetsBundle); + assertEntityViewIsDeleted(tenant, device, entityView); + assertAssetIsDeleted(tenant, asset); + assertDeviceIsDeleted(tenant, device); + assertDeviceProfileIsDeleted(tenant, deviceProfile); + assertDashboardIsDeleted(tenant, dashboard); + assertEdgeIsDeleted(tenant, edge); + assertTenantAdminIsDeleted(tenant); + assertUserIsDeleted(tenant, user); + Assert.assertNull(ruleChainService.findRuleChainById(tenant.getId(), ruleChain.getId())); + Assert.assertNull(apiUsageStateService.findTenantApiUsageState(tenant.getId())); + assertResourceIsDeleted(tenant, resource); + assertOtaPackageIsDeleted(tenant, otaPackage); + Assert.assertNull(rpcService.findById(tenant.getId(), rpc.getId())); + + tenantProfileService.deleteTenantProfile(TenantId.SYS_TENANT_ID, profile.getId()); + } + + private void assertOtaPackageIsDeleted(Tenant tenant, OtaPackage otaPackage) { + assertThat(otaPackageService.findOtaPackageById(tenant.getId(), otaPackage.getId())) + .as("otaPackage").isNull(); + PageLink pageLinkOta = new PageLink(1); + PageData pageDataOta = otaPackageService.findTenantOtaPackagesByTenantId(tenant.getId(), pageLinkOta); Assert.assertEquals(0, pageDataOta.getTotalElements()); } - private void assertResourceIsDeleted(Tenant savedTenant, TbResource savedResource) { - Assert.assertNull(resourceService.findResourceById(savedTenant.getId(), savedResource.getId())); - PageLink pageLinkResources = new PageLink(1000); + private void assertResourceIsDeleted(Tenant tenant, TbResource resource) { + assertThat(resourceService.findResourceById(tenant.getId(), resource.getId())) + .as("resource").isNull(); + PageLink pageLinkResources = new PageLink(1); PageData tenantResources = - resourceService.findAllTenantResourcesByTenantId(savedTenant.getId(), pageLinkResources); - Assert.assertFalse(tenantResources.hasNext()); + resourceService.findAllTenantResourcesByTenantId(tenant.getId(), pageLinkResources); Assert.assertEquals(0, tenantResources.getTotalElements()); } - private void assertUserIsDeleted(Tenant savedTenant, User savedUser) { - Assert.assertNull(userService.findUserById(savedTenant.getId(), savedUser.getId())); - PageLink pageLinkUsers = new PageLink(1000); + private void assertUserIsDeleted(Tenant tenant, User user) { + assertThat(userService.findUserById(tenant.getId(), user.getId())) + .as("user").isNull(); + PageLink pageLinkUsers = new PageLink(1); PageData users = - userService.findUsersByTenantId(savedTenant.getId(), pageLinkUsers); - Assert.assertFalse(users.hasNext()); + userService.findUsersByTenantId(tenant.getId(), pageLinkUsers); Assert.assertEquals(0, users.getTotalElements()); } private void assertTenantAdminIsDeleted(Tenant savedTenant) { - PageLink pageLinkTenantAdmins = new PageLink(1000); + PageLink pageLinkTenantAdmins = new PageLink(1); PageData tenantAdmins = userService.findTenantAdmins(savedTenant.getId(), pageLinkTenantAdmins); - Assert.assertFalse(tenantAdmins.hasNext()); Assert.assertEquals(0, tenantAdmins.getTotalElements()); } - private void assertEdgeIsDeleted(Tenant savedTenant, Edge savedEdge) { - Assert.assertNull(edgeService.findEdgeById(savedTenant.getId(), savedEdge.getId())); - PageLink pageLinkEdges = new PageLink(1000); - PageData edges = edgeService.findEdgesByTenantId(savedTenant.getId(), pageLinkEdges); - Assert.assertFalse(edges.hasNext()); + private void assertEdgeIsDeleted(Tenant tenant, Edge edge) { + assertThat(edgeService.findEdgeById(tenant.getId(), edge.getId())) + .as("edge").isNull(); + PageLink pageLinkEdges = new PageLink(1); + PageData edges = edgeService.findEdgesByTenantId(tenant.getId(), pageLinkEdges); Assert.assertEquals(0, edges.getTotalElements()); } - private void assertDashboardIsDeleted(Tenant savedTenant, Dashboard savedDashboard) { - Assert.assertNull(dashboardService.findDashboardById( - savedTenant.getId(), savedDashboard.getId() - )); - PageLink pageLinkDashboards = new PageLink(1000); + private void assertDashboardIsDeleted(Tenant tenant, Dashboard dashboard) { + assertThat(dashboardService.findDashboardById(tenant.getId(), dashboard.getId())) + .as("dashboard").isNull(); + PageLink pageLinkDashboards = new PageLink(1); PageData dashboards = - dashboardService.findDashboardsByTenantId(savedTenant.getId(), pageLinkDashboards); - Assert.assertFalse(dashboards.hasNext()); + dashboardService.findDashboardsByTenantId(tenant.getId(), pageLinkDashboards); Assert.assertEquals(0, dashboards.getTotalElements()); } - private void assertDeviceProfileIsDeleted(Tenant savedTenant, DeviceProfile savedDeviceProfile) { - Assert.assertNull(deviceProfileService.findDeviceProfileById( - savedTenant.getId(), savedDeviceProfile.getId() - )); - PageLink pageLinkDeviceProfiles = new PageLink(1000); + private void assertDeviceProfileIsDeleted(Tenant tenant, DeviceProfile deviceProfile) { + assertThat(deviceProfileService.findDeviceProfileById(tenant.getId(), deviceProfile.getId())) + .as("deviceProfile").isNull(); + PageLink pageLinkDeviceProfiles = new PageLink(1); PageData profiles = - deviceProfileService.findDeviceProfiles(savedTenant.getId(), pageLinkDeviceProfiles); - Assert.assertFalse(profiles.hasNext()); + deviceProfileService.findDeviceProfiles(tenant.getId(), pageLinkDeviceProfiles); Assert.assertEquals(0, profiles.getTotalElements()); } - private void assertDeviceIsDeleted(Tenant savedTenant, Device savedDevice) { - Assert.assertNull(deviceService.findDeviceById( - savedTenant.getId(), savedDevice.getId() - )); - PageLink pageLinkDevices = new PageLink(1000); + private void assertDeviceIsDeleted(Tenant tenant, Device device) { + assertThat(deviceService.findDeviceById(tenant.getId(), device.getId())) + .as("device").isNull(); + PageLink pageLinkDevices = new PageLink(1); PageData devices = - deviceService.findDevicesByTenantId(savedTenant.getId(), pageLinkDevices); - Assert.assertFalse(devices.hasNext()); + deviceService.findDevicesByTenantId(tenant.getId(), pageLinkDevices); Assert.assertEquals(0, devices.getTotalElements()); } - private void assertAssetIsDeleted(Tenant savedTenant, Asset savedAsset) { - Assert.assertNull(assetService.findAssetById( - savedTenant.getId(), savedAsset.getId() - )); - PageLink pageLinkAssets = new PageLink(1000); + private void assertAssetIsDeleted(Tenant tenant, Asset asset) { + assertThat(assetService.findAssetById(tenant.getId(), asset.getId())) + .as("asset").isNull(); + PageLink pageLinkAssets = new PageLink(1); PageData assets = - assetService.findAssetsByTenantId(savedTenant.getId(), pageLinkAssets); - Assert.assertFalse(assets.hasNext()); + assetService.findAssetsByTenantId(tenant.getId(), pageLinkAssets); Assert.assertEquals(0, assets.getTotalElements()); } - private void assertEntityViewIsDeleted(Tenant savedTenant, Device savedDevice, EntityView savedEntityView) { - Assert.assertNull(entityViewService.findEntityViewById( - savedTenant.getId(), savedEntityView.getId() - )); + private void assertEntityViewIsDeleted(Tenant tenant, Device device, EntityView entityView) { + assertThat(entityViewService.findEntityViewById(tenant.getId(), entityView.getId())) + .as("entityView").isNull(); List entityViews = - entityViewService.findEntityViewsByTenantIdAndEntityId( - savedTenant.getId(), savedDevice.getId()); + entityViewService.findEntityViewsByTenantIdAndEntityId(tenant.getId(), device.getId()); Assert.assertTrue(entityViews.isEmpty()); } - private void assertWidgetsBundleIsDeleted(Tenant savedTenant, WidgetsBundle savedWidgetsBundle) { - Assert.assertNull( - widgetsBundleService.findWidgetsBundleById(savedTenant.getId(), savedWidgetsBundle.getId()) - ); + private void assertWidgetsBundleIsDeleted(Tenant tenant, WidgetsBundle widgetsBundle) { + assertThat(widgetsBundleService.findWidgetsBundleById(tenant.getId(), widgetsBundle.getId())) + .as("widgetBundle").isNull(); List widgetsBundlesByTenantId = - widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(savedTenant.getId()); + widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenant.getId()); Assert.assertTrue(widgetsBundlesByTenantId.isEmpty()); } - private void assertCustomerIsDeleted(Tenant savedTenant, Customer savedCustomer) { - Assert.assertNull(customerService.findCustomerById(savedTenant.getId(), savedCustomer.getId())); - PageLink pageLinkCustomer = new PageLink(1000); + private void assertCustomerIsDeleted(Tenant tenant, Customer customer) { + assertThat(customerService.findCustomerById(tenant.getId(), customer.getId())) + .as("customer").isNull(); + PageLink pageLinkCustomer = new PageLink(1); PageData pageDataCustomer = customerService - .findCustomersByTenantId(savedTenant.getId(), pageLinkCustomer); - Assert.assertFalse(pageDataCustomer.hasNext()); + .findCustomersByTenantId(tenant.getId(), pageLinkCustomer); Assert.assertEquals(0, pageDataCustomer.getTotalElements()); } - private Rpc createAndSaveRpcFor(Tenant savedTenant, Device savedDevice) { + private Rpc createAndSaveRpcFor(Tenant tenant, Device device) { Rpc rpc = new Rpc(); - rpc.setTenantId(savedTenant.getId()); - rpc.setDeviceId(savedDevice.getId()); + rpc.setTenantId(tenant.getId()); + rpc.setDeviceId(device.getId()); rpc.setStatus(RpcStatus.QUEUED); rpc.setRequest(JacksonUtil.toJsonNode("{}")); return rpcService.save(rpc); } - private TbResource createAndSaveResourceFor(Tenant savedTenant) { + private TbResource createAndSaveResourceFor(Tenant tenant) { TbResource resource = new TbResource(); - resource.setTenantId(savedTenant.getId()); + resource.setTenantId(tenant.getId()); resource.setTitle("Test resource"); resource.setResourceType(ResourceType.LWM2M_MODEL); resource.setFileName("filename.txt"); @@ -567,47 +555,49 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { return resourceService.saveResource(resource); } - private OtaPackage createAndSaveOtaPackageFor(Tenant savedTenant, DeviceProfile savedDeviceProfile) { - OtaPackage otaPackage = createFirmware(savedTenant.getId(), savedDeviceProfile.getId()); - return otaPackageService.saveOtaPackage(otaPackage); + private OtaPackage createAndSaveOtaPackageFor(Tenant tenant, DeviceProfile deviceProfile) { + return otaPackageService.saveOtaPackage( + BaseOtaPackageServiceTest.createFirmware( + tenant.getId(), "2", deviceProfile.getId()) + ); } - private Edge createAndSaveEdgeFor(Tenant savedTenant) { - Edge edge = constructEdge(savedTenant.getId(), "Test edge", "Simple"); + private Edge createAndSaveEdgeFor(Tenant tenant) { + Edge edge = constructEdge(tenant.getId(), "Test edge", "Simple"); return edgeService.saveEdge(edge, false); } - private RuleChain createAndSaveRuleChainFor(Tenant savedTenant) { + private RuleChain createAndSaveRuleChainFor(Tenant tenant) { RuleChain ruleChain = new RuleChain(); - ruleChain.setTenantId(savedTenant.getId()); + ruleChain.setTenantId(tenant.getId()); ruleChain.setName("Test rule chain"); ruleChain.setType(RuleChainType.CORE); return ruleChainService.saveRuleChain(ruleChain); } - private Dashboard createAndSaveDashboardFor(Tenant savedTenant, Customer savedCustomer) { + private Dashboard createAndSaveDashboardFor(Tenant tenant, Customer customer) { Dashboard dashboard = new Dashboard(); - dashboard.setTenantId(savedTenant.getId()); + dashboard.setTenantId(tenant.getId()); dashboard.setTitle("Test dashboard"); - dashboard.setAssignedCustomers(Set.of(savedCustomer.toShortCustomerInfo())); + dashboard.setAssignedCustomers(Set.of(customer.toShortCustomerInfo())); return dashboardService.saveDashboard(dashboard); } - private Asset createAndSaveAssetFor(Tenant savedTenant, Customer savedCustomer) { + private Asset createAndSaveAssetFor(Tenant tenant, Customer customer) { Asset asset = new Asset(); - asset.setTenantId(savedTenant.getId()); - asset.setCustomerId(savedCustomer.getId()); + asset.setTenantId(tenant.getId()); + asset.setCustomerId(customer.getId()); asset.setType("Test asset type"); asset.setName("Test asset type"); asset.setLabel("Test asset type"); return assetService.saveAsset(asset); } - private EntityView createAndSaveEntityViewFor(Tenant savedTenant, Customer savedCustomer, Device savedDevice) { + private EntityView createAndSaveEntityViewFor(Tenant tenant, Customer customer, Device device) { EntityView entityView = new EntityView(); - entityView.setEntityId(savedDevice.getId()); - entityView.setTenantId(savedTenant.getId()); - entityView.setCustomerId(savedCustomer.getId()); + entityView.setEntityId(device.getId()); + entityView.setTenantId(tenant.getId()); + entityView.setCustomerId(customer.getId()); entityView.setType("Test type"); entityView.setName("Test entity view"); entityView.setStartTimeMs(0); @@ -615,20 +605,20 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { return entityViewService.saveEntityView(entityView); } - private Device createAndSaveDeviceFor(Tenant savedTenant, Customer savedCustomer, DeviceProfile savedDeviceProfile) { + private Device createAndSaveDeviceFor(Tenant tenant, Customer customer, DeviceProfile deviceProfile) { Device device = new Device(); - device.setCustomerId(savedCustomer.getId()); - device.setTenantId(savedTenant.getId()); + device.setCustomerId(customer.getId()); + device.setTenantId(tenant.getId()); device.setType("Test type"); device.setName("TestType"); device.setLabel("Test type"); - device.setDeviceProfileId(savedDeviceProfile.getId()); + device.setDeviceProfileId(deviceProfile.getId()); return deviceService.saveDevice(device); } - private DeviceProfile createAndSaveDeviceProfileWithProfileDataFor(Tenant savedTenant) { + private DeviceProfile createAndSaveDeviceProfileWithProfileDataFor(Tenant tenant) { DeviceProfile deviceProfile = new DeviceProfile(); - deviceProfile.setTenantId(savedTenant.getId()); + deviceProfile.setTenantId(tenant.getId()); deviceProfile.setTransportType(DeviceTransportType.MQTT); deviceProfile.setName("Test device profile"); deviceProfile.setType(DeviceProfileType.DEFAULT); @@ -638,37 +628,37 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { return deviceProfileService.saveDeviceProfile(deviceProfile); } - private WidgetsBundle createAndSaveWidgetBundleFor(Tenant savedTenant) { + private WidgetsBundle createAndSaveWidgetBundleFor(Tenant tenant) { WidgetsBundle widgetsBundle = new WidgetsBundle(); - widgetsBundle.setTenantId(savedTenant.getId()); + widgetsBundle.setTenantId(tenant.getId()); widgetsBundle.setTitle("Test widgets bundle"); widgetsBundle.setAlias("TestWidgetsBundle"); widgetsBundle.setDescription("Just a simple widgets bundle"); return widgetsBundleService.saveWidgetsBundle(widgetsBundle); } - private Customer createAndSaveCustomerFor(Tenant savedTenant) { + private Customer createAndSaveCustomerFor(Tenant tenant) { Customer customer = new Customer(); customer.setTitle("Test customer"); - customer.setTenantId(savedTenant.getId()); + customer.setTenantId(tenant.getId()); customer.setEmail("testCustomer@test.com"); return customerService.saveCustomer(customer); } - private User createAndSaveUserFor(Tenant savedTenant) { + private User createAndSaveUserFor(Tenant tenant) { User user = new User(); user.setAuthority(Authority.TENANT_ADMIN); user.setEmail("tenantAdmin@test.com"); user.setFirstName("tenantAdmin"); user.setLastName("tenantAdmin"); - user.setTenantId(savedTenant.getId()); + user.setTenantId(tenant.getId()); return userService.saveUser(user); } - private Tenant createAndSaveTenant(TenantProfile savedProfile) { + private Tenant createAndSaveTenant(TenantProfile tenantProfile) { Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); - tenant.setTenantProfileId(savedProfile.getId()); + tenant.setTenantProfileId(tenantProfile.getId()); return tenantService.saveTenant(tenant); } @@ -677,20 +667,4 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenantProfile.setName("Test tenant profile"); return tenantProfileService.saveTenantProfile(TenantId.SYS_TENANT_ID, tenantProfile); } - - private OtaPackage createFirmware(TenantId tenantId, DeviceProfileId deviceProfileId) { - OtaPackage firmware = new OtaPackage(); - firmware.setTenantId(tenantId); - firmware.setDeviceProfileId(deviceProfileId); - firmware.setType(FIRMWARE); - firmware.setTitle("My firmware"); - firmware.setVersion("1"); - firmware.setFileName("filename.txt"); - firmware.setContentType("text/plain"); - firmware.setChecksumAlgorithm(ChecksumAlgorithm.SHA256); - firmware.setChecksum("4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"); - firmware.setData(ByteBuffer.wrap(new byte[]{(int) 1L})); - firmware.setDataSize(1L); - return otaPackageService.saveOtaPackage(firmware); - } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java index 28eafabfce..14d6a11489 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java @@ -124,7 +124,7 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode checkRelation(TbContext ctx, SearchDirectionIds sdId, String relationType) { - return ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON); + return ctx.getRelationService().checkRelationAsync(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON); } private ListenableFuture processCreateRelation(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java index b51c960900..116c46f9ad 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java @@ -98,7 +98,7 @@ public class TbDeleteRelationNode extends TbAbstractRelationActionNode processSingle(TbContext ctx, TbMsg msg, EntityContainer entityContainer, String relationType) { SearchDirectionIds sdId = processSingleSearchDirection(msg, entityContainer); - return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON), + return Futures.transformAsync(ctx.getRelationService().checkRelationAsync(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON), result -> { if (result) { return processSingleDeleteRelation(ctx, sdId, relationType); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java index f2eb539a3e..77158fe05e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java @@ -82,7 +82,7 @@ public class TbCheckRelationNode implements TbNode { to = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId()); from = msg.getOriginator(); } - return ctx.getRelationService().checkRelation(ctx.getTenantId(), from, to, config.getRelationType(), RelationTypeGroup.COMMON); + return ctx.getRelationService().checkRelationAsync(ctx.getTenantId(), from, to, config.getRelationType(), RelationTypeGroup.COMMON); } private ListenableFuture processList(TbContext ctx, TbMsg msg) { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java index b1e96f228e..352bbacc23 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java @@ -113,7 +113,7 @@ public class TbCreateRelationNodeTest { metaData.putValue("type", "AssetType"); msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - when(ctx.getRelationService().checkRelation(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) .thenReturn(Futures.immediateFuture(true)); @@ -144,7 +144,7 @@ public class TbCreateRelationNodeTest { when(ctx.getRelationService().findByToAndTypeAsync(any(), eq(msg.getOriginator()), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(Collections.singletonList(relation))); when(ctx.getRelationService().deleteRelationAsync(any(), eq(relation))).thenReturn(Futures.immediateFuture(true)); - when(ctx.getRelationService().checkRelation(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) .thenReturn(Futures.immediateFuture(true)); @@ -171,7 +171,7 @@ public class TbCreateRelationNodeTest { metaData.putValue("type", "AssetType"); msg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, "{}", ruleChainId, ruleNodeId); - when(ctx.getRelationService().checkRelation(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) + when(ctx.getRelationService().checkRelationAsync(any(), eq(assetId), eq(deviceId), eq(RELATION_TYPE_CONTAINS), eq(RelationTypeGroup.COMMON))) .thenReturn(Futures.immediateFuture(false)); when(ctx.getRelationService().saveRelationAsync(any(), eq(new EntityRelation(assetId, deviceId, RELATION_TYPE_CONTAINS, RelationTypeGroup.COMMON)))) .thenReturn(Futures.immediateFuture(true)); From c28e13c03c289ca8b54a9c9a357ee28c8a19a74f Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 20 Jan 2022 17:09:20 +0200 Subject: [PATCH 14/41] remove todo --- .../thingsboard/server/dao/entityview/EntityViewServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 17bccd93c3..4ab8f279c3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -447,7 +447,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti throw new DataValidationException("Entity view should be assigned to tenant!"); } else { Tenant tenant = tenantService.findTenantById(entityView.getTenantId()); - // TODO: 13.01.22 Instead of finding and checking for null need to create and use tenantService.exists() if (tenant == null) { throw new DataValidationException("Entity view is referencing to non-existent tenant!"); } From fdc318a526dcd1a25e3bcb3b87abe64a6f5f6827 Mon Sep 17 00:00:00 2001 From: desoliture Date: Fri, 21 Jan 2022 11:32:05 +0200 Subject: [PATCH 15/41] fix RelationService and TenantServiceTest --- .../server/dao/relation/BaseRelationService.java | 6 ++++-- .../server/dao/service/BaseTenantServiceTest.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 1f5f4ffbe2..b1f3fda91d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -75,14 +75,16 @@ public class BaseRelationService implements RelationService { @Override public ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { - log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup); + log.trace("Executing checkRelationAsync [{}][{}][{}][{}]", from, to, relationType, typeGroup); validate(from, to, relationType, typeGroup); return relationDao.checkRelationAsync(tenantId, from, to, relationType, typeGroup); } @Override public Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { - return null; + log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup); + validate(from, to, relationType, typeGroup); + return relationDao.checkRelation(tenantId, from, to, relationType, typeGroup); } @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType, #typeGroup}") diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index b36467a307..3c4009144d 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -329,7 +329,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { } @Test - public void testGettingTenantAddItToCache() { + public void testGettingTenantAddingItToCache() { Tenant tenant = new Tenant(); tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); From 6d1969447b3c8b8736a319437652d73a8e712b68 Mon Sep 17 00:00:00 2001 From: desoliture Date: Fri, 21 Jan 2022 16:55:39 +0200 Subject: [PATCH 16/41] add 'exists' method in TenantService and make it cacheable, update corresponding test --- .../server/dao/tenant/TenantService.java | 4 +- .../server/dao/tenant/TenantServiceImpl.java | 18 +++++-- .../dao/service/BaseTenantServiceTest.java | 53 ++++++++++++++++--- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index 01c4d9b4e2..899d85993f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -31,7 +31,9 @@ public interface TenantService { ListenableFuture findTenantByIdAsync(TenantId callerId, TenantId tenantId); Tenant saveTenant(Tenant tenant); - + + boolean exists(TenantId tenantId); + void deleteTenant(TenantId tenantId); PageData findTenants(PageLink pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 50fe23f22b..48c86d8241 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.springframework.context.annotation.Lazy; import org.springframework.transaction.annotation.Transactional; @@ -107,7 +108,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe private RpcService rpcService; @Override - @Cacheable(cacheNames = TENANTS_CACHE, key = "#tenantId") + @Cacheable(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'TENANT'}") public Tenant findTenantById(TenantId tenantId) { log.trace("Executing findTenantById [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); @@ -130,7 +131,10 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional - @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenant.id", condition = "#tenant.id!=null") + @Caching(evict = { + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'TENANT'}", condition = "#tenant.id!=null"), + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'EXISTS'}", condition = "#tenant.id!=null") + }) public Tenant saveTenant(Tenant tenant) { log.trace("Executing saveTenant [{}]", tenant); tenant.setRegion(DEFAULT_TENANT_REGION); @@ -149,7 +153,10 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional(timeout = 60 * 60) - @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenantId") + @Caching(evict = { + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'TENANT'}"), + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'EXISTS'}") + }) public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); @@ -198,6 +205,11 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe return tenantDao.findTenantsIds(pageLink); } + @Cacheable(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'EXISTS'}") + public boolean exists(TenantId tenantId) { + return tenantDao.existsById(tenantId, tenantId.getId()); + } + private DataValidator tenantValidator = new DataValidator() { @Override diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 3c4009144d..9021f1fd8a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -335,14 +335,14 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Mockito.reset(tenantDao); - Objects.requireNonNull(tenantCache, "Tenant cache manager is null").evict(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Tenant cache manager is null").evict(List.of(savedTenant.getId(), "TENANT")); verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedTenant); for (int i = 0; i < 100; i++) { @@ -353,6 +353,30 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenantService.deleteTenant(savedTenant.getId()); } + @Test + public void testExistsTenantAddingResultToCache() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + + Mockito.reset(tenantDao); + + verify(tenantDao, Mockito.times(0)).existsById(any(), any()); + tenantService.exists(savedTenant.getId()); + verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + + Cache.ValueWrapper cachedExists = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); + Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedExists); + + for (int i = 0; i < 100; i++) { + tenantService.exists(savedTenant.getId()); + } + verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + + tenantService.deleteTenant(savedTenant.getId()); + } + @Test public void testUpdatingExistingTenantEvictCache() { Tenant tenant = new Tenant(); @@ -360,7 +384,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); savedTenant.setTitle("My new tenant"); @@ -368,13 +392,19 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Mockito.reset(tenantDao); - cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + Mockito.reset(tenantDao); + + verify(tenantDao, Mockito.times(0)).existsById(any(), any()); + tenantService.exists(savedTenant.getId()); + verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + tenantService.deleteTenant(savedTenant.getId()); } @@ -384,13 +414,24 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); + tenantService.exists(savedTenant.getId()); + Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + Cache.ValueWrapper cachedExists = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); + Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedExists); tenantService.deleteTenant(savedTenant.getId()); - cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + cachedTenant = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + cachedExists = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); + + Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant); + Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedExists); } @Test From 27efb4adfc48075e5f2df96c6630f39c93167d84 Mon Sep 17 00:00:00 2001 From: desoliture Date: Fri, 21 Jan 2022 18:49:35 +0200 Subject: [PATCH 17/41] replace getting tenant and checking it for null to invocations of 'exists' method --- .../org/thingsboard/server/dao/alarm/BaseAlarmService.java | 3 +-- .../org/thingsboard/server/dao/asset/BaseAssetService.java | 3 +-- .../thingsboard/server/dao/customer/CustomerServiceImpl.java | 3 +-- .../server/dao/dashboard/DashboardServiceImpl.java | 3 +-- .../server/dao/device/DeviceProfileServiceImpl.java | 3 +-- .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 3 +-- .../java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java | 3 +-- .../server/dao/entityview/EntityViewServiceImpl.java | 3 +-- .../org/thingsboard/server/dao/ota/BaseOtaPackageService.java | 4 +--- .../thingsboard/server/dao/resource/BaseResourceService.java | 3 +-- .../org/thingsboard/server/dao/rule/BaseRuleChainService.java | 3 +-- .../server/dao/usagerecord/ApiUsageStateServiceImpl.java | 3 +-- .../java/org/thingsboard/server/dao/user/UserServiceImpl.java | 4 +--- .../thingsboard/server/dao/widget/WidgetTypeServiceImpl.java | 3 +-- .../server/dao/widget/WidgetsBundleServiceImpl.java | 3 +-- 15 files changed, 15 insertions(+), 32 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index e2e1d54935..1390cdf2d3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -430,8 +430,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getTenantId() == null) { throw new DataValidationException("Alarm should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(alarm.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(alarm.getTenantId())) { throw new DataValidationException("Alarm is referencing to non-existent tenant!"); } } 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 2610aff3e3..f1b84eac21 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 @@ -411,8 +411,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ if (asset.getTenantId() == null) { throw new DataValidationException("Asset should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(asset.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(asset.getTenantId())) { throw new DataValidationException("Asset is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 3b2376f98d..a0ba27e8bf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -210,8 +210,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom if (customer.getTenantId() == null) { throw new DataValidationException("Customer should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(customer.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(customer.getTenantId())) { throw new DataValidationException("Customer is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index a27d69f7ee..c04f25079f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -308,8 +308,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb if (dashboard.getTenantId() == null) { throw new DataValidationException("Dashboard should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(dashboard.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(dashboard.getTenantId())) { throw new DataValidationException("Dashboard is referencing to non-existent tenant!"); } } 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 254b84889b..561f703bb9 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 @@ -375,8 +375,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (deviceProfile.getTenantId() == null) { throw new DataValidationException("Device profile should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(deviceProfile.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(deviceProfile.getTenantId())) { throw new DataValidationException("Device profile is referencing to non-existent tenant!"); } } 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 00d393c4bd..a2f289532c 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 @@ -731,8 +731,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe if (device.getTenantId() == null) { throw new DataValidationException("Device should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(device.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(device.getTenantId())) { throw new DataValidationException("Device is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 281848a68d..5af1ffe506 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -413,8 +413,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic if (edge.getTenantId() == null) { throw new DataValidationException("Edge should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(edge.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(edge.getTenantId())) { throw new DataValidationException("Edge is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 4ab8f279c3..1ac8e91bac 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -446,8 +446,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti if (entityView.getTenantId() == null) { throw new DataValidationException("Entity view should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(entityView.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(entityView.getTenantId())) { throw new DataValidationException("Entity view is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index 734c96b1c7..a9f1c83330 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -357,9 +357,7 @@ public class BaseOtaPackageService implements OtaPackageService { if (otaPackageInfo.getTenantId() == null) { throw new DataValidationException("OtaPackage should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(otaPackageInfo.getTenantId()); - // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() - if (tenant == null) { + if (!tenantService.exists(otaPackageInfo.getTenantId())) { throw new DataValidationException("OtaPackage is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 2511a7ec6a..013d754959 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -183,8 +183,7 @@ public class BaseResourceService implements ResourceService { resource.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantService.findTenantById(resource.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(resource.getTenantId())) { throw new DataValidationException("Resource is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 1ef88f5450..1c5e0e893d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -726,8 +726,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (ruleChain.getTenantId() == null || ruleChain.getTenantId().isNullUid()) { throw new DataValidationException("Rule chain should be assigned to tenant!"); } - Tenant tenant = tenantService.findTenantById(ruleChain.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(ruleChain.getTenantId())) { throw new DataValidationException("Rule chain is referencing to non-existent tenant!"); } if (ruleChain.isRoot() && RuleChainType.CORE.equals(ruleChain.getType())) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index 8cb4e17598..4635136a67 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -164,8 +164,7 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A if (apiUsageState.getTenantId() == null) { throw new DataValidationException("ApiUsageState should be assigned to tenant!"); } else { - Tenant tenant = tenantService.findTenantById(apiUsageState.getTenantId()); - if (tenant == null && !requestTenantId.equals(TenantId.SYS_TENANT_ID)) { + if (!tenantService.exists(apiUsageState.getTenantId()) && !requestTenantId.equals(TenantId.SYS_TENANT_ID)) { throw new DataValidationException("ApiUsageState is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 171cb5fbd1..3032a5a8ad 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -448,9 +448,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic + " already present in database!"); } if (!tenantId.getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantService.findTenantById(user.getTenantId()); - // TODO: 12.01.22 Instead of finding and checking for null need to create and use tenantService.exists() - if (tenant == null) { + if (!tenantService.exists(user.getTenantId())) { throw new DataValidationException("User is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index e2fe57ca74..24f6ce905d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -138,8 +138,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { widgetTypeDetails.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!widgetTypeDetails.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantService.findTenantById(widgetTypeDetails.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(widgetTypeDetails.getTenantId())) { throw new DataValidationException("Widget type is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 2bea7f3ade..18900e7e28 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -162,8 +162,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { widgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - Tenant tenant = tenantService.findTenantById(widgetsBundle.getTenantId()); - if (tenant == null) { + if (!tenantService.exists(widgetsBundle.getTenantId())) { throw new DataValidationException("Widgets bundle is referencing to non-existent tenant!"); } } From 6121f96a9cedeb367276f62f57f4ecddd6a075b7 Mon Sep 17 00:00:00 2001 From: desoliture Date: Tue, 25 Jan 2022 12:43:23 +0200 Subject: [PATCH 18/41] BaseTenantServiceTest --- .../thingsboard/server/dao/service/BaseTenantServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 9021f1fd8a..96737a6c75 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -360,6 +360,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Mockito.reset(tenantDao); + tenantCache.clear(); verify(tenantDao, Mockito.times(0)).existsById(any(), any()); tenantService.exists(savedTenant.getId()); From 54c48e1166802d8cff75cfa73bca6c6625c5cce9 Mon Sep 17 00:00:00 2001 From: deso-deso Date: Tue, 25 Jan 2022 13:35:47 +0200 Subject: [PATCH 19/41] refactor tenantExists method --- .../org/thingsboard/server/dao/tenant/TenantService.java | 2 +- .../thingsboard/server/dao/alarm/BaseAlarmService.java | 3 +-- .../thingsboard/server/dao/asset/BaseAssetService.java | 4 +--- .../server/dao/customer/CustomerServiceImpl.java | 4 +--- .../server/dao/dashboard/DashboardServiceImpl.java | 3 +-- .../server/dao/device/DeviceProfileServiceImpl.java | 3 +-- .../thingsboard/server/dao/device/DeviceServiceImpl.java | 4 +--- .../org/thingsboard/server/dao/edge/EdgeServiceImpl.java | 3 +-- .../server/dao/entityview/EntityViewServiceImpl.java | 4 +--- .../thingsboard/server/dao/ota/BaseOtaPackageService.java | 3 +-- .../server/dao/resource/BaseResourceService.java | 3 +-- .../thingsboard/server/dao/rule/BaseRuleChainService.java | 3 +-- .../thingsboard/server/dao/tenant/TenantServiceImpl.java | 7 ++----- .../server/dao/usagerecord/ApiUsageStateServiceImpl.java | 2 +- .../org/thingsboard/server/dao/user/UserServiceImpl.java | 3 +-- .../server/dao/widget/WidgetTypeServiceImpl.java | 3 +-- .../server/dao/widget/WidgetsBundleServiceImpl.java | 3 +-- .../server/dao/service/BaseTenantServiceTest.java | 8 ++++---- 18 files changed, 22 insertions(+), 43 deletions(-) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index 899d85993f..6a521c2b5e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -32,7 +32,7 @@ public interface TenantService { Tenant saveTenant(Tenant tenant); - boolean exists(TenantId tenantId); + boolean tenantExists(TenantId tenantId); void deleteTenant(TenantId tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 1390cdf2d3..49c75914b6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -27,7 +27,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; @@ -430,7 +429,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getTenantId() == null) { throw new DataValidationException("Alarm should be assigned to tenant!"); } else { - if (!tenantService.exists(alarm.getTenantId())) { + if (!tenantService.tenantExists(alarm.getTenantId())) { throw new DataValidationException("Alarm is referencing to non-existent tenant!"); } } 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 f1b84eac21..1823f47db7 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 @@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetInfo; import org.thingsboard.server.common.data.asset.AssetSearchQuery; @@ -62,7 +61,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.CacheConstants.ASSET_CACHE; @@ -411,7 +409,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ if (asset.getTenantId() == null) { throw new DataValidationException("Asset should be assigned to tenant!"); } else { - if (!tenantService.exists(asset.getTenantId())) { + if (!tenantService.tenantExists(asset.getTenantId())) { throw new DataValidationException("Asset is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index a0ba27e8bf..dc6375f521 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -25,7 +25,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -35,7 +34,6 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.entity.AbstractEntityService; -import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.service.DataValidator; @@ -210,7 +208,7 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom if (customer.getTenantId() == null) { throw new DataValidationException("Customer should be assigned to tenant!"); } else { - if (!tenantService.exists(customer.getTenantId())) { + if (!tenantService.tenantExists(customer.getTenantId())) { throw new DataValidationException("Customer is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index c04f25079f..18ae67da43 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -26,7 +26,6 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; @@ -308,7 +307,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb if (dashboard.getTenantId() == null) { throw new DataValidationException("Dashboard should be assigned to tenant!"); } else { - if (!tenantService.exists(dashboard.getTenantId())) { + if (!tenantService.tenantExists(dashboard.getTenantId())) { throw new DataValidationException("Dashboard is referencing to non-existent tenant!"); } } 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 561f703bb9..60735d80ef 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 @@ -45,7 +45,6 @@ import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.OtaPackage; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; @@ -375,7 +374,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D if (deviceProfile.getTenantId() == null) { throw new DataValidationException("Device profile should be assigned to tenant!"); } else { - if (!tenantService.exists(deviceProfile.getTenantId())) { + if (!tenantService.tenantExists(deviceProfile.getTenantId())) { throw new DataValidationException("Device profile is referencing to non-existent tenant!"); } } 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 a2f289532c..66eabed0e1 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 @@ -43,7 +43,6 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.OtaPackage; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfiguration; @@ -91,7 +90,6 @@ import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.UUID; -import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CACHE; @@ -731,7 +729,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe if (device.getTenantId() == null) { throw new DataValidationException("Device should be assigned to tenant!"); } else { - if (!tenantService.exists(device.getTenantId())) { + if (!tenantService.tenantExists(device.getTenantId())) { throw new DataValidationException("Device is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 5af1ffe506..d90884bc59 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -34,7 +34,6 @@ import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeInfo; @@ -413,7 +412,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic if (edge.getTenantId() == null) { throw new DataValidationException("Edge should be assigned to tenant!"); } else { - if (!tenantService.exists(edge.getTenantId())) { + if (!tenantService.tenantExists(edge.getTenantId())) { throw new DataValidationException("Edge is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 1ac8e91bac..9dbab008ed 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityViewInfo; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; @@ -61,7 +60,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Optional; -import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE; @@ -446,7 +444,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti if (entityView.getTenantId() == null) { throw new DataValidationException("Entity view should be assigned to tenant!"); } else { - if (!tenantService.exists(entityView.getTenantId())) { + if (!tenantService.tenantExists(entityView.getTenantId())) { throw new DataValidationException("Entity view is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index a9f1c83330..daf4aeb5b2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.StringUtils; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.TenantId; @@ -357,7 +356,7 @@ public class BaseOtaPackageService implements OtaPackageService { if (otaPackageInfo.getTenantId() == null) { throw new DataValidationException("OtaPackage should be assigned to tenant!"); } else { - if (!tenantService.exists(otaPackageInfo.getTenantId())) { + if (!tenantService.tenantExists(otaPackageInfo.getTenantId())) { throw new DataValidationException("OtaPackage is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index 013d754959..6d3d29540b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -24,7 +24,6 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -183,7 +182,7 @@ public class BaseResourceService implements ResourceService { resource.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - if (!tenantService.exists(resource.getTenantId())) { + if (!tenantService.tenantExists(resource.getTenantId())) { throw new DataValidationException("Resource is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 1c5e0e893d..9b01af1832 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -30,7 +30,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; @@ -726,7 +725,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (ruleChain.getTenantId() == null || ruleChain.getTenantId().isNullUid()) { throw new DataValidationException("Rule chain should be assigned to tenant!"); } - if (!tenantService.exists(ruleChain.getTenantId())) { + if (!tenantService.tenantExists(ruleChain.getTenantId())) { throw new DataValidationException("Rule chain is referencing to non-existent tenant!"); } if (ruleChain.isRoot() && RuleChainType.CORE.equals(ruleChain.getType())) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 48c86d8241..6d685bceb9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -131,10 +131,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional - @Caching(evict = { - @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'TENANT'}", condition = "#tenant.id!=null"), - @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'EXISTS'}", condition = "#tenant.id!=null") - }) + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'TENANT'}", condition = "#tenant.id!=null") public Tenant saveTenant(Tenant tenant) { log.trace("Executing saveTenant [{}]", tenant); tenant.setRegion(DEFAULT_TENANT_REGION); @@ -206,7 +203,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe } @Cacheable(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'EXISTS'}") - public boolean exists(TenantId tenantId) { + public boolean tenantExists(TenantId tenantId) { return tenantDao.existsById(tenantId, tenantId.getId()); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index 4635136a67..a9864b1e1e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -164,7 +164,7 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A if (apiUsageState.getTenantId() == null) { throw new DataValidationException("ApiUsageState should be assigned to tenant!"); } else { - if (!tenantService.exists(apiUsageState.getTenantId()) && !requestTenantId.equals(TenantId.SYS_TENANT_ID)) { + if (!tenantService.tenantExists(apiUsageState.getTenantId()) && !requestTenantId.equals(TenantId.SYS_TENANT_ID)) { throw new DataValidationException("ApiUsageState is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 3032a5a8ad..6647958965 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -31,7 +31,6 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -448,7 +447,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic + " already present in database!"); } if (!tenantId.getId().equals(ModelConstants.NULL_UUID)) { - if (!tenantService.exists(user.getTenantId())) { + if (!tenantService.tenantExists(user.getTenantId())) { throw new DataValidationException("User is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 24f6ce905d..42195fdfda 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; @@ -138,7 +137,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { widgetTypeDetails.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!widgetTypeDetails.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - if (!tenantService.exists(widgetTypeDetails.getTenantId())) { + if (!tenantService.tenantExists(widgetTypeDetails.getTenantId())) { throw new DataValidationException("Widget type is referencing to non-existent tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 18900e7e28..0a9c23c972 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -19,7 +19,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.page.PageData; @@ -162,7 +161,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { widgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID)); } if (!widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) { - if (!tenantService.exists(widgetsBundle.getTenantId())) { + if (!tenantService.tenantExists(widgetsBundle.getTenantId())) { throw new DataValidationException("Widgets bundle is referencing to non-existent tenant!"); } } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 96737a6c75..c48bdd1dcf 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -363,7 +363,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenantCache.clear(); verify(tenantDao, Mockito.times(0)).existsById(any(), any()); - tenantService.exists(savedTenant.getId()); + tenantService.tenantExists(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); Cache.ValueWrapper cachedExists = @@ -371,7 +371,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedExists); for (int i = 0; i < 100; i++) { - tenantService.exists(savedTenant.getId()); + tenantService.tenantExists(savedTenant.getId()); } verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); @@ -403,7 +403,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Mockito.reset(tenantDao); verify(tenantDao, Mockito.times(0)).existsById(any(), any()); - tenantService.exists(savedTenant.getId()); + tenantService.tenantExists(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); tenantService.deleteTenant(savedTenant.getId()); @@ -415,7 +415,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); - tenantService.exists(savedTenant.getId()); + tenantService.tenantExists(savedTenant.getId()); Cache.ValueWrapper cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); From 80df8d1a4583d5f001044a42278004e7d7c82b55 Mon Sep 17 00:00:00 2001 From: deso-deso Date: Tue, 25 Jan 2022 18:52:48 +0200 Subject: [PATCH 20/41] fix test --- .../server/dao/service/BaseTenantServiceTest.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index c48bdd1dcf..216d23d71f 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -393,19 +393,13 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Mockito.reset(tenantDao); - cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); + cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); - Mockito.reset(tenantDao); - - verify(tenantDao, Mockito.times(0)).existsById(any(), any()); - tenantService.tenantExists(savedTenant.getId()); - verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); - tenantService.deleteTenant(savedTenant.getId()); } From 1687c5ba774c29661070d0168b7f191fe8d487f4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 10 Jun 2022 12:56:32 +0200 Subject: [PATCH 21/41] fixed antisamy vulnerabilities --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 78c4ae6fa2..e8f6990ec7 100755 --- a/pom.xml +++ b/pom.xml @@ -119,7 +119,7 @@ 6.0.20.Final 3.0.0 2.0.1.Final - 1.6.4 + 1.6.8 2.8.5 4.1.0 From d965f85f22852d6921c9641667943b242c234879 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 10 Jun 2022 13:15:57 +0200 Subject: [PATCH 22/41] fixed gson vulnerabilities --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e8f6990ec7..aa29e71bf0 100755 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ 2.2.6 3.0.0 2.0.0-M5 - 2.6.2 + 2.9.0 2.3.30 1.6.2 4.2.0 From a1e812bc0c856150272b67565162b226a46b16f2 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 10 Jun 2022 14:21:35 +0200 Subject: [PATCH 23/41] fixed spring vulnerabilities --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index aa29e71bf0..2f2bcdab5c 100755 --- a/pom.xml +++ b/pom.xml @@ -39,9 +39,9 @@ 1.3.2 2.3.2 2.3.2 - 2.5.12 + 2.5.14 2.5.10 - 5.3.18 + 5.3.20 5.5.10 5.6.2 2.5.10 From 98c78cd511d8c9b6822f538fd6733866fadda1fa Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 10 Jun 2022 20:02:56 +0200 Subject: [PATCH 24/41] updated spring redis and spring security versions --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 2f2bcdab5c..3c34cd0f4c 100755 --- a/pom.xml +++ b/pom.xml @@ -40,11 +40,11 @@ 2.3.2 2.3.2 2.5.14 - 2.5.10 + 2.5.11 5.3.20 - 5.5.10 - 5.6.2 - 2.5.10 + 5.5.12 + 5.6.5 + 2.5.11 3.7.1 0.7.0 1.7.32 From 08d5cb5e930d71fa5f3116ba47e01ff89c3b19a2 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Sat, 11 Jun 2022 15:05:14 +0200 Subject: [PATCH 25/41] migrated spring boot to version 2.7 due to vulnerabilities --- ...ngfoxHandlerProviderBeanPostProcessor.java | 61 +++++++++++++++++++ .../ThingsboardSecurityConfiguration.java | 15 +++-- .../resources/application-test.properties | 2 + pom.xml | 12 ++-- 4 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java diff --git a/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java b/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java new file mode 100644 index 0000000000..7e53c7f120 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java @@ -0,0 +1,61 @@ +/** + * 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.config; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; +import org.thingsboard.server.queue.util.TbCoreComponent; +import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.stream.Collectors; + +@TbCoreComponent +@Component +//TODO: remove after fixing issue https://github.com/springfox/springfox/issues/3462 or after migration from springfox to springdoc +public class SpringfoxHandlerProviderBeanPostProcessor implements BeanPostProcessor { + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof WebMvcRequestHandlerProvider) { + customizeSpringfoxHandlerMappings(getHandlerMappings(bean)); + } + return bean; + } + + private void customizeSpringfoxHandlerMappings(List mappings) { + List copy = mappings.stream() + .filter(mapping -> mapping.getPatternParser() == null) + .collect(Collectors.toList()); + mappings.clear(); + mappings.addAll(copy); + } + + @SuppressWarnings("unchecked") + private List getHandlerMappings(Object bean) { + try { + Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings"); + field.setAccessible(true); + return (List) field.get(bean); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java index 823bbf35e3..76c631bddb 100644 --- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java @@ -181,13 +181,18 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt @Autowired private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver; + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring().antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**"); + } + @Override protected void configure(HttpSecurity http) throws Exception { - http.authorizeHttpRequests((authorizeHttpRequests) -> - authorizeHttpRequests - .antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**") - .permitAll() - ); +// http.authorizeHttpRequests((authorizeHttpRequests) -> +// authorizeHttpRequests +// .antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**") +// .permitAll() +// ); http.headers().cacheControl().and().frameOptions().disable() .and() .cors() diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index 518c9b42d3..279d1e99be 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -55,3 +55,5 @@ queue.rule-engine.queues[2].partitions=2 queue.rule-engine.queues[2].processing-strategy.retries=1 queue.rule-engine.queues[2].processing-strategy.pause-between-retries=0 queue.rule-engine.queues[2].processing-strategy.max-pause-between-retries=0 + +usage.stats.report.enabled=false \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3c34cd0f4c..770b9ed9f5 100755 --- a/pom.xml +++ b/pom.xml @@ -39,12 +39,12 @@ 1.3.2 2.3.2 2.3.2 - 2.5.14 - 2.5.11 + 2.7.0 + 2.7.0 5.3.20 5.5.12 - 5.6.5 - 2.5.11 + 5.7.1 + 2.7.0 3.7.1 0.7.0 1.7.32 @@ -112,7 +112,7 @@ 1.4.3 1.9.4 3.2.2 - 1.8.3 + 1.9.0 1.0.3TB 3.4.0 8.17.0 @@ -127,7 +127,7 @@ 2.7.2 2.6.1 1.5.2 - 5.7.2 + 5.8.2 2.6.0 1.3.0 1.2.7 From 50f307260889e79d1e83e1675c27bcafd2eec218 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 13 Jun 2022 10:13:39 +0200 Subject: [PATCH 26/41] allow circular references --- .../config/SpringfoxHandlerProviderBeanPostProcessor.java | 2 +- transport/coap/src/main/resources/tb-coap-transport.yml | 2 ++ transport/http/src/main/resources/tb-http-transport.yml | 2 ++ transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 2 ++ transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 2 ++ transport/snmp/src/main/resources/tb-snmp-transport.yml | 2 ++ 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java b/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java index 7e53c7f120..feec10c86f 100644 --- a/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java +++ b/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java @@ -27,7 +27,7 @@ import java.lang.reflect.Field; import java.util.List; import java.util.stream.Collectors; -@TbCoreComponent +//@TbCoreComponent @Component //TODO: remove after fixing issue https://github.com/springfox/springfox/issues/3462 or after migration from springfox to springdoc public class SpringfoxHandlerProviderBeanPostProcessor implements BeanPostProcessor { diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 5262fbaef1..ef25058751 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -19,6 +19,8 @@ spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" +spring.main.allow-circular-references: "true" + server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 7574687ecc..1478f88f4d 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -14,6 +14,8 @@ # limitations under the License. # +spring.main.allow-circular-references: "true" + server: # Server bind address address: "${HTTP_BIND_ADDRESS:0.0.0.0}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 19d70e0bc2..387c0f95ed 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -19,6 +19,8 @@ spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" +spring.main.allow-circular-references: "true" + server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 1a6f04e598..14339f5056 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -19,6 +19,8 @@ spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" +spring.main.allow-circular-references: "true" + server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 6ff1a37442..82060defb3 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -19,6 +19,8 @@ spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" +spring.main.allow-circular-references: "true" + server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" From 619cabf514ca14a13c1cb0892d645e92959888b9 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 13 Jun 2022 16:55:28 +0200 Subject: [PATCH 27/41] fixed install app --- .../org/thingsboard/server/ThingsboardInstallApplication.java | 4 +++- .../SpringfoxHandlerProviderBeanPostProcessor.java | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) rename application/src/main/java/org/thingsboard/server/{config => springfox}/SpringfoxHandlerProviderBeanPostProcessor.java (97%) diff --git a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java index efc1e55701..e90ed98351 100644 --- a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java +++ b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java @@ -32,7 +32,9 @@ import java.util.Arrays; "org.thingsboard.server.dao", "org.thingsboard.server.common.stats", "org.thingsboard.server.common.transport.config.ssl", - "org.thingsboard.server.cache"}) + "org.thingsboard.server.cache", + "org.thingsboard.server.springfox" +}) public class ThingsboardInstallApplication { private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; diff --git a/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java b/application/src/main/java/org/thingsboard/server/springfox/SpringfoxHandlerProviderBeanPostProcessor.java similarity index 97% rename from application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java rename to application/src/main/java/org/thingsboard/server/springfox/SpringfoxHandlerProviderBeanPostProcessor.java index feec10c86f..af03c72004 100644 --- a/application/src/main/java/org/thingsboard/server/config/SpringfoxHandlerProviderBeanPostProcessor.java +++ b/application/src/main/java/org/thingsboard/server/springfox/SpringfoxHandlerProviderBeanPostProcessor.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.config; +package org.thingsboard.server.springfox; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; @@ -27,7 +27,6 @@ import java.lang.reflect.Field; import java.util.List; import java.util.stream.Collectors; -//@TbCoreComponent @Component //TODO: remove after fixing issue https://github.com/springfox/springfox/issues/3462 or after migration from springfox to springdoc public class SpringfoxHandlerProviderBeanPostProcessor implements BeanPostProcessor { From 539390e6b54736857a3e4ff51831ee3e6b8f00ba Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 15 Jun 2022 16:21:00 +0300 Subject: [PATCH 28/41] UI: Improvement function validateDatasources added validation for required label in dataKey setting --- ui-ngx/src/app/core/services/utils.service.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui-ngx/src/app/core/services/utils.service.ts b/ui-ngx/src/app/core/services/utils.service.ts index fcef76f612..b901b87328 100644 --- a/ui-ngx/src/app/core/services/utils.service.ts +++ b/ui-ngx/src/app/core/services/utils.service.ts @@ -284,6 +284,11 @@ export class UtilsService { if (!datasource.dataKeys) { datasource.dataKeys = []; } + datasource.dataKeys.forEach(dataKey => { + if (isUndefined(dataKey.label)) { + dataKey.label = dataKey.name; + } + }); }); return datasources; } From 66cc42644e78f0b82d11e2919a1fe6ebe92bfaa7 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 16 Jun 2022 15:18:25 +0300 Subject: [PATCH 29/41] UI: Improvement image-map when image attr empty set default image --- ui-ngx/src/app/core/utils.ts | 2 +- .../components/widget/lib/maps/providers/image-map.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index 37d2f1f652..96fad967a1 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -96,7 +96,7 @@ export function isEmptyStr(value: any): boolean { } export function isNotEmptyStr(value: any): boolean { - return value !== null && typeof value === 'string' && value.trim().length > 0; + return typeof value === 'string' && value.trim().length > 0; } export function isFunction(value: any): boolean { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index 783ebd2096..dd03604a9a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -27,7 +27,7 @@ import { WidgetContext } from '@home/models/widget-component.models'; import { DataSet, DatasourceType, widgetType } from '@shared/models/widget.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { WidgetSubscriptionOptions } from '@core/api/widget-api.models'; -import { isDefinedAndNotNull, isEmptyStr, parseFunction } from '@core/utils'; +import { isDefinedAndNotNull, isEmptyStr, isNotEmptyStr, parseFunction } from '@core/utils'; import { EntityDataPageLink } from '@shared/models/query/query.models'; const maxZoom = 4; // ? @@ -93,10 +93,12 @@ export class ImageMap extends LeafletMap { type: widgetType.latest, callbacks: { onDataUpdated: (subscription) => { - if (subscription.data[0]?.data[0]?.length > 0) { + if (isNotEmptyStr(subscription.data[0]?.data[0]?.[1])) { result.next([subscription.data[0].data, isUpdate]); - isUpdate = true; + } else { + result.next([[[0, options.mapImageUrl]], isUpdate]); } + isUpdate = true; } } }; From 2b18b44a52da9861b6a53a9ca8f9bc8adcf05399 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 16 Jun 2022 22:04:26 +0200 Subject: [PATCH 30/41] added tenant cache --- .../validator/ApiUsageDataValidator.java | 8 ++-- .../service/validator/UserDataValidator.java | 3 +- .../server/dao/tenant/TenantCacheKey.java | 45 +++++++++++++++++ .../dao/tenant/TenantCaffeineCache.java | 33 +++++++++++++ .../server/dao/tenant/TenantEvictEvent.java | 26 ++++++++++ .../dao/tenant/TenantExistsCaffeineCache.java | 33 +++++++++++++ .../dao/tenant/TenantExistsRedisCache.java | 35 ++++++++++++++ .../server/dao/tenant/TenantRedisCache.java | 35 ++++++++++++++ .../server/dao/tenant/TenantServiceImpl.java | 41 ++++++++++------ .../dao/service/BaseTenantServiceTest.java | 48 +++++++++---------- .../resources/application-test.properties | 4 +- 11 files changed, 265 insertions(+), 46 deletions(-) create mode 100644 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/ApiUsageDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/ApiUsageDataValidator.java index 0e1634c06e..28e4dc0582 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/ApiUsageDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/ApiUsageDataValidator.java @@ -15,7 +15,8 @@ */ package org.thingsboard.server.dao.service.validator; -import lombok.AllArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.EntityType; @@ -25,10 +26,11 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.tenant.TenantService; @Component -@AllArgsConstructor public class ApiUsageDataValidator extends DataValidator { - private final TenantService tenantService; + @Lazy + @Autowired + private TenantService tenantService; @Override protected void validateDataImpl(TenantId requestTenantId, ApiUsageState apiUsageState) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java index 3e6831084b..21e2143f1a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java @@ -21,7 +21,6 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -32,7 +31,6 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.tenant.TenantDao; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserDao; import org.thingsboard.server.dao.user.UserService; @@ -55,6 +53,7 @@ public class UserDataValidator extends DataValidator { private TbTenantProfileCache tenantProfileCache; @Autowired + @Lazy private TenantService tenantService; @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java new file mode 100644 index 0000000000..8a0af86faa --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java @@ -0,0 +1,45 @@ +/** + * 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.dao.tenant; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.TenantProfileId; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +public class TenantCacheKey implements Serializable { + + private static final long serialVersionUID = -121787454251592384L; + + private final TenantId tenantId; + private final TenantCacheKeyPrefix keyPrefix; + + public static TenantCacheKey fromId(TenantId tenantId) { + return new TenantCacheKey(tenantId, TenantCacheKeyPrefix.TENANT); + } + + public static TenantCacheKey fromIdExists(TenantId tenantId) { + return new TenantCacheKey(tenantId, TenantCacheKeyPrefix.EXISTS); + } + + public enum TenantCacheKeyPrefix { + TENANT, EXISTS + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java new file mode 100644 index 0000000000..e6ae0d930f --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java @@ -0,0 +1,33 @@ +/** + * 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.dao.tenant; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CaffeineTbTransactionalCache; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.Tenant; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) +@Service("TenantCache") +public class TenantCaffeineCache extends CaffeineTbTransactionalCache { + + public TenantCaffeineCache(CacheManager cacheManager) { + super(cacheManager, CacheConstants.TENANTS_CACHE); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java new file mode 100644 index 0000000000..2bd28ae511 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java @@ -0,0 +1,26 @@ +/** + * 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.dao.tenant; + +import lombok.Data; +import org.thingsboard.server.common.data.id.TenantId; + +@Data +public class TenantEvictEvent { + private final TenantId tenantId; + // for exists tenant cache + private final boolean isExistsTenant; +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java new file mode 100644 index 0000000000..c7b25a5059 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java @@ -0,0 +1,33 @@ +/** + * 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.dao.tenant; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CaffeineTbTransactionalCache; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.Tenant; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) +@Service("TenantExistsCache") +public class TenantExistsCaffeineCache extends CaffeineTbTransactionalCache { + + public TenantExistsCaffeineCache(CacheManager cacheManager) { + super(cacheManager, CacheConstants.TENANTS_CACHE); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java new file mode 100644 index 0000000000..4f938bf690 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java @@ -0,0 +1,35 @@ +/** + * 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.dao.tenant; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CacheSpecsMap; +import org.thingsboard.server.cache.RedisTbTransactionalCache; +import org.thingsboard.server.cache.TBRedisCacheConfiguration; +import org.thingsboard.server.cache.TbRedisSerializer; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.Tenant; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") +@Service("TenantExistsCache") +public class TenantExistsRedisCache extends RedisTbTransactionalCache { + + public TenantExistsRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { + super(CacheConstants.TENANTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>()); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java new file mode 100644 index 0000000000..195e781755 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java @@ -0,0 +1,35 @@ +/** + * 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.dao.tenant; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.CacheSpecsMap; +import org.thingsboard.server.cache.RedisTbTransactionalCache; +import org.thingsboard.server.cache.TBRedisCacheConfiguration; +import org.thingsboard.server.cache.TbRedisSerializer; +import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.Tenant; + +@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") +@Service("TenantCache") +public class TenantRedisCache extends RedisTbTransactionalCache { + + public TenantRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { + super(CacheConstants.TENANTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>()); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index edc1afe033..4ae1ec49e0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -18,12 +18,11 @@ package org.thingsboard.server.dao.tenant; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.event.TransactionalEventListener; +import org.thingsboard.server.cache.TbTransactionalCache; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; @@ -36,7 +35,7 @@ import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.entity.AbstractEntityService; +import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.resource.ResourceService; @@ -51,12 +50,11 @@ import org.thingsboard.server.dao.widget.WidgetsBundleService; import java.util.List; -import static org.thingsboard.server.common.data.CacheConstants.TENANTS_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; @Service @Slf4j -public class TenantServiceImpl extends AbstractEntityService implements TenantService { +public class TenantServiceImpl extends AbstractCachedEntityService implements TenantService { private static final String DEFAULT_TENANT_REGION = "Global"; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; @@ -83,6 +81,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Autowired private DeviceProfileService deviceProfileService; + @Lazy @Autowired private ApiUsageStateService apiUsageStateService; @@ -110,12 +109,26 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Autowired private QueueService queueService; + @Autowired + protected TbTransactionalCache existsTenantCache; + + @TransactionalEventListener(classes = TenantEvictEvent.class) + @Override + public void handleEvictEvent(TenantEvictEvent event) { + TenantId tenantId = event.getTenantId(); + cache.evict(TenantCacheKey.fromId(tenantId)); + if (event.isExistsTenant()) { + existsTenantCache.evict(TenantCacheKey.fromIdExists(tenantId)); + } + } + @Override - @Cacheable(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'TENANT'}") public Tenant findTenantById(TenantId tenantId) { log.trace("Executing findTenantById [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - return tenantDao.findById(tenantId, tenantId.getId()); + + return cache.getAndPutInTransaction(TenantCacheKey.fromId(tenantId), + () -> tenantDao.findById(tenantId, tenantId.getId()), true); } @Override @@ -134,7 +147,6 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional - @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'TENANT'}", condition = "#tenant.id!=null") public Tenant saveTenant(Tenant tenant) { log.trace("Executing saveTenant [{}]", tenant); tenant.setRegion(DEFAULT_TENANT_REGION); @@ -144,6 +156,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe } tenantValidator.validate(tenant, Tenant::getId); Tenant savedTenant = tenantDao.save(tenant.getId(), tenant); + publishEvictEvent(new TenantEvictEvent(savedTenant.getId(), false)); if (tenant.getId() == null) { deviceProfileService.createDefaultDeviceProfile(savedTenant.getId()); apiUsageStateService.createDefaultApiUsageState(savedTenant.getId(), null); @@ -153,10 +166,6 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional(timeout = 60 * 60) - @Caching(evict = { - @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'TENANT'}"), - @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'EXISTS'}") - }) public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); @@ -176,6 +185,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe rpcService.deleteAllRpcByTenantId(tenantId); queueService.deleteQueuesByTenantId(tenantId); tenantDao.removeById(tenantId, tenantId.getId()); + publishEvictEvent(new TenantEvictEvent(tenantId, true)); deleteEntityRelations(tenantId, tenantId); } @@ -212,9 +222,10 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe return tenantDao.findTenantsIds(pageLink); } - @Cacheable(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'EXISTS'}") + @Override public boolean tenantExists(TenantId tenantId) { - return tenantDao.existsById(tenantId, tenantId.getId()); + return existsTenantCache.getAndPutInTransaction(TenantCacheKey.fromIdExists(tenantId), + () -> tenantDao.existsById(tenantId, tenantId.getId()), false); } private PaginatedRemover tenantsRemover = new PaginatedRemover<>() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index fbcb563131..d893a1ba40 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -25,6 +25,8 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.cache.TbCacheValueWrapper; +import org.thingsboard.server.cache.TbTransactionalCache; import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; @@ -59,6 +61,7 @@ import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileCon import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.tenant.TenantCacheKey; import org.thingsboard.server.dao.tenant.TenantDao; import java.util.ArrayList; @@ -80,14 +83,10 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { protected TenantDao tenantDao; @Autowired - CacheManager cacheManager; + protected TbTransactionalCache cache; - private Cache tenantCache; - - @Before - public void setup() { - tenantCache = cacheManager.getCache(CacheConstants.TENANTS_CACHE); - } + @Autowired + protected TbTransactionalCache existsTenantCache; @Test public void testSaveTenant() { @@ -155,7 +154,6 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { @Test public void testFindTenants() { - List tenants = new ArrayList<>(); PageLink pageLink = new PageLink(17); PageData pageData = tenantService.findTenants(pageLink); @@ -335,15 +333,14 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Mockito.reset(tenantDao); - Objects.requireNonNull(tenantCache, "Tenant cache manager is null").evict(List.of(savedTenant.getId(), "TENANT")); verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); - Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + var cachedTenant = cache.get(TenantCacheKey.fromId(savedTenant.getId())); Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedTenant); + Assert.assertEquals(savedTenant, cachedTenant.get()); for (int i = 0; i < 100; i++) { tenantService.findTenantById(savedTenant.getId()); @@ -360,15 +357,15 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Mockito.reset(tenantDao); - tenantCache.clear(); + //fromIdExists invoked from device profile validator + existsTenantCache.evict(TenantCacheKey.fromIdExists(savedTenant.getTenantId())); verify(tenantDao, Mockito.times(0)).existsById(any(), any()); tenantService.tenantExists(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); - Cache.ValueWrapper cachedExists = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); - Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedExists); + var isExists = existsTenantCache.get(TenantCacheKey.fromIdExists(savedTenant.getId())); + Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", isExists); for (int i = 0; i < 100; i++) { tenantService.tenantExists(savedTenant.getId()); @@ -384,16 +381,18 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); - Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + tenantService.findTenantById(savedTenant.getId()); + + var cachedTenant = cache.get(TenantCacheKey.fromId(savedTenant.getId())); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); + Assert.assertEquals(savedTenant, cachedTenant.get()); savedTenant.setTitle("My new tenant"); savedTenant = tenantService.saveTenant(savedTenant); Mockito.reset(tenantDao); - cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + cachedTenant = cache.get(TenantCacheKey.fromId(savedTenant.getId())); Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); verify(tenantDao, Mockito.times(0)).findById(any(), any()); @@ -409,20 +408,21 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); + tenantService.findTenantById(savedTenant.getId()); tenantService.tenantExists(savedTenant.getId()); - Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); - Cache.ValueWrapper cachedExists = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); + var cachedTenant = + cache.get(TenantCacheKey.fromId(savedTenant.getId())); + var cachedExists = + existsTenantCache.get(TenantCacheKey.fromIdExists(savedTenant.getId())); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedExists); tenantService.deleteTenant(savedTenant.getId()); cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + cache.get(TenantCacheKey.fromId(savedTenant.getId())); cachedExists = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); + existsTenantCache.get(TenantCacheKey.fromIdExists(savedTenant.getId())); Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant); diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index 936aa30bfc..063b1275d1 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -35,8 +35,8 @@ cache.specs.entityViews.maxSize=100000 cache.specs.claimDevices.timeToLiveInMinutes=1440 cache.specs.claimDevices.maxSize=100000 -caffeine.specs.tenants.timeToLiveInMinutes=1440 -caffeine.specs.tenants.maxSize=100000 +cache.specs.tenants.timeToLiveInMinutes=1440 +cache.specs.tenants.maxSize=100000 cache.specs.securitySettings.timeToLiveInMinutes=1440 cache.specs.securitySettings.maxSize=100000 From 2457fdf317660c185ab29dc6c00d6660fb9f0992 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 17 Jun 2022 12:10:40 +0300 Subject: [PATCH 31/41] UI: Fixed incorrect show fullscreen dialog in sm display(600-959px) --- .../script/node-script-test.service.ts | 2 +- .../add-rule-node-dialog.component.html | 2 +- .../add-rule-node-dialog.component.scss | 26 +++++++++++++++++++ .../rulechain/rulechain-page.component.ts | 2 +- ui-ngx/src/styles.scss | 4 +-- 5 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.scss diff --git a/ui-ngx/src/app/core/services/script/node-script-test.service.ts b/ui-ngx/src/app/core/services/script/node-script-test.service.ts index 7428bc40f5..5dcdb192af 100644 --- a/ui-ngx/src/app/core/services/script/node-script-test.service.ts +++ b/ui-ngx/src/app/core/services/script/node-script-test.service.ts @@ -85,7 +85,7 @@ export class NodeScriptTestService { return this.dialog.open(NodeScriptTestDialogComponent, { disableClose: true, - panelClass: ['tb-dialog', 'tb-fullscreen-dialog', 'tb-fullscreen-dialog-gt-sm'], + panelClass: ['tb-dialog', 'tb-fullscreen-dialog', 'tb-fullscreen-dialog-gt-xs'], data: { msg, metadata, diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html index baea44755c..a8ae57a458 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+

rulenode.add

: {{ruleNode.component.name}} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.scss new file mode 100644 index 0000000000..2057868837 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/rulechain/add-rule-node-dialog.component.scss @@ -0,0 +1,26 @@ +/** + * 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. + */ +@import './../scss/constants'; + +:host { + .dialog-container { + min-width: 650px !important; + + @media #{$mat-lt-md} { + min-width: 100% !important; + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 843616cce0..0640dee39f 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -1677,7 +1677,7 @@ export interface AddRuleNodeDialogData { selector: 'tb-add-rule-node-dialog', templateUrl: './add-rule-node-dialog.component.html', providers: [{provide: ErrorStateMatcher, useExisting: AddRuleNodeDialogComponent}], - styleUrls: [] + styleUrls: ['./add-rule-node-dialog.component.scss'] }) export class AddRuleNodeDialogComponent extends DialogComponent implements OnInit, ErrorStateMatcher { diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index b6bf5fdfd2..8c6fffabf1 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -1263,8 +1263,8 @@ mat-label { } } - .tb-fullscreen-dialog-gt-sm { - @media #{$mat-gt-sm} { + .tb-fullscreen-dialog-gt-xs { + @media #{$mat-gt-xs} { min-height: 100%; min-width: 100%; max-width: none !important; From 9af37b263601003e8f656763b7dee2ff175b006b Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 17 Jun 2022 17:35:33 +0300 Subject: [PATCH 32/41] UI: Fixed incorrect close add widget panel with the escape key --- .../home/components/dashboard-page/dashboard-page.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index dd7212cf5b..580ef0e2f8 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -228,6 +228,7 @@ [opened]="isEditingWidget || isAddingWidget" (openedStart)="detailsDrawerOpenedStart()" (closed)="detailsDrawerClosed()" + disableClose mode="over" position="end"> Date: Mon, 20 Jun 2022 19:05:00 +0200 Subject: [PATCH 33/41] Add vc spanish translations --- .../assets/locale/locale.constant-es_ES.json | 143 +++++++++++++++++- 1 file changed, 138 insertions(+), 5 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-es_ES.json b/ui-ngx/src/assets/locale/locale.constant-es_ES.json index 56b85eac62..a684aaa568 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -59,7 +59,9 @@ "read-more": "Leer más", "hide": "Ocultar", "done": "Terminado", - "print": "Imprimir" + "print": "Imprimir", + "restore": "Restaurar", + "confirm": "Confirmar" }, "aggregation": { "aggregation": "Agrupación", @@ -322,6 +324,30 @@ "queue-submit-strategy": "Estrategia de envíos", "queue-processing-strategy": "Estrategia de procesamiento", "queue-configuration": "Configuración Cola", + "repository-settings": "Ajustes del repositorio", + "repository-url": "URL del repositorio", + "repository-url-required": "Se requiere la URL del repositorio.", + "default-branch": "Nombre de rama por defecto", + "authentication-settings": "Ajustes de autenticación", + "auth-method": "Método de autenticación", + "auth-method-username-password": "Usuario / Contraseña", + "auth-method-private-key": "Clave privada", + "password-access-token": "Contraseña / Tóken de acceso", + "change-password-access-token": "Cambiar contraseña / Tóken de acceso", + "private-key": "Clave privada", + "drop-private-key-file-or": "Arrastrar y soltar un fichero de llave privada o", + "passphrase": "Frase de contraseña", + "enter-passphrase": "Entrar frase de contraseña", + "change-passphrase": "Cambiar frase de contraseña", + "check-access": "Verificar acceso", + "check-repository-access-success": "Acceso al repositorio verificado satisfactoriamente!", + "delete-repository-settings-title": "Estás seguro de borrar los ajustes del repositorio?", + "delete-repository-settings-text": "Atención, tras la confirmación los ajustes del repositorio serán eliminados y la característica de control de versiones no estará disponible.", + "auto-commit-settings": "Ajustes Auto-publicar", + "auto-commit-entities": "Entidades Auto-publicar", + "no-auto-commit-entities-prompt": "No hay entidades configuradas para auto-publicar", + "delete-auto-commit-settings-title": "Estás seguro de borrar los ajustes de auto-publicar?", + "delete-auto-commit-settings-text": "Atención, tras la confirmación los ajustes de auto-publicar serán borrados y la característica de auto-publicar se desactivará para todas las entidades.", "2fa": { "2fa": "Autenticación de dos factores (2FA)", "available-providers": "Proveedores disponibles", @@ -485,7 +511,7 @@ "management": "Gestión de Activos", "view-assets": "Ver Activos", "add": "Añadir Activo", - + "asset-type-max-length": "El tipo de activo debe ser menor de 256", "assign-to-customer": "Asignar a cliente", "assign-asset-to-customer": "Asignar Activo(s) A Cliente", "assign-asset-to-customer-text": "Selecciona los activos a asignar al cliente", @@ -937,6 +963,8 @@ "assignedToCustomer": "Asignado al cliente", "assignedToCustomers": "Asignado a los clientes", "public": "Público", + "copyId": "Copiar ID del panel", + "idCopiedMessage": "El ID del panel ha sido copiado al portapapeles", "public-link": "Link público", "copy-public-link": "Copiar link público", "public-link-copied-message": "El link público del panel se ha copiado al portapapeles", @@ -1817,6 +1845,9 @@ "type-current-tenant": "Propietario Actual", "type-current-user": "Usuario Actual", "type-current-user-owner": "Usuario Propietario Actual", + "type-widgets-bundle": "Paquete de widgets", + "type-widgets-bundles": "Paquetes de widgets", + "list-of-widgets-bundles": "{ count, plural, 1 {Un paquete de widget} other {Lista de # paquetes de widgets} }", "search": "Buscar entidades", "selected-entities": "{ count, plural, 1 {1 entidad} other {# entidades} } seleccionadas", "entity-label": "Etiqueta de entidad", @@ -2246,6 +2277,7 @@ "current-device": "Dispositivo actual", "default-value": "Valor por defecto", "dynamic-source-type": "Tipo de origen dinámico", + "dynamic-value": "Valor dinámico", "no-dynamic-value": "Sin valor dinámico", "source-attribute": "Atributo de origen", "switch-to-dynamic-value": "Cambiar a valor dinámico", @@ -2488,7 +2520,7 @@ "request-password-reset": "Solicitar restablecer contraseña", "reset-password": "Restablecer contraseña", "create-password": "Crear contraseña", - "two-factor-authentication": "Two factor authentication", + "two-factor-authentication": "Autenticado de dos factores", "passwords-mismatch-error": "¡Las contraseñas introducidas deben ser iguales!", "password-again": "Repita la contraseña de nuevo", "sign-in": "Por favor, inicie sesión", @@ -2601,7 +2633,8 @@ "change-password": "Cambiar contraseña", "current-password": "Contraseña actual", "copy-jwt-token": "Copiar JWT", - "valid-till": "Válido hasta {{expirationData}}", + "jwt-token": "Tóken JWT", + "token-valid-till": "Válido hasta {{expirationData}}", "tokenCopiedSuccessMessage": "JWT copiado al portapapeles", "tokenCopiedWarnMessage": "JWT caducado, por favor actualiza la página." }, @@ -2660,6 +2693,20 @@ "backup-code-description": "Estos códigos de seguridad imprimibles son de un solo uso, te permiten identificarte cuando no tengas el teléfono a mano, útil cuando se viaja.", "backup-code-hint": "{{ info }} códigos de un solo uso activos en este momento" } + }, + "password-requirement": { + "at-least": "Al menos:", + "character": "{ count, plural, 1 {1 caracter} other {# caracteres} }", + "digit": "{ count, plural, 1 {1 dígito} other {# dígitos} }", + "incorrect-password-try-again": "Contraseña incorrecta. Prueba otra vez", + "lowercase-letter": "{ count, plural, 1 {1 minúscula} other {# mínusculas} }", + "new-passwords-not-match": "Las contraseñas no coinciden", + "password-should-not-contain-spaces": "La contraseña no puede contener espacios", + "password-not-meet-requirements": "La contraseña no reune los requisitos necesarios", + "password-requirements": "Requisitos de contraseña", + "password-should-difference": "La nueva contraseña debe ser diferente a la actual", + "special-character": "{ count, plural, 1 {1 caracter especial} other {# caracteres especiales} }", + "uppercase-letter": "{ count, plural, 1 {1 mayúscula} other {# mayúsculas} }" } }, "relation": { @@ -3053,6 +3100,8 @@ "transport-device-msg-rate-limit": "Tasa de mensajes de dispositivo.", "transport-device-telemetry-msg-rate-limit": "Tasa de mensajes de telemetría de dispositivo.", "transport-device-telemetry-data-points-rate-limit": "Tasa de datapoints de telemetría de dispositivo.", + "tenant-entity-export-rate-limit": "Tasa de creación de versión de entidades", + "tenant-entity-import-rate-limit": "Tasa de carga de versión de entidades", "max-transport-messages": "Nº Máximo de mensajes de transporte (0 - sin límite)", "max-transport-messages-required": "Nº Máximo de mensajes de transporte requerido.", "max-transport-messages-range": "Nº Máximo de mensajes de transporte no puede ser negativo", @@ -3091,7 +3140,22 @@ "max-created-alarms-range": "Nº Máximo de alarmas creadas no puede ser negativo", "no-queue": "No Queue configured", "add-queue": "Add Queue", - "queues-with-count": "Queues ({{count}})" + "queues-with-count": "Queues ({{count}})", + "tenant-rest-limits": "Rate limit for REST requests for tenant", + "customer-rest-limits": "Rate limit for REST requests for customer", + "incorrect-pattern-for-rate-limits": "The format is comma separated pairs of capacity and period (in seconds) with a colon between, e.g. 100:1,2000:60", + "too-small-value-zero": "The value must be bigger than 0", + "too-small-value-one": "The value must be bigger than 1", + "cassandra-tenant-limits-configuration": "Cassandra query rate limit for tenant", + "ws-limit-max-sessions-per-tenant": "Maximum number of WS sessions per tenant", + "ws-limit-max-sessions-per-customer": "Maximum number of WS sessions per customer", + "ws-limit-max-sessions-per-public-user": "Maximum number of WS sessions per public user", + "ws-limit-queue-per-session": "Maximum size of WS message queue per session", + "ws-limit-max-subscriptions-per-tenant": "Maximum number of WS subscriptions per tenant", + "ws-limit-max-subscriptions-per-customer": "Maximum number of WS subscriptions per customer", + "ws-limit-max-subscriptions-per-regular-user": "Maximum number of WS subscriptions per regular user", + "ws-limit-max-subscriptions-per-public-user": "Maximum number of WS subscriptions per public user", + "ws-limit-updates-per-session": "Rate limit for WS updates per session" }, "timeinterval": { "seconds-interval": "{ seconds, plural, 1 {1 segundo} other {# segundos} }", @@ -3220,6 +3284,68 @@ "json-value-invalid": "El valor JSON tiene un formato inválido", "json-value-required": "Se requiere valor JSON" }, + "version-control": { + "version-control": "Control de Versión", + "management": "Administrador de versiones", + "branch": "Rama", + "default": "Por defecto", + "select-branch": "Seleccionar rama", + "branch-required": "Se requiere rama", + "create-entity-version": "Versión creación de entidad", + "version-name": "Nombre de versión", + "version-name-required": "Se requiere nombre de versión", + "author": "Autor", + "export-relations": "Exportar relaciones", + "export-attributes": "Exportar atributos", + "export-credentials": "Exportar credenciales", + "entity-versions": "Versiones de entidad", + "versions": "Versiones", + "created-time": "Hora de creación", + "version-id": "ID de versión", + "no-entity-versions-text": "No se han encontrado versiones de entidad", + "no-versions-text": "No se han encontrado versiones", + "copy-full-version-id": "Copiar el ID de versión", + "create-version": "Crear versión", + "nothing-to-commit": "No hay cambios a publicar", + "restore-version": "Restaurar versión", + "restore-entity-from-version": "Restaurar entidad desde versión '{{versionName}}'", + "load-relations": "Cargar relaciones", + "load-attributes": "Cargar atributos", + "load-credentials": "Cargar credencialess", + "show-version-diff": "Mostrar diff de versión", + "diff-entity-with-version": "Diff de la versión de entidad '{{versionName}}'", + "previous-difference": "Anterior diferencia", + "next-difference": "Siguiente diferencia", + "current": "Actual", + "differences": "{ count, plural, 1 {1 diferencia} other {# diferencias} }", + "create-entities-version": "Crear versión de entidades", + "default-sync-strategy": "Estrategia de sincronización por defecto", + "sync-strategy-merge": "Combinar (Merge)", + "sync-strategy-overwrite": "Sobreescribir", + "entities-to-export": "Entidades a exportar", + "entities-to-restore": "Entidades a restaurar", + "sync-strategy": "Estrategia de sincronización", + "all-entities": "Todas las entidades", + "no-entities-to-export-prompt": "Por favor, especifica las entidades a exportar", + "no-entities-to-restore-prompt": "Por favor, especifica las entidades a restaurar", + "add-entity-type": "Añadir tipo de entidad", + "remove-all": "Borrar todo", + "version-create-result": "{ added, plural, 0 {Ninguna entidad} 1 {1 entidad} other {# entidades} } añadidas.
{ modified, plural, 0 {Ninguna entidad} 1 {1 entidad} other {# entidades} } modificadas.
{ removed, plural, 0 {Ninguna entidad} 1 {1 entidad} other {# entidades} } borradas.", + "remove-other-entities": "Borrar otras entidades", + "find-existing-entity-by-name": "Buscar entidad existente por nombre", + "restore-entities-from-version": "Restaurar entidades desde la versión '{{versionName}}'", + "no-entities-restored": "No se restauraron entidades", + "created": "{{created}} creadas", + "updated": "{{updated}} actualizadas", + "deleted": "{{deleted}} borradas", + "remove-other-entities-confirm-text": "Atención! Esta acción borrará permanentemente todas las entidades actuales
no presentes en la versión a restaurar.

Escribe remove other entities para confirmar.", + "auto-commit-to-branch": "auto-publicar a la rama {{ branch }}", + "default-create-entity-version-name": "{{entityName}} actualización", + "sync-strategy-merge-hint": "Crea o actualiza las entidades seleccionadas en el repositorio. Las demás entidades no serán modificadas.", + "sync-strategy-overwrite-hint": "Crea o actualiza las entidades seleccionadas en el repositorio. Las demás entidades serán borradas.", + "device-credentials-conflict": "Fallo al cargar el dispositivo con ID externo {{entityId}}
debido a que las mismas credenciales están ya presentes en la base de datos para otro dispositivo.
Por favor, considera desactivar el ajuste cargar credenciales en el formulario de restauración.", + "missing-referenced-entity": "Fallo al cargar {{sourceEntityTypeName}} con ID externo {{sourceEntityId}}
porque hace referencia al tipo de entidad {{targetEntityTypeName}} con el ID {{targetEntityId}}." + }, "widget": { "widget-library": "Bibloteca de Widgets", "widget-bundle": "Paquetes de Widgets", @@ -4431,6 +4557,13 @@ "material-icons": "Iconos material-design", "show-all": "Mostrar todos los iconos" }, + "phone-input": { + "phone-input-label": "Número de teléfono", + "phone-input-required": "Número de teléfono requerido", + "phone-input-validation": "El número es inválido o erróneo", + "phone-input-pattern": "Número inválido. Debe cumplir el formato E.164, ej. {{phoneNumber}}", + "phone-input-hint": "Número en el formato E.164, ej. {{phoneNumber}}" + }, "custom": { "widget-action": { "action-cell-button": "Acción botón de celda", From b61307af1c5b7084b016454104cc57455dbe15ca Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 20 Jun 2022 20:55:13 +0300 Subject: [PATCH 34/41] Fixed incorrect pagination of downlink table --- .../home/components/edge/edge-downlink-table-config.ts | 1 + .../components/edge/edge-downlink-table-header.component.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts index 2e3b55f32d..5816f8b968 100644 --- a/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/edge/edge-downlink-table-config.ts @@ -76,6 +76,7 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig Date: Tue, 21 Jun 2022 11:11:32 +0300 Subject: [PATCH 35/41] JS-executor: Added logs compilation time; Cache script map delete min used script --- .../api/jsInvokeMessageProcessor.js | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/msa/js-executor/api/jsInvokeMessageProcessor.js b/msa/js-executor/api/jsInvokeMessageProcessor.js index 8f2ae8db49..f0ed4c274c 100644 --- a/msa/js-executor/api/jsInvokeMessageProcessor.js +++ b/msa/js-executor/api/jsInvokeMessageProcessor.js @@ -32,15 +32,17 @@ const maxActiveScripts = Number(config.get('script.max_active_scripts')); const slowQueryLogMs = Number(config.get('script.slow_query_log_ms')); const slowQueryLogBody = config.get('script.slow_query_log_body') === 'true'; -const {performance} = require('perf_hooks'); +const { performance } = require('node:perf_hooks'); function JsInvokeMessageProcessor(producer) { this.producer = producer; this.executor = new JsExecutor(useSandbox); this.scriptMap = new Map(); this.scriptIds = []; + this.executedScriptIdsCounter = []; this.executedScriptsCounter = 0; this.lastStatTime = performance.now(); + this.compilationTime = 0; } JsInvokeMessageProcessor.prototype.onJsInvokeMessage = function (message) { @@ -125,7 +127,8 @@ JsInvokeMessageProcessor.prototype.processInvokeRequest = function (requestId, r const msSinceLastStat = nowMs - this.lastStatTime; const requestsPerSec = msSinceLastStat == 0 ? statFrequency : statFrequency / msSinceLastStat * 1000; this.lastStatTime = nowMs; - logger.info('STAT[%s]: requests [%s], took [%s]ms, request/s [%s]', this.executedScriptsCounter, statFrequency, msSinceLastStat, requestsPerSec); + logger.info('STAT[%s]: requests [%s], took [%s]ms, request/s [%s], compilation [%s]ms', this.executedScriptsCounter, statFrequency, msSinceLastStat, requestsPerSec, this.compilationTime); + this.compilationTime = 0; } if (this.executedScriptsCounter % scriptBodyTraceFrequency == 0) { @@ -167,6 +170,7 @@ JsInvokeMessageProcessor.prototype.processReleaseRequest = function (requestId, var index = this.scriptIds.indexOf(scriptId); if (index > -1) { this.scriptIds.splice(index, 1); + this.executedScriptIdsCounter.splice(index, 1); } this.scriptMap.delete(scriptId); } @@ -198,14 +202,18 @@ JsInvokeMessageProcessor.prototype.getOrCompileScript = function (scriptId, scri return new Promise(function (resolve, reject) { const script = self.scriptMap.get(scriptId); if (script) { + incrementUseScriptId.call(self, scriptId); resolve(script); } else { + const startTime = performance.now(); self.executor.compileScript(scriptBody).then( (compiledScript) => { + self.compilationTime += (performance.now() - startTime); self.cacheScript(scriptId, compiledScript); resolve(compiledScript); }, (err) => { + self.compilationTime += (performance.now() - startTime); reject(err); } ); @@ -216,11 +224,10 @@ JsInvokeMessageProcessor.prototype.getOrCompileScript = function (scriptId, scri JsInvokeMessageProcessor.prototype.cacheScript = function (scriptId, script) { if (!this.scriptMap.has(scriptId)) { this.scriptIds.push(scriptId); + this.executedScriptIdsCounter.push(0); while (this.scriptIds.length > maxActiveScripts) { logger.info('Active scripts count [%s] exceeds maximum limit [%s]', this.scriptIds.length, maxActiveScripts); - const prevScriptId = this.scriptIds.shift(); - logger.info('Removing active script with id [%s]', prevScriptId); - this.scriptMap.delete(prevScriptId); + deleteMinUsedScript.apply(this); } } this.scriptMap.set(scriptId, script); @@ -291,4 +298,27 @@ function getScriptId(request) { return Utils.toUUIDString(request.scriptIdMSB, request.scriptIdLSB); } +function incrementUseScriptId(scriptId) { + const index = this.scriptIds.indexOf(scriptId); + if (this.executedScriptIdsCounter[index] < Number.MAX_SAFE_INTEGER) { + this.executedScriptIdsCounter[index]++; + } +} + +function deleteMinUsedScript() { + let min = Infinity; + let minIndex = 0; + const scriptIdsLength = this.executedScriptIdsCounter.length - 1; // ignored last added script + for (let i = 0; i < scriptIdsLength; i++) { + if (this.executedScriptIdsCounter[i] < min) { + min = this.executedScriptIdsCounter[i]; + minIndex = i; + } + } + const prevScriptId = this.scriptIds.splice(minIndex, 1)[0]; + this.executedScriptIdsCounter.splice(minIndex, 1) + logger.info('Removing active script with id [%s]', prevScriptId); + this.scriptMap.delete(prevScriptId); +} + module.exports = JsInvokeMessageProcessor; From 0141787d0895543096c93deec60cd5bdecf21db2 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Fri, 17 Jun 2022 19:15:44 +0300 Subject: [PATCH 36/41] RedisTbTransactionalCache - redis cluster watch support by a single key --- .../cache/RedisTbTransactionalCache.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java index ed39bf3716..2cf326905c 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java @@ -21,20 +21,27 @@ import org.springframework.cache.support.NullValue; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStringCommands; +import org.springframework.data.redis.connection.jedis.JedisClusterConnection; +import org.springframework.data.redis.connection.jedis.JedisConnection; import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.util.JedisClusterCRC16; import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; @Slf4j public abstract class RedisTbTransactionalCache implements TbTransactionalCache { private static final byte[] BINARY_NULL_VALUE = RedisSerializer.java().serialize(NullValue.INSTANCE); + static final JedisPool MOCK_POOL = new JedisPool(); //non-null pool required for JedisConnection to trigger closing jedis connection @Getter private final String cacheName; @@ -53,12 +60,12 @@ public abstract class RedisTbTransactionalCache x.get(cacheName)) + .map(CacheSpecs::getTimeToLiveInMinutes) + .map(t -> Expiration.from(t, TimeUnit.MINUTES)) + .orElseGet(Expiration::persistent); } @Override @@ -130,8 +137,24 @@ public abstract class RedisTbTransactionalCache(this, connection); } + RedisConnection getConnection(byte[] rawKey) { + RedisConnection connection = connectionFactory.getClusterConnection(); + if (!(connection instanceof JedisClusterConnection)) { + return connection; + } + + int slotNum = JedisClusterCRC16.getSlot(rawKey); + Jedis jedis = ((JedisClusterConnection) connection).getNativeConnection().getConnectionFromSlot(slotNum); + + JedisConnection jedisConnection = new JedisConnection(jedis, MOCK_POOL, jedis.getDB()); + jedisConnection.setConvertPipelineAndTxResults(connectionFactory.getConvertPipelineAndTxResults()); + + return jedisConnection; + } + private RedisConnection watch(byte[][] rawKeysList) { - var connection = connectionFactory.getConnection(); + //TODO process keys only on suitable slot connection, see getConnection(byte[] rawKey) + RedisConnection connection = getConnection(rawKeysList[0]); try { connection.watch(rawKeysList); connection.multi(); From c40823095eab96f926c088e039294c9570b73533 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 21 Jun 2022 10:32:26 +0200 Subject: [PATCH 37/41] checkRelation improvements --- .../org/thingsboard/server/dao/relation/RelationService.java | 2 +- .../thingsboard/server/dao/relation/BaseRelationService.java | 2 +- .../org/thingsboard/server/dao/relation/RelationDao.java | 2 +- .../thingsboard/server/dao/sql/relation/JpaRelationDao.java | 5 ++--- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java index 8c3eab86d9..e7df5eea93 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java @@ -37,7 +37,7 @@ public interface RelationService { ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); - Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); EntityRelation getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index 9f9615a445..f60920a31d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -97,7 +97,7 @@ public class BaseRelationService implements RelationService { } @Override - public Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + public boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup); validate(from, to, relationType, typeGroup); return relationDao.checkRelation(tenantId, from, to, relationType, typeGroup); diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java index c6459ecf58..a3e81c2652 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java @@ -44,7 +44,7 @@ public interface RelationDao { ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); - Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); + boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); EntityRelation getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 473d2f1021..422e0a8623 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -116,12 +116,11 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple @Override public ListenableFuture checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { - RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup); - return service.submit(() -> relationRepository.existsById(key)); + return service.submit(() -> checkRelation(tenantId, from, to, relationType, typeGroup)); } @Override - public Boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { + public boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) { RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup); return relationRepository.existsById(key); } From eb4745ea56ce12b9c82cf795da9a55913a4f107c Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 21 Jun 2022 13:56:46 +0300 Subject: [PATCH 38/41] UI: Fixed incorrect label in tenant profile --- .../tenant/default-tenant-profile-configuration.component.html | 2 +- ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html index a20f29ac71..3712bcb21d 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html @@ -329,7 +329,7 @@ - tenant-profile.ws-limit-max-sessions-per-public-user + tenant-profile.ws-limit-max-sessions-per-regular-user {{ 'tenant-profile.too-small-value-zero' | translate}} diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 0ab99ccd79..9e0424eb6c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3149,6 +3149,7 @@ "cassandra-tenant-limits-configuration": "Cassandra query rate limit for tenant", "ws-limit-max-sessions-per-tenant": "Maximum number of WS sessions per tenant", "ws-limit-max-sessions-per-customer": "Maximum number of WS sessions per customer", + "ws-limit-max-sessions-per-regular-user": "Maximum number of WS sessions per regular user", "ws-limit-max-sessions-per-public-user": "Maximum number of WS sessions per public user", "ws-limit-queue-per-session": "Maximum size of WS message queue per session", "ws-limit-max-subscriptions-per-tenant": "Maximum number of WS subscriptions per tenant", From a2422dab00595b1beb7dc7d6a7f5fc151ec0b23f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 21 Jun 2022 16:05:10 +0300 Subject: [PATCH 39/41] UI: Fixed permission check in show alarm details --- .../home/components/alarm/alarm-table-config.ts | 11 +++++++++-- .../home/components/alarm/alarm-table.component.ts | 8 ++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts index d35f82daf8..f9b0502d2d 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts @@ -44,9 +44,15 @@ import { AlarmDetailsDialogData } from '@home/components/alarm/alarm-details-dialog.component'; import { DAY, historyInterval } from '@shared/models/time/time.models'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { getCurrentAuthUser } from '@core/auth/auth.selectors'; +import { Authority } from '@shared/models/authority.enum'; export class AlarmTableConfig extends EntityTableConfig { + private authUser = getCurrentAuthUser(this.store); + searchStatus: AlarmSearchStatus; constructor(private alarmService: AlarmService, @@ -55,7 +61,8 @@ export class AlarmTableConfig extends EntityTableConfig private datePipe: DatePipe, private dialog: MatDialog, public entityId: EntityId = null, - private defaultSearchStatus: AlarmSearchStatus = AlarmSearchStatus.ANY) { + private defaultSearchStatus: AlarmSearchStatus = AlarmSearchStatus.ANY, + private store: Store) { super(); this.loadDataOnInit = false; this.tableTitle = ''; @@ -102,7 +109,7 @@ export class AlarmTableConfig extends EntityTableConfig { name: this.translate.instant('alarm.details'), icon: 'more_horiz', - isEnabled: () => true, + isEnabled: (entity) => this.authUser.authority !== Authority.CUSTOMER_USER || entity.customerId.id === this.authUser.customerId, onAction: ($event, entity) => this.showAlarmDetails(entity) } ); diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.ts index cf8c66c93a..d642bcef7a 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-table.component.ts @@ -24,6 +24,8 @@ import { DialogService } from '@core/services/dialog.service'; import { AlarmTableConfig } from './alarm-table-config'; import { AlarmSearchStatus } from '@shared/models/alarm.models'; import { AlarmService } from '@app/core/http/alarm.service'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; @Component({ selector: 'tb-alarm-table', @@ -68,7 +70,8 @@ export class AlarmTableComponent implements OnInit { private dialogService: DialogService, private translate: TranslateService, private datePipe: DatePipe, - private dialog: MatDialog) { + private dialog: MatDialog, + private store: Store) { } ngOnInit() { @@ -80,7 +83,8 @@ export class AlarmTableComponent implements OnInit { this.datePipe, this.dialog, this.entityIdValue, - AlarmSearchStatus.ANY + AlarmSearchStatus.ANY, + this.store ); } From ebbf5833923a21895f0907e13851ee915716d2a4 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 21 Jun 2022 16:11:39 +0300 Subject: [PATCH 40/41] Fix multi-key cache transaction for attributes service --- .../server/cache/RedisTbTransactionalCache.java | 14 +++++++------- .../server/cache/TbTransactionalCache.java | 6 ++++++ .../server/dao/attributes/AttributeCacheKey.java | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java index 2cf326905c..4f22dff046 100644 --- a/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/RedisTbTransactionalCache.java @@ -23,6 +23,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.jedis.JedisClusterConnection; import org.springframework.data.redis.connection.jedis.JedisConnection; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @@ -45,7 +46,7 @@ public abstract class RedisTbTransactionalCache keySerializer = new StringRedisSerializer(); private final RedisSerializer valueSerializer; private final Expiration evictExpiration; @@ -57,7 +58,7 @@ public abstract class RedisTbTransactionalCache valueSerializer) { this.cacheName = cacheName; - this.connectionFactory = connectionFactory; + this.connectionFactory = (JedisConnectionFactory) connectionFactory; this.valueSerializer = valueSerializer; this.evictExpiration = Expiration.from(configuration.getEvictTtlInMs(), TimeUnit.MILLISECONDS); this.cacheTtl = Optional.ofNullable(cacheSpecsMap) @@ -137,11 +138,11 @@ public abstract class RedisTbTransactionalCache(this, connection); } - RedisConnection getConnection(byte[] rawKey) { - RedisConnection connection = connectionFactory.getClusterConnection(); - if (!(connection instanceof JedisClusterConnection)) { - return connection; + private RedisConnection getConnection(byte[] rawKey) { + if (!connectionFactory.isRedisClusterAware()) { + return connectionFactory.getConnection(); } + RedisConnection connection = connectionFactory.getClusterConnection(); int slotNum = JedisClusterCRC16.getSlot(rawKey); Jedis jedis = ((JedisClusterConnection) connection).getNativeConnection().getConnectionFromSlot(slotNum); @@ -153,7 +154,6 @@ public abstract class RedisTbTransactionalCache newTransactionForKey(K key); + /** + * Note that all keys should be in the same cache slot for redis. You may control the cache slot using '{}' bracers. + * See CLUSTER KEYSLOT command for more details. + * @param keys - list of keys to use + * @return transaction object + */ TbCacheTransaction newTransactionForKeys(List keys); default V getAndPutInTransaction(K key, Supplier dbCall, boolean cacheNullValue) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java index 3dc3f1e232..68a2a11c4a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/AttributeCacheKey.java @@ -34,6 +34,6 @@ public class AttributeCacheKey implements Serializable { @Override public String toString() { - return entityId + "_" + scope + "_" + key; + return "{" + entityId + "}" + scope + "_" + key; } } From d05712d3e2973cadd0faed6c5004674af5bbb128 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 21 Jun 2022 17:14:03 +0300 Subject: [PATCH 41/41] UI: Improvement alarm details dialog --- .../alarm/alarm-details-dialog.component.ts | 37 ++++++++++++++----- .../components/alarm/alarm-table-config.ts | 8 ++-- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts index dc88580177..be3aff8c50 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-details-dialog.component.ts @@ -35,7 +35,8 @@ import { DatePipe } from '@angular/common'; import { TranslateService } from '@ngx-translate/core'; export interface AlarmDetailsDialogData { - alarmId: string; + alarmId?: string; + alarm?: AlarmInfo; allowAcknowledgment: boolean; allowClear: boolean; displayDetails: boolean; @@ -48,6 +49,7 @@ export interface AlarmDetailsDialogData { }) export class AlarmDetailsDialogComponent extends DialogComponent implements OnInit { + alarmId: string; alarmFormGroup: FormGroup; allowAcknowledgment: boolean; @@ -93,12 +95,17 @@ export class AlarmDetailsDialogComponent extends DialogComponent this.loadAlarmSubject.next(alarm) ); } @@ -140,15 +147,25 @@ export class AlarmDetailsDialogComponent extends DialogComponent { this.alarmUpdated = true; this.loadAlarm(); } - ); + if (this.alarmId) { + this.alarmService.ackAlarm(this.alarmId).subscribe( + () => { + this.alarmUpdated = true; + this.loadAlarm(); + } + ); + } } clear(): void { - this.alarmService.clearAlarm(this.data.alarmId).subscribe( - () => { this.alarmUpdated = true; this.loadAlarm(); } - ); + if (this.alarmId) { + this.alarmService.clearAlarm(this.alarmId).subscribe( + () => { + this.alarmUpdated = true; + this.loadAlarm(); + } + ); + } } } diff --git a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts index f9b0502d2d..6cc51857e7 100644 --- a/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/alarm/alarm-table-config.ts @@ -109,7 +109,7 @@ export class AlarmTableConfig extends EntityTableConfig { name: this.translate.instant('alarm.details'), icon: 'more_horiz', - isEnabled: (entity) => this.authUser.authority !== Authority.CUSTOMER_USER || entity.customerId.id === this.authUser.customerId, + isEnabled: () => true, onAction: ($event, entity) => this.showAlarmDetails(entity) } ); @@ -121,6 +121,7 @@ export class AlarmTableConfig extends EntityTableConfig } showAlarmDetails(entity: AlarmInfo) { + const isPermissionWrite = this.authUser.authority !== Authority.CUSTOMER_USER || entity.customerId.id === this.authUser.customerId; this.dialog.open (AlarmDetailsDialogComponent, { @@ -128,8 +129,9 @@ export class AlarmTableConfig extends EntityTableConfig panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { alarmId: entity.id.id, - allowAcknowledgment: true, - allowClear: true, + alarm: entity, + allowAcknowledgment: isPermissionWrite, + allowClear: isPermissionWrite, displayDetails: true } }).afterClosed().subscribe(