From 8b1a9351f34717de9fc8f799fdee691a39ce9081 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 16 Oct 2018 16:26:01 +0300 Subject: [PATCH] Fixed for entity view afte testing --- .../server/controller/BaseController.java | 8 ++ .../controller/EntityViewController.java | 85 +++++++++++++++++++ .../controller/TelemetryController.java | 6 -- .../server/dao/entity/BaseEntityService.java | 7 ++ .../dao/entityview/EntityViewServiceImpl.java | 45 ---------- .../TbCopyAttributesToEntityViewNode.java | 16 +--- ui/src/app/api/entity-view.service.js | 27 ------ ui/src/app/api/entity.service.js | 4 + 8 files changed, 108 insertions(+), 90 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 889630b81f..154ed3adb2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -51,6 +51,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; @@ -70,6 +71,7 @@ import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.state.DeviceStateService; +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import javax.mail.MessagingException; import javax.servlet.http.HttpServletRequest; @@ -143,6 +145,12 @@ public abstract class BaseController { @Autowired protected EntityViewService entityViewService; + @Autowired + protected TelemetrySubscriptionService tsSubService; + + @Autowired + protected AttributesService attributesService; + @ExceptionHandler(ThingsboardException.class) public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { errorResponseHandler.handle(ex, response); 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 a1ba1c63f8..69e28db65a 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java @@ -15,7 +15,10 @@ */ package org.thingsboard.server.controller; +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; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; @@ -26,7 +29,9 @@ 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.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; @@ -34,15 +39,24 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.id.UUIDBased; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; +import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.service.security.model.SecurityUser; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; @@ -52,6 +66,7 @@ import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; */ @RestController @RequestMapping("/api") +@Slf4j public class EntityViewController extends BaseController { public static final String ENTITY_VIEW_ID = "entityViewId"; @@ -75,6 +90,20 @@ public class EntityViewController extends BaseController { try { entityView.setTenantId(getCurrentUser().getTenantId()); EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); + List>> futures = new ArrayList<>(); + if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) { + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), getCurrentUser())); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), getCurrentUser())); + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), getCurrentUser())); + } + for (ListenableFuture> future : futures) { + try { + future.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException("Failed to copy attributes to entity view", e); + } + } + logEntityAction(savedEntityView.getId(), savedEntityView, null, entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); return savedEntityView; @@ -85,6 +114,62 @@ public class EntityViewController extends BaseController { } } + private ListenableFuture> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys, SecurityUser user) throws ThingsboardException { + EntityViewId entityId = entityView.getId(); + if (keys != null && !keys.isEmpty()) { + ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); + return Futures.transform(getAttrFuture, attributeKvEntries -> { + List attributes; + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { + attributes = + attributeKvEntries.stream() + .filter(attributeKvEntry -> { + 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) + ? true : startTime < lastUpdateTs && endTime > lastUpdateTs; + }).collect(Collectors.toList()); + tsSubService.saveAndNotify(entityId, scope, attributes, new FutureCallback() { + @Override + public void onSuccess(@Nullable Void tmp) { + try { + logAttributesUpdated(user, entityId, scope, attributes, null); + } catch (ThingsboardException e) { + log.error("Failed to log attribute updates", e); + } + if (entityId.getEntityType() == EntityType.ENTITY_VIEW) { + DeviceId deviceId = new DeviceId(entityId.getId()); + DeviceAttributesEventNotificationMsg notificationMsg = DeviceAttributesEventNotificationMsg.onUpdate( + user.getTenantId(), deviceId, scope, attributes); + actorService.onMsg(new SendToClusterMsg(deviceId, notificationMsg)); + } + } + + @Override + public void onFailure(Throwable t) { + try { + logAttributesUpdated(user, entityId, scope, attributes, t); + } catch (ThingsboardException e) { + log.error("Failed to log attribute updates", e); + } + } + }); + } + return null; + }); + } else { + return Futures.immediateFuture(null); + } + } + + private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List attributes, Throwable e) throws ThingsboardException { + logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e), + scope, attributes); + } + @PreAuthorize("hasAuthority('TENANT_ADMIN')") @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE) @ResponseStatus(value = HttpStatus.OK) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index 7062ca97f9..9f92019550 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -93,15 +93,9 @@ import java.util.stream.Collectors; @Slf4j public class TelemetryController extends BaseController { - @Autowired - private AttributesService attributesService; - @Autowired private TimeseriesService tsService; - @Autowired - private TelemetrySubscriptionService tsSubService; - @Autowired private AccessValidator accessValidator; diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 1b67ca0486..33a26997ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserService; @@ -46,6 +47,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe @Autowired private DeviceService deviceService; + @Autowired + private EntityViewService entityViewService; + @Autowired private TenantService tenantService; @@ -81,6 +85,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe case DEVICE: hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId())); break; + case ENTITY_VIEW: + hasName = entityViewService.findEntityViewByIdAsync(new EntityViewId(entityId.getId())); + break; case TENANT: hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId())); break; 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 a44a4349a0..0cc6008ffb 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 @@ -105,21 +105,6 @@ 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 && savedEntityView.getKeys().getAttributes() != null) { - 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; } @@ -294,36 +279,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti }); } - private ListenableFuture> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection keys) { - if (keys != null && !keys.isEmpty()) { - ListenableFuture> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys); - return Futures.transform(getAttrFuture, attributeKvEntries -> { - List filteredAttributes = new ArrayList<>(); - if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) { - filteredAttributes = - attributeKvEntries.stream() - .filter(attributeKvEntry -> { - 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) - ? true : startTime < lastUpdateTs && endTime > lastUpdateTs; - }).collect(Collectors.toList()); - } - 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); - } - } - private DataValidator entityViewValidator = new DataValidator() { 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 1ab76059f7..fc0ff28749 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 @@ -116,8 +116,10 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { } List filteredAttributes = attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr, entityView)).collect(Collectors.toList()); - ctx.getAttributesService().removeAll(entityView.getId(), scope, filteredAttributes); - transformAndTellNext(ctx, msg, entityView); + if (filteredAttributes != null && !filteredAttributes.isEmpty()) { + ctx.getAttributesService().removeAll(entityView.getId(), scope, filteredAttributes); + transformAndTellNext(ctx, msg, entityView); + } } } } @@ -139,19 +141,10 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) { switch (scope) { case DataConstants.CLIENT_SCOPE: - if (entityView.getKeys().getAttributes().getCs().isEmpty()) { - return true; - } return entityView.getKeys().getAttributes().getCs().contains(attrKey); case DataConstants.SERVER_SCOPE: - if (entityView.getKeys().getAttributes().getSs().isEmpty()) { - return true; - } return entityView.getKeys().getAttributes().getSs().contains(attrKey); case DataConstants.SHARED_SCOPE: - if (entityView.getKeys().getAttributes().getSh().isEmpty()) { - return true; - } return entityView.getKeys().getAttributes().getSh().contains(attrKey); } return false; @@ -159,6 +152,5 @@ public class TbCopyAttributesToEntityViewNode implements TbNode { @Override public void destroy() { - } } diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js index e34d3a4aee..23fefbc05b 100644 --- a/ui/src/app/api/entity-view.service.js +++ b/ui/src/app/api/entity-view.service.js @@ -27,7 +27,6 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu deleteEntityView: deleteEntityView, getCustomerEntityViews: getCustomerEntityViews, getEntityView: getEntityView, - getEntityViews: getEntityViews, getTenantEntityViews: getTenantEntityViews, saveEntityView: saveEntityView, unassignEntityViewFromCustomer: unassignEntityViewFromCustomer, @@ -126,32 +125,6 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu return deferred.promise; } - function getEntityViews(entityViewIds, config) { - var deferred = $q.defer(); - var ids = ''; - for (var i=0;i0) { - ids += ','; - } - ids += entityViewIds[i]; - } - var url = '/api/entityViews?entityViewIds=' + ids; - $http.get(url, config).then(function success(response) { - var entityViews = response.data; - entityViews.sort(function (entityView1, entityView2) { - var id1 = entityView1.id.id; - var id2 = entityView2.id.id; - var index1 = entityViewIds.indexOf(id1); - var index2 = entityViewIds.indexOf(id2); - return index1 - index2; - }); - deferred.resolve(entityViews); - }, function fail(response) { - deferred.reject(response.data); - }); - return deferred.promise; - } - function saveEntityView(entityView) { var deferred = $q.defer(); var url = '/api/entityView'; diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js index 205abc9e4e..00c7ecf990 100644 --- a/ui/src/app/api/entity.service.js +++ b/ui/src/app/api/entity.service.js @@ -135,6 +135,10 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device case types.entityType.asset: promise = assetService.getAssets(entityIds, config); break; + case types.entityType.entityView: + promise = getEntitiesByIdsPromise( + (id) => entityViewService.getEntityView(id, config), entityIds); + break; case types.entityType.tenant: promise = getEntitiesByIdsPromise( (id) => tenantService.getTenant(id, config), entityIds);