diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index 01c4d9b4e2..899d85993f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -31,7 +31,9 @@ public interface TenantService { ListenableFuture findTenantByIdAsync(TenantId callerId, TenantId tenantId); Tenant saveTenant(Tenant tenant); - + + boolean exists(TenantId tenantId); + void deleteTenant(TenantId tenantId); PageData findTenants(PageLink pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 50fe23f22b..48c86d8241 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; import org.springframework.stereotype.Service; import org.springframework.context.annotation.Lazy; import org.springframework.transaction.annotation.Transactional; @@ -107,7 +108,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe private RpcService rpcService; @Override - @Cacheable(cacheNames = TENANTS_CACHE, key = "#tenantId") + @Cacheable(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'TENANT'}") public Tenant findTenantById(TenantId tenantId) { log.trace("Executing findTenantById [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); @@ -130,7 +131,10 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional - @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenant.id", condition = "#tenant.id!=null") + @Caching(evict = { + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'TENANT'}", condition = "#tenant.id!=null"), + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenant.id, 'EXISTS'}", condition = "#tenant.id!=null") + }) public Tenant saveTenant(Tenant tenant) { log.trace("Executing saveTenant [{}]", tenant); tenant.setRegion(DEFAULT_TENANT_REGION); @@ -149,7 +153,10 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @Override @Transactional(timeout = 60 * 60) - @CacheEvict(cacheNames = TENANTS_CACHE, key = "#tenantId") + @Caching(evict = { + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'TENANT'}"), + @CacheEvict(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'EXISTS'}") + }) public void deleteTenant(TenantId tenantId) { log.trace("Executing deleteTenant [{}]", tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); @@ -198,6 +205,11 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe return tenantDao.findTenantsIds(pageLink); } + @Cacheable(cacheNames = TENANTS_CACHE, key = "{#tenantId, 'EXISTS'}") + public boolean exists(TenantId tenantId) { + return tenantDao.existsById(tenantId, tenantId.getId()); + } + private DataValidator tenantValidator = new DataValidator() { @Override diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index 3c4009144d..9021f1fd8a 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -335,14 +335,14 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Mockito.reset(tenantDao); - Objects.requireNonNull(tenantCache, "Tenant cache manager is null").evict(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Tenant cache manager is null").evict(List.of(savedTenant.getId(), "TENANT")); verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedTenant); for (int i = 0; i < 100; i++) { @@ -353,6 +353,30 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenantService.deleteTenant(savedTenant.getId()); } + @Test + public void testExistsTenantAddingResultToCache() { + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + Tenant savedTenant = tenantService.saveTenant(tenant); + + Mockito.reset(tenantDao); + + verify(tenantDao, Mockito.times(0)).existsById(any(), any()); + tenantService.exists(savedTenant.getId()); + verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + + Cache.ValueWrapper cachedExists = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); + Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedExists); + + for (int i = 0; i < 100; i++) { + tenantService.exists(savedTenant.getId()); + } + verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + + tenantService.deleteTenant(savedTenant.getId()); + } + @Test public void testUpdatingExistingTenantEvictCache() { Tenant tenant = new Tenant(); @@ -360,7 +384,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant savedTenant = tenantService.saveTenant(tenant); Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); savedTenant.setTitle("My new tenant"); @@ -368,13 +392,19 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Mockito.reset(tenantDao); - cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); verify(tenantDao, Mockito.times(0)).findById(any(), any()); tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + Mockito.reset(tenantDao); + + verify(tenantDao, Mockito.times(0)).existsById(any(), any()); + tenantService.exists(savedTenant.getId()); + verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); + tenantService.deleteTenant(savedTenant.getId()); } @@ -384,13 +414,24 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setTitle("My tenant"); Tenant savedTenant = tenantService.saveTenant(tenant); + tenantService.exists(savedTenant.getId()); + Cache.ValueWrapper cachedTenant = - Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + Cache.ValueWrapper cachedExists = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); + Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedExists); tenantService.deleteTenant(savedTenant.getId()); - cachedTenant = Objects.requireNonNull(tenantCache, "Cache manager is null!").get(savedTenant.getId()); + cachedTenant = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "TENANT")); + cachedExists = + Objects.requireNonNull(tenantCache, "Cache manager is null!").get(List.of(savedTenant.getId(), "EXISTS")); + + Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant); + Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedExists); } @Test