thingsboard-aplcache

Merge pull request #1108 from thingsboard/fix-for-delete Fixes

10/3/2018 12:54:41 PM

Details

diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.cql b/application/src/main/data/upgrade/2.1.1/schema_update.cql
index a633634..c477e8a 100644
--- a/application/src/main/data/upgrade/2.1.1/schema_update.cql
+++ b/application/src/main/data/upgrade/2.1.1/schema_update.cql
@@ -17,9 +17,10 @@
 DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_name;
 DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_search_text;
 DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer;
+DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_entity_id;
 
 DROP TABLE IF EXISTS thingsboard.entity_views;
-
+ControllerSqlTestSuite
 CREATE TABLE IF NOT EXISTS thingsboard.entity_views (
     id timeuuid,
     entity_id timeuuid,
@@ -67,3 +68,14 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_cus
       AND id IS NOT NULL
     PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id)
     WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS
+    SELECT *
+    from thingsboard.entity_views
+    WHERE tenant_id IS NOT NULL
+      AND customer_id IS NOT NULL
+      AND entity_id IS NOT NULL
+      AND search_text IS NOT NULL
+      AND id IS NOT NULL
+    PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id)
+    WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC);
\ No newline at end of file
diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
index 6c8b609..f35b890 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java
@@ -30,6 +30,7 @@ import org.springframework.util.StringUtils;
 import org.thingsboard.server.common.data.Customer;
 import org.thingsboard.server.common.data.EntitySubtype;
 import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.EntityView;
 import org.thingsboard.server.common.data.Tenant;
 import org.thingsboard.server.common.data.asset.Asset;
 import org.thingsboard.server.common.data.asset.AssetSearchQuery;
@@ -43,6 +44,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 import org.thingsboard.server.dao.customer.CustomerDao;
 import org.thingsboard.server.dao.entity.AbstractEntityService;
+import org.thingsboard.server.dao.entityview.EntityViewService;
 import org.thingsboard.server.dao.exception.DataValidationException;
 import org.thingsboard.server.dao.service.DataValidator;
 import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -77,6 +79,9 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
     private CustomerDao customerDao;
 
     @Autowired
+    private EntityViewService entityViewService;
+
+    @Autowired
     private CacheManager cacheManager;
 
     @Override
@@ -130,11 +135,21 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
         validateId(assetId, INCORRECT_ASSET_ID + assetId);
         deleteEntityRelations(assetId);
 
-        Cache cache = cacheManager.getCache(ASSET_CACHE);
         Asset asset = assetDao.findById(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 is assigned to entity views!");
+            }
+        } catch (Exception 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<Object> list = new ArrayList<>();
         list.add(asset.getTenantId());
         list.add(asset.getName());
+        Cache cache = cacheManager.getCache(ASSET_CACHE);
         cache.evict(list);
 
         assetDao.removeById(assetId.getId());
diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
index 9d96f3a..a9b8bfe 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java
@@ -115,9 +115,9 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom
             throw new IncorrectParameterException("Unable to delete non-existent customer.");
         }
         dashboardService.unassignCustomerDashboards(customerId);
+        entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId);
         assetService.unassignCustomerAssets(customer.getTenantId(), customerId);
         deviceService.unassignCustomerDevices(customer.getTenantId(), customerId);
-        entityViewService.unassignCustomerEntityViews(customer.getTenantId(), customerId);
         userService.deleteCustomerUsers(customer.getTenantId(), customerId);
         deleteEntityRelations(customerId);
         customerDao.removeById(customerId.getId());
diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
index 3930e3a..6f9ea62 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java
@@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.Customer;
 import org.thingsboard.server.common.data.Device;
 import org.thingsboard.server.common.data.EntitySubtype;
 import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.EntityView;
 import org.thingsboard.server.common.data.Tenant;
 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
 import org.thingsboard.server.common.data.id.CustomerId;
@@ -45,6 +46,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
 import org.thingsboard.server.dao.customer.CustomerDao;
 import org.thingsboard.server.dao.entity.AbstractEntityService;
+import org.thingsboard.server.dao.entityview.EntityViewService;
 import org.thingsboard.server.dao.exception.DataValidationException;
 import org.thingsboard.server.dao.service.DataValidator;
 import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -87,6 +89,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
     private DeviceCredentialsService deviceCredentialsService;
 
     @Autowired
+    private EntityViewService entityViewService;
+
+    @Autowired
     private CacheManager cacheManager;
 
     @Override
@@ -145,18 +150,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
     @Override
     public void deleteDevice(DeviceId deviceId) {
         log.trace("Executing deleteDevice [{}]", deviceId);
-        Cache cache = cacheManager.getCache(DEVICE_CACHE);
         validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
+
+        Device device = deviceDao.findById(deviceId.getId());
+        try {
+            List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get();
+            if (entityViews != null && !entityViews.isEmpty()) {
+                throw new DataValidationException("Can't delete device that is assigned to entity views!");
+            }
+        } catch (Exception e) {
+            log.error("Exception while finding entity views for deviceId [{}]", deviceId, e);
+            throw new RuntimeException("Exception while finding entity views for deviceId [" + deviceId + "]", e);
+        }
+
         DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId);
         if (deviceCredentials != null) {
             deviceCredentialsService.deleteDeviceCredentials(deviceCredentials);
         }
         deleteEntityRelations(deviceId);
-        Device device = deviceDao.findById(deviceId.getId());
+
         List<Object> list = new ArrayList<>();
         list.add(device.getTenantId());
         list.add(device.getName());
+        Cache cache = cacheManager.getCache(DEVICE_CACHE);
         cache.evict(list);
+
         deviceDao.removeById(deviceId.getId());
     }
 
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java
index 395f902..a03dd89 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java
@@ -40,7 +40,8 @@ import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
 import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
 import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ID_PROPERTY;
 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN;
-import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF;
+import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF;
 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_NAME;
 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME;
 import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_VIEW_NAME_PROPERTY;
@@ -101,7 +102,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
         log.debug("Try to find entity views by tenantId [{}], customerId[{}] and pageLink [{}]",
                 tenantId, customerId, pageLink);
         List<EntityViewEntity> entityViewEntities = findPageWithTextSearch(
-                ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT,
+                ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF,
                 Arrays.asList(eq(CUSTOMER_ID_PROPERTY, customerId), eq(TENANT_ID_PROPERTY, tenantId)),
                 pageLink);
         log.trace("Found find entity views [{}] by tenantId [{}], customerId [{}] and pageLink [{}]",
@@ -112,7 +113,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
     @Override
     public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) {
         log.debug("Try to find entity views by tenantId [{}] and entityId [{}]", tenantId, entityId);
-        Select.Where query = select().from(getColumnFamilyName()).where();
+        Select.Where query = select().from(ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF).where();
         query.and(eq(TENANT_ID_PROPERTY, tenantId));
         query.and(eq(ENTITY_ID_COLUMN, entityId));
         return findListByStatementAsync(query);
diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
index 9890ff6..a487ede 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
@@ -150,7 +150,8 @@ public class ModelConstants {
     public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
     public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
     public static final String ENTITY_VIEW_NAME_PROPERTY = DEVICE_NAME_PROPERTY;
-    public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_SEARCH_TEXT = "entity_view_by_tenant_and_customer";
+    public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF = "entity_view_by_tenant_and_customer";
+    public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF = "entity_view_by_tenant_and_entity_id";
     public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys";
     public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts";
     public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts";
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 a94e715..189c713 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
@@ -105,9 +105,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
         customerService.deleteCustomersByTenantId(tenantId);
         widgetsBundleService.deleteWidgetsBundlesByTenantId(tenantId);
         dashboardService.deleteDashboardsByTenantId(tenantId);
+        entityViewService.deleteEntityViewsByTenantId(tenantId);
         assetService.deleteAssetsByTenantId(tenantId);
         deviceService.deleteDevicesByTenantId(tenantId);
-        entityViewService.deleteEntityViewsByTenantId(tenantId);
         userService.deleteTenantAdmins(tenantId);
         ruleChainService.deleteRuleChainsByTenantId(tenantId);
         tenantDao.removeById(tenantId.getId());
diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql
index bd978f7..7ccd41f 100644
--- a/dao/src/main/resources/cassandra/schema-entities.cql
+++ b/dao/src/main/resources/cassandra/schema-entities.cql
@@ -671,3 +671,14 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_cus
       AND id IS NOT NULL
     PRIMARY KEY (tenant_id, customer_id, search_text, id, entity_id)
     WITH CLUSTERING ORDER BY (customer_id DESC, search_text ASC, id DESC);
+
+CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.entity_view_by_tenant_and_entity_id AS
+    SELECT *
+    from thingsboard.entity_views
+    WHERE tenant_id IS NOT NULL
+      AND customer_id IS NOT NULL
+      AND entity_id IS NOT NULL
+      AND search_text IS NOT NULL
+      AND id IS NOT NULL
+    PRIMARY KEY (tenant_id, entity_id, customer_id, search_text, id)
+    WITH CLUSTERING ORDER BY (entity_id DESC, customer_id DESC, search_text ASC, id DESC);
\ No newline at end of file
diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties
index 20cf91c..a61c285 100644
--- a/dao/src/test/resources/application-test.properties
+++ b/dao/src/test/resources/application-test.properties
@@ -24,6 +24,9 @@ caffeine.specs.devices.maxSize=100000
 caffeine.specs.assets.timeToLiveInMinutes=1440
 caffeine.specs.assets.maxSize=100000
 
+caffeine.specs.entityViews.timeToLiveInMinutes=1440
+caffeine.specs.entityViews.maxSize=100000
+
 caching.specs.devices.timeToLiveInMinutes=1440
 caching.specs.devices.maxSize=100000