Browse Source

Merge remote-tracking branch 'upstream/develop/3.4' into feature/edge-converters-integration

pull/6600/head
Volodymyr Babak 4 years ago
parent
commit
68e35bbb40
  1. 12
      application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
  2. 6
      application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java
  3. 6
      application/src/main/java/org/thingsboard/server/service/ttl/rpc/RpcCleanUpService.java
  4. 3
      application/src/main/resources/thingsboard.yml
  5. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
  6. 4
      common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java
  7. 4
      common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java
  8. 1
      common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java
  9. 14
      dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
  10. 4
      dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
  11. 20
      dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java
  12. 6
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java
  13. 23
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
  14. 2
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
  15. 22
      dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java
  16. 28
      dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java
  17. 8
      dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java
  18. 11
      dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java
  19. 4
      dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java
  20. 4
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  21. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmDataValidator.java
  22. 14
      dao/src/main/java/org/thingsboard/server/dao/service/validator/ApiUsageDataValidator.java
  23. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/AssetDataValidator.java
  24. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/BaseOtaPackageDataValidator.java
  25. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/CustomerDataValidator.java
  26. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/DashboardDataValidator.java
  27. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceDataValidator.java
  28. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java
  29. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/EdgeDataValidator.java
  30. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/EntityViewDataValidator.java
  31. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java
  32. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/RuleChainDataValidator.java
  33. 13
      dao/src/main/java/org/thingsboard/server/dao/service/validator/UserDataValidator.java
  34. 6
      dao/src/main/java/org/thingsboard/server/dao/service/validator/WidgetTypeDataValidator.java
  35. 8
      dao/src/main/java/org/thingsboard/server/dao/service/validator/WidgetsBundleDataValidator.java
  36. 9
      dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java
  37. 45
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java
  38. 33
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java
  39. 26
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java
  40. 33
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java
  41. 35
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java
  42. 35
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java
  43. 71
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java
  44. 10
      dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java
  45. 16
      dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java
  46. 4
      dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java
  47. 36
      dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java
  48. 16
      dao/src/test/java/org/thingsboard/server/dao/service/BaseRelationServiceTest.java
  49. 434
      dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java
  50. 3
      dao/src/test/resources/application-test.properties
  51. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java
  52. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java
  53. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java
  54. 6
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbCreateRelationNodeTest.java

12
application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java

@ -378,7 +378,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
}
List<ListenableFuture<Void>> futures = new ArrayList<>();
for (EntityView entityView : entityViews) {
ListenableFuture<Boolean> future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(),
ListenableFuture<Boolean> future = relationService.checkRelationAsync(tenantId, edge.getId(), entityView.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
futures.add(Futures.transformAsync(future, result -> {
if (Boolean.TRUE.equals(result)) {
@ -413,11 +413,11 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
}
private ListenableFuture<Void> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType type,
EdgeEventActionType action,
EntityId entityId,
JsonNode body) {
EdgeId edgeId,
EdgeEventType type,
EdgeEventActionType action,
EntityId entityId,
JsonNode body) {
log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);

6
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<TenantId> 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;

6
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<TenantId> 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;

3
application/src/main/resources/thingsboard.yml

@ -394,6 +394,9 @@ cache:
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}"

2
common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java

@ -72,6 +72,8 @@ public interface EntityViewService {
ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId);
List<EntityView> findEntityViewsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId);
void deleteEntityView(TenantId tenantId, EntityViewId entityViewId);
void deleteEntityViewsByTenantId(TenantId tenantId);

4
common/dao-api/src/main/java/org/thingsboard/server/dao/relation/RelationService.java

@ -35,7 +35,9 @@ import java.util.List;
*/
public interface RelationService {
ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<Boolean> 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);

4
common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java

@ -35,6 +35,8 @@ public interface TenantService {
Tenant saveTenant(Tenant tenant);
boolean tenantExists(TenantId tenantId);
void deleteTenant(TenantId tenantId);
PageData<Tenant> findTenants(PageLink pageLink);
@ -44,4 +46,6 @@ public interface TenantService {
List<TenantId> findTenantIdsByTenantProfileId(TenantProfileId tenantProfileId);
void deleteTenants();
PageData<TenantId> findTenantsIds(PageLink pageLink);
}

1
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";

14
dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java

@ -23,8 +23,6 @@ import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
@ -53,7 +51,6 @@ import java.util.ArrayList;
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.dao.DaoUtil.toUUIDs;
@ -160,14 +157,9 @@ public class BaseAssetService extends AbstractCachedEntityService<AssetCacheKey,
deleteEntityRelations(tenantId, assetId);
Asset asset = assetDao.findById(tenantId, assetId.getId());
try {
List<EntityView> 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<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityId(asset.getTenantId(), assetId);
if (entityViews != null && !entityViews.isEmpty()) {
throw new DataValidationException("Can't delete asset that has entity views!");
}
publishEvictEvent(new AssetCacheEvictEvent(asset.getTenantId(), asset.getName(), null));

4
dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java

@ -31,7 +31,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.IncorrectParameterException;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@ -64,9 +63,6 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
@Autowired
private DeviceService deviceService;
@Autowired
private EntityViewService entityViewService;
@Autowired
private DashboardService dashboardService;

20
dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java

@ -58,7 +58,7 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
@Autowired
private CustomerDao customerDao;
@Autowired
private EdgeDao edgeDao;
@ -289,16 +289,16 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb
private PaginatedRemover<TenantId, DashboardInfo> tenantDashboardsRemover =
new PaginatedRemover<TenantId, DashboardInfo>() {
@Override
protected PageData<DashboardInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return dashboardInfoDao.findDashboardsByTenantId(id.getId(), pageLink);
}
@Override
protected PageData<DashboardInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return dashboardInfoDao.findDashboardsByTenantId(id.getId(), pageLink);
}
@Override
protected void removeEntity(TenantId tenantId, DashboardInfo entity) {
deleteDashboard(tenantId, new DashboardId(entity.getUuidId()));
}
};
@Override
protected void removeEntity(TenantId tenantId, DashboardInfo entity) {
deleteDashboard(tenantId, new DashboardId(entity.getUuidId()));
}
};
private class CustomerDashboardsUnassigner extends PaginatedRemover<Customer, DashboardInfo> {

6
dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

@ -19,8 +19,6 @@ import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
@ -47,8 +45,6 @@ import org.thingsboard.server.dao.service.Validator;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.thingsboard.server.dao.service.Validator.validateId;
@ -76,8 +72,6 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService<Device
@Autowired
private QueueService queueService;
private final Lock findOrCreateLock = new ReentrantLock();
@TransactionalEventListener(classes = DeviceProfileEvictEvent.class)
@Override
public void handleEvictEvent(DeviceProfileEvictEvent event) {

23
dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java

@ -78,7 +78,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
@ -313,14 +312,9 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
Device device = deviceDao.findById(tenantId, deviceId.getId());
DeviceCacheEvictEvent deviceCacheEvictEvent = new DeviceCacheEvictEvent(device.getTenantId(), device.getId(), device.getName(), null);
try {
List<EntityView> 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<EntityView> 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);
@ -523,14 +517,9 @@ public class DeviceServiceImpl extends AbstractCachedEntityService<DeviceCacheKe
@Override
public Device assignDeviceToTenant(TenantId tenantId, Device device) {
log.trace("Executing assignDeviceToTenant [{}][{}]", tenantId, device);
try {
List<EntityView> 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<EntityView> 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());

2
dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java

@ -26,8 +26,6 @@ import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;

22
dao/src/main/java/org/thingsboard/server/dao/entity/AbstractEntityService.java

@ -84,20 +84,16 @@ public abstract class AbstractEntityService {
}
protected void checkAssignedEntityViewsToEdge(TenantId tenantId, EntityId entityId, EdgeId edgeId) {
try {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId).get();
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<EntityView> 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);
}
}

28
dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java

@ -22,8 +22,6 @@ import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
@ -53,7 +51,6 @@ import java.util.ArrayList;
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.dao.service.Validator.validateId;
@ -68,7 +65,6 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityViewCacheKey, EntityViewCacheValue, EntityViewEvictEvent> implements EntityViewService {
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
public static final String INCORRECT_PAGE_LINK = "Incorrect page link ";
public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
public static final String INCORRECT_ENTITY_VIEW_ID = "Incorrect entityViewId ";
public static final String INCORRECT_EDGE_ID = "Incorrect edgeId ";
@ -280,6 +276,17 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
EntityViewCacheValue::getEntityViews, v -> new EntityViewCacheValue(null, v), true));
}
@Override
public List<EntityView> 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);
return cache.getAndPutInTransaction(EntityViewCacheKey.byEntityId(tenantId, entityId),
() -> entityViewDao.findEntityViewsByTenantIdAndEntityId(tenantId.getId(), entityId.getId()),
EntityViewCacheValue::getEntityViews, v -> new EntityViewCacheValue(null, v), true);
}
@Override
public void deleteEntityView(TenantId tenantId, EntityViewId entityViewId) {
log.trace("Executing deleteEntityView [{}]", entityViewId);
@ -320,15 +327,10 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService<EntityVie
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 {

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

@ -22,8 +22,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.OtaPackage;
@ -42,8 +40,6 @@ import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.thingsboard.server.dao.service.Validator.validateId;
@ -248,8 +244,4 @@ public class BaseOtaPackageService extends AbstractCachedEntityService<OtaPackag
}
}
private static List<OtaPackageId> toOtaPackageInfoKey(OtaPackageId otaPackageId) {
return Collections.singletonList(otaPackageId);
}
}

11
dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java

@ -28,8 +28,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;
import org.thingsboard.server.cache.TbTransactionalCache;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation;
@ -90,7 +90,14 @@ public class BaseRelationService implements RelationService {
}
@Override
public ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<Boolean> checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup 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) {
log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
validate(from, to, relationType, typeGroup);
return relationDao.checkRelation(tenantId, from, to, relationType, typeGroup);

4
dao/src/main/java/org/thingsboard/server/dao/relation/RelationDao.java

@ -42,7 +42,9 @@ public interface RelationDao {
List<EntityRelation> findAllByToAndType(TenantId tenantId, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup);
ListenableFuture<Boolean> 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);

4
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -70,7 +70,9 @@ import java.util.Set;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.DataConstants.TENANT;
import static org.thingsboard.server.dao.service.Validator.*;
import static org.thingsboard.server.dao.service.Validator.validateId;
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
import static org.thingsboard.server.dao.service.Validator.validateString;
/**
* Created by igor on 3/12/18.

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/AlarmDataValidator.java

@ -18,18 +18,17 @@ package org.thingsboard.server.dao.service.validator;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.id.TenantId;
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;
@Component
@AllArgsConstructor
public class AlarmDataValidator extends DataValidator<Alarm> {
private final TenantDao tenantDao;
private final TenantService tenantService;
@Override
protected void validateDataImpl(TenantId tenantId, Alarm alarm) {
@ -48,8 +47,7 @@ public class AlarmDataValidator extends DataValidator<Alarm> {
if (alarm.getTenantId() == null) {
throw new DataValidationException("Alarm should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(alarm.getTenantId(), alarm.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(alarm.getTenantId())) {
throw new DataValidationException("Alarm is referencing to non-existent tenant!");
}
}

14
dao/src/main/java/org/thingsboard/server/dao/service/validator/ApiUsageDataValidator.java

@ -15,29 +15,29 @@
*/
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;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.TenantId;
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;
@Component
@AllArgsConstructor
public class ApiUsageDataValidator extends DataValidator<ApiUsageState> {
private final TenantDao tenantDao;
@Lazy
@Autowired
private TenantService tenantService;
@Override
protected void validateDataImpl(TenantId requestTenantId, ApiUsageState apiUsageState) {
if (apiUsageState.getTenantId() == null) {
throw new DataValidationException("ApiUsageState should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(requestTenantId, apiUsageState.getTenantId().getId());
if (tenant == null && !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!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/AssetDataValidator.java

@ -21,7 +21,6 @@ import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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.asset.Asset;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@ -32,7 +31,7 @@ import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.exception.DataValidationException;
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 static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@ -43,7 +42,7 @@ public class AssetDataValidator extends DataValidator<Asset> {
private AssetDao assetDao;
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
private CustomerDao customerDao;
@ -82,8 +81,7 @@ public class AssetDataValidator extends DataValidator<Asset> {
if (asset.getTenantId() == null) {
throw new DataValidationException("Asset should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(tenantId, asset.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(asset.getTenantId())) {
throw new DataValidationException("Asset is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/BaseOtaPackageDataValidator.java

@ -20,18 +20,17 @@ import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.DeviceProfile;
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.dao.device.DeviceProfileDao;
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 java.util.Objects;
public abstract class BaseOtaPackageDataValidator<D extends BaseData<?>> extends DataValidator<D> {
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
private DeviceProfileDao deviceProfileDao;
@ -40,8 +39,7 @@ public abstract class BaseOtaPackageDataValidator<D extends BaseData<?>> extends
if (otaPackageInfo.getTenantId() == null) {
throw new DataValidationException("OtaPackage should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(otaPackageInfo.getTenantId(), otaPackageInfo.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(otaPackageInfo.getTenantId())) {
throw new DataValidationException("OtaPackage is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/CustomerDataValidator.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.id.TenantId;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.customer.CustomerDao;
@ -29,7 +28,7 @@ import org.thingsboard.server.dao.customer.CustomerServiceImpl;
import org.thingsboard.server.dao.exception.DataValidationException;
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 java.util.Optional;
@ -40,7 +39,7 @@ public class CustomerDataValidator extends DataValidator<Customer> {
private CustomerDao customerDao;
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
@Lazy
@ -87,8 +86,7 @@ public class CustomerDataValidator extends DataValidator<Customer> {
if (customer.getTenantId() == null) {
throw new DataValidationException("Customer should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(tenantId, customer.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(customer.getTenantId())) {
throw new DataValidationException("Customer is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/DashboardDataValidator.java

@ -21,14 +21,13 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.dashboard.DashboardDao;
import org.thingsboard.server.dao.exception.DataValidationException;
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;
@Component
public class DashboardDataValidator extends DataValidator<Dashboard> {
@ -37,7 +36,7 @@ public class DashboardDataValidator extends DataValidator<Dashboard> {
private DashboardDao dashboardDao;
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
@Lazy
@ -59,8 +58,7 @@ public class DashboardDataValidator extends DataValidator<Dashboard> {
if (dashboard.getTenantId() == null) {
throw new DataValidationException("Dashboard should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(tenantId, dashboard.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(dashboard.getTenantId())) {
throw new DataValidationException("Dashboard is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceDataValidator.java

@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@ -35,7 +34,7 @@ import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.ota.OtaPackageService;
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 java.util.Optional;
@ -48,7 +47,7 @@ public class DeviceDataValidator extends DataValidator<Device> {
private DeviceDao deviceDao;
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
private CustomerDao customerDao;
@ -85,8 +84,7 @@ public class DeviceDataValidator extends DataValidator<Device> {
if (device.getTenantId() == null) {
throw new DataValidationException("Device should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(device.getTenantId(), device.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(device.getTenantId())) {
throw new DataValidationException("Device is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java

@ -37,7 +37,6 @@ import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.OtaPackage;
import org.thingsboard.server.common.data.StringUtils;
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;
@ -67,7 +66,7 @@ import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.server.dao.tenant.TenantService;
import java.util.HashSet;
import java.util.List;
@ -90,7 +89,7 @@ public class DeviceProfileDataValidator extends DataValidator<DeviceProfile> {
@Autowired
private DeviceDao deviceDao;
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
@Lazy
private QueueService queueService;
@ -119,8 +118,7 @@ public class DeviceProfileDataValidator extends DataValidator<DeviceProfile> {
if (deviceProfile.getTenantId() == null) {
throw new DataValidationException("Device profile should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(deviceProfile.getTenantId(), deviceProfile.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(deviceProfile.getTenantId())) {
throw new DataValidationException("Device profile is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/EdgeDataValidator.java

@ -19,7 +19,6 @@ import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Customer;
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.TenantId;
@ -27,7 +26,7 @@ import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.edge.EdgeDao;
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 static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@ -36,7 +35,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
public class EdgeDataValidator extends DataValidator<Edge> {
private final EdgeDao edgeDao;
private final TenantDao tenantDao;
private final TenantService tenantService;
private final CustomerDao customerDao;
@Override
@ -65,8 +64,7 @@ public class EdgeDataValidator extends DataValidator<Edge> {
if (edge.getTenantId() == null) {
throw new DataValidationException("Edge should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(edge.getTenantId(), edge.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(edge.getTenantId())) {
throw new DataValidationException("Edge is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/EntityViewDataValidator.java

@ -20,14 +20,13 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntityView;
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.dao.customer.CustomerDao;
import org.thingsboard.server.dao.entityview.EntityViewDao;
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 static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@ -36,7 +35,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
public class EntityViewDataValidator extends DataValidator<EntityView> {
private final EntityViewDao entityViewDao;
private final TenantDao tenantDao;
private final TenantService tenantService;
private final CustomerDao customerDao;
@Override
@ -69,8 +68,7 @@ public class EntityViewDataValidator extends DataValidator<EntityView> {
if (entityView.getTenantId() == null) {
throw new DataValidationException("Entity view should be assigned to tenant!");
} else {
Tenant tenant = tenantDao.findById(tenantId, entityView.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(entityView.getTenantId())) {
throw new DataValidationException("Entity view is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/ResourceDataValidator.java

@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.exception.DataValidationException;
@ -28,7 +27,7 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.resource.TbResourceDao;
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 static org.thingsboard.server.common.data.EntityType.TB_RESOURCE;
@ -39,7 +38,7 @@ public class ResourceDataValidator extends DataValidator<TbResource> {
private TbResourceDao resourceDao;
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
@Lazy
@ -73,8 +72,7 @@ public class ResourceDataValidator extends DataValidator<TbResource> {
resource.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID));
}
if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
Tenant tenant = tenantDao.findById(tenantId, resource.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(resource.getTenantId())) {
throw new DataValidationException("Resource is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/RuleChainDataValidator.java

@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainType;
@ -30,7 +29,7 @@ import org.thingsboard.server.dao.rule.RuleChainDao;
import org.thingsboard.server.dao.rule.RuleChainService;
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;
@Component
public class RuleChainDataValidator extends DataValidator<RuleChain> {
@ -43,7 +42,7 @@ public class RuleChainDataValidator extends DataValidator<RuleChain> {
private RuleChainService ruleChainService;
@Autowired
private TenantDao tenantDao;
private TenantService tenantService;
@Autowired
@Lazy
@ -68,8 +67,7 @@ public class RuleChainDataValidator extends DataValidator<RuleChain> {
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());
if (tenant == null) {
if (!tenantService.tenantExists(ruleChain.getTenantId())) {
throw new DataValidationException("Rule chain is referencing to non-existent tenant!");
}
if (ruleChain.isRoot() && RuleChainType.CORE.equals(ruleChain.getType())) {

13
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,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.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;
@ -46,9 +45,6 @@ public class UserDataValidator extends DataValidator<User> {
@Lazy
private UserService userService;
@Autowired
private TenantDao tenantDao;
@Autowired
private CustomerDao customerDao;
@ -56,6 +52,10 @@ public class UserDataValidator extends DataValidator<User> {
@Lazy
private TbTenantProfileCache tenantProfileCache;
@Autowired
@Lazy
private TenantService tenantService;
@Override
protected void validateCreate(TenantId tenantId, User user) {
if (!user.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
@ -119,8 +119,7 @@ public class UserDataValidator extends DataValidator<User> {
+ " already present in database!");
}
if (!tenantId.getId().equals(ModelConstants.NULL_UUID)) {
Tenant tenant = tenantDao.findById(tenantId, user.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(user.getTenantId())) {
throw new DataValidationException("User is referencing to non-existent tenant!");
}
}

6
dao/src/main/java/org/thingsboard/server/dao/service/validator/WidgetTypeDataValidator.java

@ -27,6 +27,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.tenant.TenantDao;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.widget.WidgetTypeDao;
import org.thingsboard.server.dao.widget.WidgetsBundleDao;
@ -35,8 +36,8 @@ import org.thingsboard.server.dao.widget.WidgetsBundleDao;
public class WidgetTypeDataValidator extends DataValidator<WidgetTypeDetails> {
private final WidgetTypeDao widgetTypeDao;
private final TenantDao tenantDao;
private final WidgetsBundleDao widgetsBundleDao;
private final TenantService tenantService;
@Override
protected void validateDataImpl(TenantId tenantId, WidgetTypeDetails widgetTypeDetails) {
@ -53,8 +54,7 @@ public class WidgetTypeDataValidator extends DataValidator<WidgetTypeDetails> {
widgetTypeDetails.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID));
}
if (!widgetTypeDetails.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
Tenant tenant = tenantDao.findById(tenantId, widgetTypeDetails.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(widgetTypeDetails.getTenantId())) {
throw new DataValidationException("Widget type is referencing to non-existent tenant!");
}
}

8
dao/src/main/java/org/thingsboard/server/dao/service/validator/WidgetsBundleDataValidator.java

@ -18,13 +18,12 @@ package org.thingsboard.server.dao.service.validator;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
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.TenantDao;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.widget.WidgetsBundleDao;
@Component
@ -32,7 +31,7 @@ import org.thingsboard.server.dao.widget.WidgetsBundleDao;
public class WidgetsBundleDataValidator extends DataValidator<WidgetsBundle> {
private final WidgetsBundleDao widgetsBundleDao;
private final TenantDao tenantDao;
private final TenantService tenantService;
@Override
protected void validateDataImpl(TenantId tenantId, WidgetsBundle widgetsBundle) {
@ -43,8 +42,7 @@ public class WidgetsBundleDataValidator extends DataValidator<WidgetsBundle> {
widgetsBundle.setTenantId(TenantId.fromUUID(ModelConstants.NULL_UUID));
}
if (!widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
Tenant tenant = tenantDao.findById(tenantId, widgetsBundle.getTenantId().getId());
if (tenant == null) {
if (!tenantService.tenantExists(widgetsBundle.getTenantId())) {
throw new DataValidationException("Widgets bundle is referencing to non-existent tenant!");
}
}

9
dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java

@ -115,9 +115,14 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
}
@Override
public ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
public ListenableFuture<Boolean> checkRelationAsync(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
return service.submit(() -> checkRelation(tenantId, from, to, relationType, typeGroup));
}
@Override
public boolean checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup);
return service.submit(() -> relationRepository.existsById(key));
return relationRepository.existsById(key);
}
@Override

45
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
}
}

33
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<TenantCacheKey, Tenant> {
public TenantCaffeineCache(CacheManager cacheManager) {
super(cacheManager, CacheConstants.TENANTS_CACHE);
}
}

26
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;
}

33
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<TenantCacheKey, Boolean> {
public TenantExistsCaffeineCache(CacheManager cacheManager) {
super(cacheManager, CacheConstants.TENANTS_CACHE);
}
}

35
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<TenantCacheKey, Boolean> {
public TenantExistsRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
super(CacheConstants.TENANTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>());
}
}

35
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<TenantCacheKey, Tenant> {
public TenantRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
super(CacheConstants.TENANTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>());
}
}

71
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

@ -18,7 +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.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;
@ -31,8 +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.entityview.EntityViewService;
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;
@ -52,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
@Service
@Slf4j
public class TenantServiceImpl extends AbstractEntityService implements TenantService {
public class TenantServiceImpl extends AbstractCachedEntityService<TenantCacheKey, Tenant, TenantEvictEvent> implements TenantService {
private static final String DEFAULT_TENANT_REGION = "Global";
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
@ -64,6 +67,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
private TenantProfileService tenantProfileService;
@Autowired
@Lazy
private UserService userService;
@Autowired
@ -78,12 +82,10 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
@Autowired
private DeviceProfileService deviceProfileService;
@Lazy
@Autowired
private ApiUsageStateService apiUsageStateService;
@Autowired
private EntityViewService entityViewService;
@Autowired
private WidgetsBundleService widgetsBundleService;
@ -111,11 +113,26 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
@Autowired
private AdminSettingsService adminSettingsService;
@Autowired
protected TbTransactionalCache<TenantCacheKey, Boolean> 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
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
@ -127,12 +144,13 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
@Override
public ListenableFuture<Tenant> 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());
}
@Override
@Transactional
public Tenant saveTenant(Tenant tenant) {
log.trace("Executing saveTenant [{}]", tenant);
tenant.setRegion(DEFAULT_TENANT_REGION);
@ -142,6 +160,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);
@ -150,6 +169,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
}
@Override
@Transactional(timeout = 60 * 60)
public void deleteTenant(TenantId tenantId) {
log.trace("Executing deleteTenant [{}]", tenantId);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
@ -170,6 +190,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
queueService.deleteQueuesByTenantId(tenantId);
adminSettingsService.deleteAdminSettingsByTenantId(tenantId);
tenantDao.removeById(tenantId, tenantId.getId());
publishEvictEvent(new TenantEvictEvent(tenantId, true));
deleteEntityRelations(tenantId, tenantId);
}
@ -199,17 +220,29 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
tenantsRemover.removeEntities(TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID);
}
private PaginatedRemover<TenantId, Tenant> tenantsRemover =
new PaginatedRemover<>() {
@Override
public PageData<TenantId> findTenantsIds(PageLink pageLink) {
log.trace("Executing findTenantsIds");
Validator.validatePageLink(pageLink);
return tenantDao.findTenantsIds(pageLink);
}
@Override
protected PageData<Tenant> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return tenantDao.findTenants(tenantId, pageLink);
}
@Override
public boolean tenantExists(TenantId tenantId) {
return existsTenantCache.getAndPutInTransaction(TenantCacheKey.fromIdExists(tenantId),
() -> tenantDao.existsById(tenantId, tenantId.getId()), false);
}
@Override
protected void removeEntity(TenantId tenantId, Tenant entity) {
deleteTenant(TenantId.fromUUID(entity.getUuidId()));
}
};
private PaginatedRemover<TenantId, Tenant> tenantsRemover = new PaginatedRemover<>() {
@Override
protected PageData<Tenant> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return tenantDao.findTenants(tenantId, pageLink);
}
@Override
protected void removeEntity(TenantId tenantId, Tenant entity) {
deleteTenant(TenantId.fromUUID(entity.getUuidId()));
}
};
}

10
dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java

@ -35,8 +35,8 @@ import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.tenant.TenantDao;
import org.thingsboard.server.dao.tenant.TenantProfileDao;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import java.util.ArrayList;
@ -52,16 +52,16 @@ 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;
private final DataValidator<ApiUsageState> apiUsageStateValidator;
public ApiUsageStateServiceImpl(ApiUsageStateDao apiUsageStateDao, TenantProfileDao tenantProfileDao,
TenantDao tenantDao, @Lazy TimeseriesService tsService,
TenantService tenantService, @Lazy TimeseriesService tsService,
DataValidator<ApiUsageState> apiUsageStateValidator) {
this.apiUsageStateDao = apiUsageStateDao;
this.tenantProfileDao = tenantProfileDao;
this.tenantDao = tenantDao;
this.tenantService = tenantService;
this.tsService = tsService;
this.apiUsageStateValidator = apiUsageStateValidator;
}
@ -118,7 +118,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();

16
dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java

@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Value;
@ -50,6 +51,7 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends AbstractEntityService implements UserService {
public static final String USER_PASSWORD_HISTORY = "userPasswordHistory";
@ -73,20 +75,6 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic
private final DataValidator<UserCredentials> userCredentialsValidator;
private final ApplicationEventPublisher eventPublisher;
public UserServiceImpl(UserDao userDao,
UserCredentialsDao userCredentialsDao,
UserAuthSettingsDao userAuthSettingsDao,
DataValidator<User> userValidator,
DataValidator<UserCredentials> userCredentialsValidator,
ApplicationEventPublisher eventPublisher) {
this.userDao = userDao;
this.userCredentialsDao = userCredentialsDao;
this.userAuthSettingsDao = userAuthSettingsDao;
this.userValidator = userValidator;
this.userCredentialsValidator = userCredentialsValidator;
this.eventPublisher = eventPublisher;
}
@Override
public User findUserByEmail(TenantId tenantId, String email) {
log.trace("Executing findUserByEmail [{}]", email);

4
dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java

@ -65,6 +65,7 @@ import org.thingsboard.server.dao.ota.OtaPackageService;
import org.thingsboard.server.dao.queue.QueueService;
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;
@ -170,6 +171,9 @@ public abstract class AbstractServiceTest {
@Autowired
protected OtaPackageService otaPackageService;
@Autowired
protected RpcService rpcService;
@Autowired
protected QueueService queueService;

36
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<OtaPackage> 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);
@ -493,7 +493,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);
@ -519,7 +519,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);
@ -532,7 +532,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
public void testFindTenantFirmwaresByTenantId() {
List<OtaPackageInfo> 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);
}
@ -579,7 +579,7 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
public void testFindTenantFirmwaresByTenantIdAndHasData() {
List<OtaPackageInfo> 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();
@ -695,7 +695,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);
@ -708,6 +716,6 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM);
firmware.setData(DATA);
firmware.setDataSize(DATA_SIZE);
return otaPackageService.saveOtaPackage(firmware);
return firmware;
}
}

16
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 {
relationService.deleteEntityRelations(SYSTEM_TENANT_ID, childId);
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

434
dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java

@ -17,26 +17,77 @@ 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;
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;
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.TenantId;
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.TenantCacheKey;
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 java.util.Set;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.assertj.core.api.Assertions.assertThat;
public abstract class BaseTenantServiceTest extends AbstractServiceTest {
private IdComparator<Tenant> idComparator = new IdComparator<>();
@SpyBean
protected TenantDao tenantDao;
@Autowired
protected TbTransactionalCache<TenantCacheKey, Tenant> cache;
@Autowired
protected TbTransactionalCache<TenantCacheKey, Boolean> existsTenantCache;
@Test
public void testSaveTenant() {
Tenant tenant = new Tenant();
@ -103,7 +154,6 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest {
@Test
public void testFindTenants() {
List<Tenant> tenants = new ArrayList<>();
PageLink pageLink = new PageLink(17);
PageData<Tenant> pageData = tenantService.findTenants(pageLink);
@ -275,4 +325,382 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest {
tenant.setTenantProfileId(isolatedTenantProfile.getId());
tenantService.saveTenant(tenant);
}
@Test
public void testGettingTenantAddingItToCache() {
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
Tenant savedTenant = tenantService.saveTenant(tenant);
Mockito.reset(tenantDao);
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()));
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());
}
verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId()));
tenantService.deleteTenant(savedTenant.getId());
}
@Test
public void testExistsTenantAddingResultToCache() {
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
Tenant savedTenant = tenantService.saveTenant(tenant);
Mockito.reset(tenantDao);
//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()));
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());
}
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();
tenant.setTitle("My tenant");
Tenant savedTenant = tenantService.saveTenant(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 = 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());
tenantService.findTenantById(savedTenant.getId());
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);
tenantService.findTenantById(savedTenant.getId());
tenantService.tenantExists(savedTenant.getId());
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 =
cache.get(TenantCacheKey.fromId(savedTenant.getId()));
cachedExists =
existsTenantCache.get(TenantCacheKey.fromIdExists(savedTenant.getId()));
Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant);
Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedExists);
}
@Test
public void testDeleteTenantDeletingAllRelatedEntities() throws Exception {
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<OtaPackageInfo> pageDataOta = otaPackageService.findTenantOtaPackagesByTenantId(tenant.getId(), pageLinkOta);
Assert.assertEquals(0, pageDataOta.getTotalElements());
}
private void assertResourceIsDeleted(Tenant tenant, TbResource resource) {
assertThat(resourceService.findResourceById(tenant.getId(), resource.getId()))
.as("resource").isNull();
PageLink pageLinkResources = new PageLink(1);
PageData<TbResourceInfo> tenantResources =
resourceService.findAllTenantResourcesByTenantId(tenant.getId(), pageLinkResources);
Assert.assertEquals(0, tenantResources.getTotalElements());
}
private void assertUserIsDeleted(Tenant tenant, User user) {
assertThat(userService.findUserById(tenant.getId(), user.getId()))
.as("user").isNull();
PageLink pageLinkUsers = new PageLink(1);
PageData<User> users =
userService.findUsersByTenantId(tenant.getId(), pageLinkUsers);
Assert.assertEquals(0, users.getTotalElements());
}
private void assertTenantAdminIsDeleted(Tenant savedTenant) {
PageLink pageLinkTenantAdmins = new PageLink(1);
PageData<User> tenantAdmins =
userService.findTenantAdmins(savedTenant.getId(), pageLinkTenantAdmins);
Assert.assertEquals(0, tenantAdmins.getTotalElements());
}
private void assertEdgeIsDeleted(Tenant tenant, Edge edge) {
assertThat(edgeService.findEdgeById(tenant.getId(), edge.getId()))
.as("edge").isNull();
PageLink pageLinkEdges = new PageLink(1);
PageData<Edge> edges = edgeService.findEdgesByTenantId(tenant.getId(), pageLinkEdges);
Assert.assertEquals(0, edges.getTotalElements());
}
private void assertDashboardIsDeleted(Tenant tenant, Dashboard dashboard) {
assertThat(dashboardService.findDashboardById(tenant.getId(), dashboard.getId()))
.as("dashboard").isNull();
PageLink pageLinkDashboards = new PageLink(1);
PageData<DashboardInfo> dashboards =
dashboardService.findDashboardsByTenantId(tenant.getId(), pageLinkDashboards);
Assert.assertEquals(0, dashboards.getTotalElements());
}
private void assertDeviceProfileIsDeleted(Tenant tenant, DeviceProfile deviceProfile) {
assertThat(deviceProfileService.findDeviceProfileById(tenant.getId(), deviceProfile.getId()))
.as("deviceProfile").isNull();
PageLink pageLinkDeviceProfiles = new PageLink(1);
PageData<DeviceProfile> profiles =
deviceProfileService.findDeviceProfiles(tenant.getId(), pageLinkDeviceProfiles);
Assert.assertEquals(0, profiles.getTotalElements());
}
private void assertDeviceIsDeleted(Tenant tenant, Device device) {
assertThat(deviceService.findDeviceById(tenant.getId(), device.getId()))
.as("device").isNull();
PageLink pageLinkDevices = new PageLink(1);
PageData<Device> devices =
deviceService.findDevicesByTenantId(tenant.getId(), pageLinkDevices);
Assert.assertEquals(0, devices.getTotalElements());
}
private void assertAssetIsDeleted(Tenant tenant, Asset asset) {
assertThat(assetService.findAssetById(tenant.getId(), asset.getId()))
.as("asset").isNull();
PageLink pageLinkAssets = new PageLink(1);
PageData<Asset> assets =
assetService.findAssetsByTenantId(tenant.getId(), pageLinkAssets);
Assert.assertEquals(0, assets.getTotalElements());
}
private void assertEntityViewIsDeleted(Tenant tenant, Device device, EntityView entityView) {
assertThat(entityViewService.findEntityViewById(tenant.getId(), entityView.getId()))
.as("entityView").isNull();
List<EntityView> entityViews =
entityViewService.findEntityViewsByTenantIdAndEntityId(tenant.getId(), device.getId());
Assert.assertTrue(entityViews.isEmpty());
}
private void assertWidgetsBundleIsDeleted(Tenant tenant, WidgetsBundle widgetsBundle) {
assertThat(widgetsBundleService.findWidgetsBundleById(tenant.getId(), widgetsBundle.getId()))
.as("widgetBundle").isNull();
List<WidgetsBundle> widgetsBundlesByTenantId =
widgetsBundleService.findAllTenantWidgetsBundlesByTenantId(tenant.getId());
Assert.assertTrue(widgetsBundlesByTenantId.isEmpty());
}
private void assertCustomerIsDeleted(Tenant tenant, Customer customer) {
assertThat(customerService.findCustomerById(tenant.getId(), customer.getId()))
.as("customer").isNull();
PageLink pageLinkCustomer = new PageLink(1);
PageData<Customer> pageDataCustomer = customerService
.findCustomersByTenantId(tenant.getId(), pageLinkCustomer);
Assert.assertEquals(0, pageDataCustomer.getTotalElements());
}
private Rpc createAndSaveRpcFor(Tenant tenant, Device device) {
Rpc rpc = new Rpc();
rpc.setTenantId(tenant.getId());
rpc.setDeviceId(device.getId());
rpc.setStatus(RpcStatus.QUEUED);
rpc.setRequest(JacksonUtil.toJsonNode("{}"));
return rpcService.save(rpc);
}
private TbResource createAndSaveResourceFor(Tenant tenant) {
TbResource resource = new TbResource();
resource.setTenantId(tenant.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 tenant, DeviceProfile deviceProfile) {
return otaPackageService.saveOtaPackage(
BaseOtaPackageServiceTest.createFirmware(
tenant.getId(), "2", deviceProfile.getId())
);
}
private Edge createAndSaveEdgeFor(Tenant tenant) {
Edge edge = constructEdge(tenant.getId(), "Test edge", "Simple");
return edgeService.saveEdge(edge);
}
private RuleChain createAndSaveRuleChainFor(Tenant tenant) {
RuleChain ruleChain = new RuleChain();
ruleChain.setTenantId(tenant.getId());
ruleChain.setName("Test rule chain");
ruleChain.setType(RuleChainType.CORE);
return ruleChainService.saveRuleChain(ruleChain);
}
private Dashboard createAndSaveDashboardFor(Tenant tenant, Customer customer) {
Dashboard dashboard = new Dashboard();
dashboard.setTenantId(tenant.getId());
dashboard.setTitle("Test dashboard");
dashboard.setAssignedCustomers(Set.of(customer.toShortCustomerInfo()));
return dashboardService.saveDashboard(dashboard);
}
private Asset createAndSaveAssetFor(Tenant tenant, Customer customer) {
Asset asset = new Asset();
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 tenant, Customer customer, Device device) {
EntityView entityView = new EntityView();
entityView.setEntityId(device.getId());
entityView.setTenantId(tenant.getId());
entityView.setCustomerId(customer.getId());
entityView.setType("Test type");
entityView.setName("Test entity view");
entityView.setStartTimeMs(0);
entityView.setEndTimeMs(840000);
return entityViewService.saveEntityView(entityView);
}
private Device createAndSaveDeviceFor(Tenant tenant, Customer customer, DeviceProfile deviceProfile) {
Device device = new Device();
device.setCustomerId(customer.getId());
device.setTenantId(tenant.getId());
device.setType("Test type");
device.setName("TestType");
device.setLabel("Test type");
device.setDeviceProfileId(deviceProfile.getId());
return deviceService.saveDevice(device);
}
private DeviceProfile createAndSaveDeviceProfileWithProfileDataFor(Tenant tenant) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setTenantId(tenant.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 tenant) {
WidgetsBundle widgetsBundle = new WidgetsBundle();
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 tenant) {
Customer customer = new Customer();
customer.setTitle("Test customer");
customer.setTenantId(tenant.getId());
customer.setEmail("testCustomer@test.com");
return customerService.saveCustomer(customer);
}
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(tenant.getId());
return userService.saveUser(user);
}
private Tenant createAndSaveTenant(TenantProfile tenantProfile) {
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
tenant.setTenantProfileId(tenantProfile.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);
}
}

3
dao/src/test/resources/application-test.properties

@ -35,6 +35,9 @@ cache.specs.entityViews.maxSize=100000
cache.specs.claimDevices.timeToLiveInMinutes=1440
cache.specs.claimDevices.maxSize=100000
cache.specs.tenants.timeToLiveInMinutes=1440
cache.specs.tenants.maxSize=100000
cache.specs.securitySettings.timeToLiveInMinutes=1440
cache.specs.securitySettings.maxSize=100000

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java

@ -124,7 +124,7 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
}
private ListenableFuture<Boolean> 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<Boolean> processCreateRelation(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java

@ -98,7 +98,7 @@ public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteR
private ListenableFuture<Boolean> 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);

2
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<Boolean> processList(TbContext ctx, TbMsg msg) {

6
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));

Loading…
Cancel
Save