From 4489440ae341615daf32c024c39caedca28bc670 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Mon, 24 Sep 2018 14:55:49 +0300 Subject: [PATCH 1/7] Were renamed variables --- .../controller/BaseEntityViewControllerTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 9dc13a8d37..0daaeca72f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -343,18 +343,18 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes client.publish("v1/devices/me/attributes", message); Thread.sleep(1000); - List actualTelemetry = + List actualAttributes = doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class); - Set actualTelemetrySet = new HashSet<>(actualTelemetry); + Set actualAttributesSet = new HashSet<>(actualAttributes); - List expectedActualTelemetry = Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"); - Set expectedActualTelemetrySet = new HashSet<>(expectedActualTelemetry); - assertTrue(actualTelemetrySet.containsAll(expectedActualTelemetrySet)); + List expectedActualAttributes = Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"); + Set expectedActualAttributesSet = new HashSet<>(expectedActualAttributes); + assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); Thread.sleep(1000); EntityView savedView = getNewSavedEntityView("Test entity view"); String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualTelemetrySet); + "/values/attributes?keys=" + String.join(",", actualAttributesSet); List> values = doGetAsync(urlOfTelemetryValues, List.class); assertEquals("value1", getValueOfMap(values, "caValue1")); From 2269656b095340b4d2892bfc4fc31cf483121663 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Tue, 25 Sep 2018 18:57:04 +0300 Subject: [PATCH 2/7] Were fixed --- .../server/controller/BaseController.java | 6 +- .../controller/EntityViewController.java | 26 +-- .../entityview/CassandraEntityViewDao.java | 2 +- .../server/dao/entityview/EntityViewDao.java | 2 +- .../dao/entityview/EntityViewService.java | 19 +- .../dao/entityview/EntityViewServiceImpl.java | 210 +++++++++++------- .../dao/sql/entityview/JpaEntityViewDao.java | 2 +- .../TbCopyAttributesToEntityViewNode.java | 59 +++-- 8 files changed, 184 insertions(+), 142 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index af62e04cff..84a8151316 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -318,7 +318,7 @@ public abstract class BaseController { checkUserId(new UserId(entityId.getId())); return; case ENTITY_VIEW: - checkEntityView(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); + checkEntityViewId(entityViewService.findEntityViewById(new EntityViewId(entityId.getId()))); return; default: throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); @@ -351,14 +351,14 @@ public abstract class BaseController { try { validateId(entityViewId, "Incorrect entityViewId " + entityViewId); EntityView entityView = entityViewService.findEntityViewById(entityViewId); - checkEntityView(entityView); + checkEntityViewId(entityView); return entityView; } catch (Exception e) { throw handleException(e, false); } } - protected void checkEntityView(EntityView entityView) throws ThingsboardException { + protected void checkEntityViewId(EntityView entityView) throws ThingsboardException { checkNotNull(entityView); checkTenantId(entityView.getTenantId()); if (entityView.getCustomerId() != null && !entityView.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java index 26a48daff6..e6f149e05c 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -17,7 +17,14 @@ package org.thingsboard.server.controller; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; @@ -49,13 +56,10 @@ public class EntityViewController extends BaseController { @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.GET) @ResponseBody - public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) - throws ThingsboardException { - + public EntityView getEntityViewById(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { checkParameter(ENTITY_VIEW_ID, strEntityViewId); try { - EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); - return checkEntityViewId(entityViewId); + return checkEntityViewId(new EntityViewId(toUUID(strEntityViewId))); } catch (Exception e) { throw handleException(e); } @@ -70,13 +74,10 @@ public class EntityViewController extends BaseController { EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); logEntityAction(savedEntityView.getId(), savedEntityView, null, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); - return savedEntityView; - } catch (Exception e) { logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); - throw handleException(e); } } @@ -90,7 +91,6 @@ public class EntityViewController extends BaseController { EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); EntityView entityView = checkEntityViewId(entityViewId); entityViewService.deleteEntityView(entityViewId); - logEntityAction(entityViewId, entityView, entityView.getCustomerId(), ActionType.DELETED,null, strEntityViewId); } catch (Exception e) { @@ -117,11 +117,9 @@ public class EntityViewController extends BaseController { checkEntityViewId(entityViewId); EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToCustomer(entityViewId, customerId)); - logEntityAction(entityViewId, savedEntityView, savedEntityView.getCustomerId(), ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName()); - return savedEntityView; } catch (Exception e) { logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, @@ -143,9 +141,7 @@ public class EntityViewController extends BaseController { throw new IncorrectParameterException("Entity View isn't assigned to any customer!"); } Customer customer = checkCustomerId(entityView.getCustomerId()); - EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromCustomer(entityViewId)); - logEntityAction(entityViewId, entityView, entityView.getCustomerId(), ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName()); @@ -208,7 +204,7 @@ public class EntityViewController extends BaseController { List entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(query).get()); entityViews = entityViews.stream().filter(entityView -> { try { - checkEntityView(entityView); + checkEntityViewId(entityView); return true; } catch (ThingsboardException e) { return false; 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 e866bc89b8..395f9022b0 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 @@ -78,7 +78,7 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { + public List findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink) { log.debug("Try to find entity views by tenantId [{}] and pageLink [{}]", tenantId, pageLink); List entityViewEntities = findPageWithTextSearch(ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME, diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java index 742cb92d90..ba433855e2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java @@ -45,7 +45,7 @@ public interface EntityViewDao extends Dao { * @param pageLink the page link * @return the list of entity view objects */ - List findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink); + List findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink); /** * Find entity views by tenantId and entity view name. diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index 89b7e2f85c..19f326c0bc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -32,28 +32,27 @@ import java.util.List; */ public interface EntityViewService { - EntityView findEntityViewById(EntityViewId entityViewId); - EntityView saveEntityView(EntityView entityView); EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId); EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId); - void deleteEntityView(EntityViewId entityViewId); + void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); - TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); + EntityView findEntityViewById(EntityViewId entityViewId); - void deleteEntityViewsByTenantId(TenantId tenantId); + TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink); - TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, - TextPageLink pageLink); + TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink); - void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId); + ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query); ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId); - ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query); - ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId); + + void deleteEntityView(EntityViewId entityViewId); + + void deleteEntityViewsByTenantId(TenantId tenantId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 8647af7fe4..79ceff2351 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -24,7 +24,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; @@ -41,6 +40,7 @@ import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; +import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -54,13 +54,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.CacheConstants.ENTITY_VIEW_CACHE; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; 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 Victor Basanets on 8/28/2017. @@ -73,6 +74,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti 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 "; + private static final int DEFAULT_LIMIT = 100; @Autowired private EntityViewDao entityViewDao; @@ -89,13 +91,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; - @Override - public EntityView findEntityViewById(EntityViewId entityViewId) { - log.trace("Executing findEntityViewById [{}]", entityViewId); - validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - return entityViewDao.findById(entityViewId.getId()); - } - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.name}") @Override public EntityView saveEntityView(EntityView entityView) { @@ -110,41 +105,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return savedEntityView; } - private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { - if (keys != null && !keys.isEmpty()) { - ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); - Futures.addCallback(getAttrFuture, new FutureCallback>() { - @Override - public void onSuccess(@Nullable List attributeKvEntries) { - if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { - List filteredAttributes = - attributeKvEntries.stream() - .filter(attributeKvEntry -> { - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { - return true; - } - if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { - return true; - } - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { - return true; - } - return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() - && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); - }).collect(Collectors.toList()); - attributesService.save(entityView.getId(), scope, filteredAttributes); - } - } - - @Override - public void onFailure(Throwable throwable) { - log.error("Failed to fetch [{}] attributes [{}] for [{}] entity [{}]", - scope, keys, entityView.getEntityId().getEntityType().name(), entityView.getEntityId().getId().toString(), throwable); - } - }); - } - } - @Override public EntityView assignEntityViewToCustomer(EntityViewId entityViewId, CustomerId customerId) { EntityView entityView = findEntityViewById(entityViewId); @@ -160,63 +120,66 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti } @Override - public void deleteEntityView(EntityViewId entityViewId) { - log.trace("Executing deleteEntityView [{}]", entityViewId); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) { + log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); + new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); + } + + + @Override + public EntityView findEntityViewById(EntityViewId entityViewId) { + log.trace("Executing findEntityViewById [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - deleteEntityRelations(entityViewId); - EntityView entityView = entityViewDao.findById(entityViewId.getId()); - cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getName())); - entityViewDao.removeById(entityViewId.getId()); + List ids = Arrays.asList(entityViewId.getId()); + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + EntityView fromCache = cache.get(ids, EntityView.class); + if (fromCache != null) { + return fromCache; + } else { + ListenableFuture entityViewFuture + = Futures.immediateFuture(entityViewDao.findById(entityViewId.getId())); + Futures.addCallback(entityViewFuture, + new FutureCallback() { + @Override + public void onSuccess(@Nullable EntityView result) { + cache.putIfAbsent(ids, result); + } + @Override + public void onFailure(Throwable t) {} + }); + try { + return entityViewFuture.get(); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + return entityViewDao.findById(entityViewId.getId()); } @Override public TextPageData findEntityViewByTenantId(TenantId tenantId, TextPageLink pageLink) { - log.trace("Executing findEntityViewByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); + log.trace("Executing findEntityViewsByTenantId, tenantId [{}], pageLink [{}]", tenantId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); - List entityViews = entityViewDao.findEntityViewByTenantId(tenantId.getId(), pageLink); + List entityViews = entityViewDao.findEntityViewsByTenantId(tenantId.getId(), pageLink); return new TextPageData<>(entityViews, pageLink); } - @Override - public void deleteEntityViewsByTenantId(TenantId tenantId) { - log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - tenantEntityViewRemover.removeEntities(tenantId); - } - @Override public TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TextPageLink pageLink) { - log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," + " pageLink [{}]", tenantId, customerId, pageLink); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); List entityViews = entityViewDao.findEntityViewsByTenantIdAndCustomerId(tenantId.getId(), customerId.getId(), pageLink); - return new TextPageData<>(entityViews, pageLink); } - @Override - public void unassignCustomerEntityViews(TenantId tenantId, CustomerId customerId) { - log.trace("Executing unassignCustomerEntityViews, tenantId [{}], customerId [{}]", tenantId, customerId); - validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); - new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); - } - - @Override - public ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId) { - log.trace("Executing findEntityViewById [{}]", entityViewId); - validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - return entityViewDao.findByIdAsync(entityViewId.getId()); - } - @Override public ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query) { ListenableFuture> relations = relationService.findByQuery(query.toEntitySearchQuery()); @@ -235,12 +198,99 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViews; } + @Override + public ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId) { + log.trace("Executing findEntityViewById [{}]", entityViewId); + validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); + return entityViewDao.findByIdAsync(entityViewId.getId()); + } + @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(entityId.getId(), "Incorrect entityId" + entityId); - return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + + List tenantAndEntityIds = Arrays.asList(tenantId, entityId); + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + List fromCache = cache.get(tenantAndEntityIds, List.class); + if (fromCache != null) { + return Futures.immediateFuture(fromCache); + } else { + ListenableFuture> entityViewsFuture = + entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + Futures.addCallback(entityViewsFuture, + new FutureCallback>() { + @Override + public void onSuccess(@Nullable List result) { + cache.putIfAbsent(tenantAndEntityIds, result); + } + @Override + public void onFailure(Throwable t) {} + }); + return entityViewsFuture; + } + } + + @Override + public void deleteEntityView(EntityViewId entityViewId) { + log.trace("Executing deleteEntityView [{}]", entityViewId); + validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); + deleteEntityRelations(entityViewId); + cacheEvict(entityViewId, cacheManager.getCache(ENTITY_VIEW_CACHE)); + entityViewDao.removeById(entityViewId.getId()); + } + + @Override + public void deleteEntityViewsByTenantId(TenantId tenantId) { + log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + entityViewDao.findEntityViewsByTenantId(tenantId.getId(), new TextPageLink(DEFAULT_LIMIT)).stream() + .map(view -> view.getId()) + .collect(Collectors.toList()) + .forEach(id -> cacheEvict(id, cacheManager.getCache(ENTITY_VIEW_CACHE))); + tenantEntityViewRemover.removeEntities(tenantId); + } + + private void cacheEvict(EntityViewId entityViewId, Cache cache) { + EntityView entityView = entityViewDao.findById(entityViewId.getId()); + cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getName())); + cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); + } + + private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { + if (keys != null && !keys.isEmpty()) { + ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); + Futures.addCallback(getAttrFuture, new FutureCallback>() { + @Override + public void onSuccess(@Nullable List attributeKvEntries) { + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { + List filteredAttributes = + attributeKvEntries.stream() + .filter(attributeKvEntry -> { + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { + return true; + } + if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { + return true; + } + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { + return true; + } + return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() + && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); + }).collect(Collectors.toList()); + attributesService.save(entityView.getId(), scope, filteredAttributes); + } + } + + @Override + public void onFailure(Throwable throwable) { + log.error("Failed to fetch [{}] attributes [{}] for [{}] entity [{}]", + scope, keys, entityView.getEntityId().getEntityType().name(), entityView.getEntityId().getId().toString(), throwable); + } + }); + } } private DataValidator entityViewValidator = @@ -296,7 +346,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override protected List findEntities(TenantId id, TextPageLink pageLink) { - return entityViewDao.findEntityViewByTenantId(id.getId(), pageLink); + return entityViewDao.findEntityViewsByTenantId(id.getId(), pageLink); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index 0cd1b2b0d6..912c9d5eed 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -66,7 +66,7 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao findEntityViewByTenantId(UUID tenantId, TextPageLink pageLink) { + public List findEntityViewsByTenantId(UUID tenantId, TextPageLink pageLink) { return DaoUtil.convertDataList( entityViewRepository.findByTenantId( fromTimeUUID(tenantId), diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java index d609620edf..c5dcc0f62d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -15,9 +15,7 @@ */ package org.thingsboard.rule.engine.action; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Function; -import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; @@ -28,24 +26,23 @@ import org.thingsboard.rule.engine.api.TbNode; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.DonAsynchron; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.kv.AttributeKvEntry; -import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import javax.annotation.Nullable; -import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; +import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; @Slf4j @RuleNode( @@ -70,25 +67,22 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { - if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) || - msg.getType().equals(DataConstants.ATTRIBUTES_DELETED) || - msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) { + if (!msg.getMetaData().getData().isEmpty()) { long now = System.currentTimeMillis(); - String scope; - if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) { - scope = DataConstants.CLIENT_SCOPE; - } else { - scope = msg.getMetaData().getValue("scope"); - } + String scope = msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ? + DataConstants.CLIENT_SCOPE : msg.getMetaData().getValue("scope"); + ListenableFuture> entityViewsFuture = ctx.getEntityViewService().findEntityViewsByTenantIdAndEntityIdAsync(ctx.getTenantId(), msg.getOriginator()); - withCallback(entityViewsFuture, + + DonAsynchron.withCallback(entityViewsFuture, entityViews -> { - List>> saveFutures = new ArrayList<>(); for (EntityView entityView : entityViews) { - if ((entityView.getEndTimeMs() != 0 && entityView.getEndTimeMs() > now && entityView.getStartTimeMs() < now) || - (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < now)) { - Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes(); + long startTime = entityView.getStartTimeMs(); + long endTime = entityView.getEndTimeMs(); + if ((endTime != 0 && endTime > now && startTime < now) || (endTime == 0 && startTime < now)) { + Set attributes = + JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes(); List filteredAttributes = attributes.stream() .filter(attr -> { @@ -110,19 +104,22 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { return entityView.getKeys().getAttributes().getSh().contains(attr.getKey()); } return false; - }) - .collect(Collectors.toList()); - saveFutures.add(ctx.getAttributesService().save(entityView.getId(), scope, new ArrayList<>(filteredAttributes))); + }).collect(Collectors.toList()); + + ctx.getTelemetryService().saveAndNotify(entityView.getId(), scope, filteredAttributes, + new FutureCallback() { + @Override + public void onSuccess(@Nullable Void result) { + ctx.tellNext(msg, SUCCESS); + } + + @Override + public void onFailure(Throwable t) { + ctx.tellFailure(msg, t); + } + }); } } - Futures.transform(Futures.allAsList(saveFutures), new Function>, Object>() { - @Nullable - @Override - public Object apply(@Nullable List> lists) { - ctx.tellNext(msg, TbRelationTypes.SUCCESS); - return null; - } - }); }, t -> ctx.tellFailure(msg, t)); } else { From 7bcb64958dd325e3ac401f57c4ebffb1418cc379 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Wed, 26 Sep 2018 11:43:15 +0300 Subject: [PATCH 3/7] Fixed --- .../controller/ControllerSqlTestSuite.java | 2 +- .../dao/entityview/EntityViewServiceImpl.java | 78 ++++++++++--------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java index c8a5da8151..a9e94e9184 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -24,7 +24,7 @@ import java.util.Arrays; @RunWith(ClasspathSuite.class) @ClasspathSuite.ClassnameFilters({ - "org.thingsboard.server.controller.sql.*Test", + "org.thingsboard.server.controller.sql.EntityViewControllerSqlTest", }) public class ControllerSqlTestSuite { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 79ceff2351..c1c2b6548d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -97,10 +97,19 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti log.trace("Executing save entity view [{}]", entityView); entityViewValidator.validate(entityView); EntityView savedEntityView = entityViewDao.save(entityView); + List>> futures = new ArrayList<>(); if (savedEntityView.getKeys() != null) { - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs()); - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs()); - copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh()); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs())); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs())); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh())); + } + for (ListenableFuture> future : futures) { + try { + future.get(); + } catch (InterruptedException | ExecutionException e) { + log.error("Failed to copy attributes to entity view", e); + throw new RuntimeException("Failed to copy attributes to entity view", e); + } } return savedEntityView; } @@ -169,9 +178,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override public TextPageData findEntityViewsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, - TextPageLink pageLink) { + TextPageLink pageLink) { log.trace("Executing findEntityViewByTenantIdAndCustomerId, tenantId [{}], customerId [{}]," + - " pageLink [{}]", tenantId, customerId, pageLink); + " pageLink [{}]", tenantId, customerId, pageLink); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); validatePageLink(pageLink, INCORRECT_PAGE_LINK + pageLink); @@ -246,7 +255,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); entityViewDao.findEntityViewsByTenantId(tenantId.getId(), new TextPageLink(DEFAULT_LIMIT)).stream() - .map(view -> view.getId()) + .map(view -> view.getId()) .collect(Collectors.toList()) .forEach(id -> cacheEvict(id, cacheManager.getCache(ENTITY_VIEW_CACHE))); tenantEntityViewRemover.removeEntities(tenantId); @@ -258,38 +267,37 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); } - private void copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { + private ListenableFuture> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { if (keys != null && !keys.isEmpty()) { ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); - Futures.addCallback(getAttrFuture, new FutureCallback>() { - @Override - public void onSuccess(@Nullable List attributeKvEntries) { - if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { - List filteredAttributes = - attributeKvEntries.stream() - .filter(attributeKvEntry -> { - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { - return true; - } - if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { - return true; - } - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { - return true; - } - return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() - && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); - }).collect(Collectors.toList()); - attributesService.save(entityView.getId(), scope, filteredAttributes); - } + return Futures.transform(getAttrFuture, attributeKvEntries -> { + List filteredAttributes = new ArrayList<>(); + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { + filteredAttributes = + attributeKvEntries.stream() + .filter(attributeKvEntry -> { + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { + return true; + } + if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { + return true; + } + if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { + return true; + } + return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() + && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); + }).collect(Collectors.toList()); } - - @Override - public void onFailure(Throwable throwable) { - log.error("Failed to fetch [{}] attributes [{}] for [{}] entity [{}]", - scope, keys, entityView.getEntityId().getEntityType().name(), entityView.getEntityId().getId().toString(), throwable); + try { + return attributesService.save(entityView.getId(), scope, filteredAttributes).get(); + } catch (InterruptedException | ExecutionException e) { + log.error("Failed to copy attributes to entity view", e); + throw new RuntimeException("Failed to copy attributes to entity view", e); } }); + } else { + return Futures.immediateFuture(null); } } @@ -299,7 +307,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override protected void validateCreate(EntityView entityView) { entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName()) - .ifPresent( e -> { + .ifPresent(e -> { throw new DataValidationException("Entity view with such name already exists!"); }); } @@ -307,7 +315,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Override protected void validateUpdate(EntityView entityView) { entityViewDao.findEntityViewByTenantIdAndName(entityView.getTenantId().getId(), entityView.getName()) - .ifPresent( e -> { + .ifPresent(e -> { if (!e.getUuidId().equals(entityView.getUuidId())) { throw new DataValidationException("Entity view with such name already exists!"); } From 87eb21d68ff41ea15a27a9b28714e79173bb71d8 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 27 Sep 2018 13:11:06 +0300 Subject: [PATCH 4/7] Were fixed caches --- .../dao/entityview/EntityViewServiceImpl.java | 76 ++++--------------- 1 file changed, 14 insertions(+), 62 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index c1c2b6548d..a45a6419b1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.entityview; -import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; @@ -24,6 +23,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; 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.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; @@ -40,7 +41,6 @@ import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; -import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerDao; import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -49,12 +49,10 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TenantDao; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; @@ -74,7 +72,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti 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 "; - private static final int DEFAULT_LIMIT = 100; @Autowired private EntityViewDao entityViewDao; @@ -91,12 +88,15 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @Autowired private CacheManager cacheManager; - @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.name}") + @Caching(evict = { + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.tenantId, #entityView.entityId}"), + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityView.id}")}) @Override public EntityView saveEntityView(EntityView entityView) { log.trace("Executing save entity view [{}]", entityView); entityViewValidator.validate(entityView); EntityView savedEntityView = entityViewDao.save(entityView); + List>> futures = new ArrayList<>(); if (savedEntityView.getKeys() != null) { futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs())); @@ -121,6 +121,7 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return saveEntityView(entityView); } + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public EntityView unassignEntityViewFromCustomer(EntityViewId entityViewId) { EntityView entityView = findEntityViewById(entityViewId); @@ -136,34 +137,11 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti new CustomerEntityViewsUnAssigner(tenantId).removeEntities(customerId); } - + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public EntityView findEntityViewById(EntityViewId entityViewId) { log.trace("Executing findEntityViewById [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); - List ids = Arrays.asList(entityViewId.getId()); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); - EntityView fromCache = cache.get(ids, EntityView.class); - if (fromCache != null) { - return fromCache; - } else { - ListenableFuture entityViewFuture - = Futures.immediateFuture(entityViewDao.findById(entityViewId.getId())); - Futures.addCallback(entityViewFuture, - new FutureCallback() { - @Override - public void onSuccess(@Nullable EntityView result) { - cache.putIfAbsent(ids, result); - } - @Override - public void onFailure(Throwable t) {} - }); - try { - return entityViewFuture.get(); - } catch (Exception e) { - log.error(e.getMessage()); - } - } return entityViewDao.findById(entityViewId.getId()); } @@ -203,7 +181,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti } return Futures.successfulAsList(futures); }); - return entityViews; } @@ -214,39 +191,24 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViewDao.findByIdAsync(entityViewId.getId()); } + @Cacheable(cacheNames = ENTITY_VIEW_CACHE, key = "{#tenantId, #entityId}") @Override public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); validateId(entityId.getId(), "Incorrect entityId" + entityId); - - List tenantAndEntityIds = Arrays.asList(tenantId, entityId); - Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); - List fromCache = cache.get(tenantAndEntityIds, List.class); - if (fromCache != null) { - return Futures.immediateFuture(fromCache); - } else { - ListenableFuture> entityViewsFuture = - entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); - Futures.addCallback(entityViewsFuture, - new FutureCallback>() { - @Override - public void onSuccess(@Nullable List result) { - cache.putIfAbsent(tenantAndEntityIds, result); - } - @Override - public void onFailure(Throwable t) {} - }); - return entityViewsFuture; - } + return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); } + @CacheEvict(cacheNames = ENTITY_VIEW_CACHE, key = "{#entityViewId}") @Override public void deleteEntityView(EntityViewId entityViewId) { log.trace("Executing deleteEntityView [{}]", entityViewId); validateId(entityViewId, INCORRECT_ENTITY_VIEW_ID + entityViewId); deleteEntityRelations(entityViewId); - cacheEvict(entityViewId, cacheManager.getCache(ENTITY_VIEW_CACHE)); + Cache cache = cacheManager.getCache(ENTITY_VIEW_CACHE); + EntityView entityView = entityViewDao.findById(entityViewId.getId()); + cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); entityViewDao.removeById(entityViewId.getId()); } @@ -254,19 +216,9 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti public void deleteEntityViewsByTenantId(TenantId tenantId) { log.trace("Executing deleteEntityViewsByTenantId, tenantId [{}]", tenantId); validateId(tenantId, INCORRECT_TENANT_ID + tenantId); - entityViewDao.findEntityViewsByTenantId(tenantId.getId(), new TextPageLink(DEFAULT_LIMIT)).stream() - .map(view -> view.getId()) - .collect(Collectors.toList()) - .forEach(id -> cacheEvict(id, cacheManager.getCache(ENTITY_VIEW_CACHE))); tenantEntityViewRemover.removeEntities(tenantId); } - private void cacheEvict(EntityViewId entityViewId, Cache cache) { - EntityView entityView = entityViewDao.findById(entityViewId.getId()); - cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getName())); - cache.evict(Arrays.asList(entityView.getTenantId(), entityView.getEntityId())); - } - private ListenableFuture> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { if (keys != null && !keys.isEmpty()) { ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); From 5a65ec75fe6dece007277555044770ed8952efd4 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Thu, 27 Sep 2018 17:07:54 +0300 Subject: [PATCH 5/7] Reviewed --- .../dao/entityview/EntityViewServiceImpl.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index a45a6419b1..9fdadcd631 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -228,17 +228,13 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti filteredAttributes = attributeKvEntries.stream() .filter(attributeKvEntry -> { - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() == 0) { - return true; - } - if (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs()) { - return true; - } - if (entityView.getStartTimeMs() == 0 && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs()) { - return true; - } - return entityView.getStartTimeMs() < attributeKvEntry.getLastUpdateTs() - && entityView.getEndTimeMs() > attributeKvEntry.getLastUpdateTs(); + long startTime = entityView.getStartTimeMs(); + long endTime = entityView.getEndTimeMs(); + long lastUpdateTs = attributeKvEntry.getLastUpdateTs(); + return startTime == 0 && endTime == 0 || + (endTime == 0 && startTime < lastUpdateTs) || + (startTime == 0 && endTime > lastUpdateTs) || + (startTime < lastUpdateTs && endTime > lastUpdateTs); }).collect(Collectors.toList()); } try { From 49a98673525407ace293bc86a14b2a44a2a88fbe Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 28 Sep 2018 17:56:32 +0300 Subject: [PATCH 6/7] After review --- .../BaseEntityViewControllerTest.java | 86 +++++++++++++------ .../dao/entityview/EntityViewServiceImpl.java | 4 +- 2 files changed, 64 insertions(+), 26 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index 0daaeca72f..a877cbf71a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -319,12 +319,62 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes } @Test - public void testTheCopyOfAttrsThatMatchWithDeviceCriteriaForTheView() throws Exception { + public void testTheCopyOfAttrsIntoTSForTheView() throws Exception { + Set actualAttributesSet = + getAttributesByKeys("{\"caValue1\":\"value1\", \"caValue2\":true, \"caValue3\":42.0, \"caValue4\":73}"); - String viewDeviceId = testDevice.getId().getId().toString(); - DeviceCredentials deviceCredentials - = doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); + Set expectedActualAttributesSet = + new HashSet<>(Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4")); + assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); + Thread.sleep(1000); + + EntityView savedView = getNewSavedEntityView("Test entity view"); + String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet); + List> values = doGetAsync(urlOfTelemetryValues, List.class); + + assertEquals("value1", getValue(values, "caValue1")); + assertEquals(true, getValue(values, "caValue2")); + assertEquals(42.0, getValue(values, "caValue3")); + assertEquals(73, getValue(values, "caValue4")); + } + + @Test + public void testTheCopyOfAttrsOutOfTSForTheView() throws Exception { + Set actualAttributesSet = + getAttributesByKeys("{\"caValue1\":\"value1\", \"caValue2\":true, \"caValue3\":42.0, \"caValue4\":73}"); + + Set expectedActualAttributesSet = new HashSet<>(Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4")); + assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); + Thread.sleep(1000); + + List> values = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); + + EntityView view = new EntityView(); + view.setEntityId(testDevice.getId()); + view.setTenantId(savedTenant.getId()); + view.setName("Test entity view"); + view.setKeys(telemetry); + view.setStartTimeMs((long) getValue(values, "lastUpdateTs") * 10); + view.setEndTimeMs((long) getValue(values, "lastUpdateTs") / 10); + EntityView savedView = doPost("/api/entityView", view, EntityView.class); + + String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet); + values = doGetAsync(urlOfTelemetryValues, List.class); + + assertEquals("value1", getValue(values, "caValue1")); + assertEquals(true, getValue(values, "caValue2")); + assertEquals(42.0, getValue(values, "caValue3")); + assertEquals(73, getValue(values, "caValue4")); + } + + private Set getAttributesByKeys(String stringKV) throws Exception { + String viewDeviceId = testDevice.getId().getId().toString(); + DeviceCredentials deviceCredentials = + doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); assertEquals(testDevice.getId(), deviceCredentials.getDeviceId()); String accessToken = deviceCredentials.getCredentialsId(); @@ -339,31 +389,19 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Thread.sleep(3000); MqttMessage message = new MqttMessage(); - message.setPayload(("{\"caValue1\":\"value1\", \"caValue2\":true, \"caValue3\":42.0, \"caValue4\":73}").getBytes()); + message.setPayload((stringKV).getBytes()); client.publish("v1/devices/me/attributes", message); Thread.sleep(1000); - List actualAttributes = - doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class); - Set actualAttributesSet = new HashSet<>(actualAttributes); - - List expectedActualAttributes = Arrays.asList("caValue1", "caValue2", "caValue3", "caValue4"); - Set expectedActualAttributesSet = new HashSet<>(expectedActualAttributes); - assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); - Thread.sleep(1000); - - EntityView savedView = getNewSavedEntityView("Test entity view"); - String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet); - List> values = doGetAsync(urlOfTelemetryValues, List.class); - - assertEquals("value1", getValueOfMap(values, "caValue1")); - assertEquals(true, getValueOfMap(values, "caValue2")); - assertEquals(42.0, getValueOfMap(values, "caValue3")); - assertEquals(73, getValueOfMap(values, "caValue4")); + return new HashSet<>(doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class)); } - private Object getValueOfMap(List> values, String stringValue) { + /*private Object getLastTs(List> values) { + return values.stream() + .filter(value -> value.get("key"); + } +*/ + private Object getValue(List> values, String stringValue) { return values.stream() .filter(value -> value.get("key").equals(stringValue)) .findFirst().get().get("value"); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index 9fdadcd631..6e7eba08c8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -233,8 +233,8 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti long lastUpdateTs = attributeKvEntry.getLastUpdateTs(); return startTime == 0 && endTime == 0 || (endTime == 0 && startTime < lastUpdateTs) || - (startTime == 0 && endTime > lastUpdateTs) || - (startTime < lastUpdateTs && endTime > lastUpdateTs); + (startTime == 0 && endTime > lastUpdateTs) + ? true : startTime < lastUpdateTs && endTime > lastUpdateTs; }).collect(Collectors.toList()); } try { From d32a36c312611e48a762821f9551eb8d186f4a45 Mon Sep 17 00:00:00 2001 From: viktorbasanets Date: Fri, 28 Sep 2018 20:11:45 +0300 Subject: [PATCH 7/7] added test --- .../BaseEntityViewControllerTest.java | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index a877cbf71a..ee97b97fa0 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -50,6 +50,7 @@ import java.util.Set; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @@ -329,9 +330,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Thread.sleep(1000); EntityView savedView = getNewSavedEntityView("Test entity view"); - String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet); - List> values = doGetAsync(urlOfTelemetryValues, List.class); + List> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); assertEquals("value1", getValue(values, "caValue1")); assertEquals(true, getValue(values, "caValue2")); @@ -348,7 +348,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet)); Thread.sleep(1000); - List> values = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + + List> valueTelemetryOfDevices = doGetAsync("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); EntityView view = new EntityView(); @@ -356,19 +356,13 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes view.setTenantId(savedTenant.getId()); view.setName("Test entity view"); view.setKeys(telemetry); - view.setStartTimeMs((long) getValue(values, "lastUpdateTs") * 10); - view.setEndTimeMs((long) getValue(values, "lastUpdateTs") / 10); + view.setStartTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") * 10); + view.setEndTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") / 10); EntityView savedView = doPost("/api/entityView", view, EntityView.class); - String urlOfTelemetryValues = "/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + - "/values/attributes?keys=" + String.join(",", actualAttributesSet); - values = doGetAsync(urlOfTelemetryValues, List.class); - - - assertEquals("value1", getValue(values, "caValue1")); - assertEquals(true, getValue(values, "caValue2")); - assertEquals(42.0, getValue(values, "caValue3")); - assertEquals(73, getValue(values, "caValue4")); + List> values = doGetAsync("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + + "/values/attributes?keys=" + String.join(",", actualAttributesSet), List.class); + assertEquals(0, values.size()); } private Set getAttributesByKeys(String stringKV) throws Exception { @@ -396,15 +390,11 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes return new HashSet<>(doGetAsync("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", List.class)); } - /*private Object getLastTs(List> values) { - return values.stream() - .filter(value -> value.get("key"); - } -*/ private Object getValue(List> values, String stringValue) { - return values.stream() - .filter(value -> value.get("key").equals(stringValue)) - .findFirst().get().get("value"); + return values.size() == 0 ? null : + values.stream() + .filter(value -> value.get("key").equals(stringValue)) + .findFirst().get().get("value"); } private EntityView getNewSavedEntityView(String name) throws Exception {