Commit 020b7a4ec68a8e4006d78697cbb81480989209c9

Authored by Volodymyr Babak
1 parent 8f72adfb

Added copy attributes to entity view rule node

@@ -48,6 +48,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; @@ -48,6 +48,7 @@ import org.thingsboard.server.dao.attributes.AttributesService;
48 import org.thingsboard.server.dao.audit.AuditLogService; 48 import org.thingsboard.server.dao.audit.AuditLogService;
49 import org.thingsboard.server.dao.customer.CustomerService; 49 import org.thingsboard.server.dao.customer.CustomerService;
50 import org.thingsboard.server.dao.device.DeviceService; 50 import org.thingsboard.server.dao.device.DeviceService;
  51 +import org.thingsboard.server.dao.entityview.EntityViewService;
51 import org.thingsboard.server.dao.event.EventService; 52 import org.thingsboard.server.dao.event.EventService;
52 import org.thingsboard.server.dao.relation.RelationService; 53 import org.thingsboard.server.dao.relation.RelationService;
53 import org.thingsboard.server.dao.rule.RuleChainService; 54 import org.thingsboard.server.dao.rule.RuleChainService;
@@ -161,6 +162,10 @@ public class ActorSystemContext { @@ -161,6 +162,10 @@ public class ActorSystemContext {
161 162
162 @Autowired 163 @Autowired
163 @Getter 164 @Getter
  165 + private EntityViewService entityViewService;
  166 +
  167 + @Autowired
  168 + @Getter
164 private TelemetrySubscriptionService tsSubService; 169 private TelemetrySubscriptionService tsSubService;
165 170
166 @Autowired 171 @Autowired
@@ -41,6 +41,7 @@ import org.thingsboard.server.dao.asset.AssetService; @@ -41,6 +41,7 @@ import org.thingsboard.server.dao.asset.AssetService;
41 import org.thingsboard.server.dao.attributes.AttributesService; 41 import org.thingsboard.server.dao.attributes.AttributesService;
42 import org.thingsboard.server.dao.customer.CustomerService; 42 import org.thingsboard.server.dao.customer.CustomerService;
43 import org.thingsboard.server.dao.device.DeviceService; 43 import org.thingsboard.server.dao.device.DeviceService;
  44 +import org.thingsboard.server.dao.entityview.EntityViewService;
44 import org.thingsboard.server.dao.relation.RelationService; 45 import org.thingsboard.server.dao.relation.RelationService;
45 import org.thingsboard.server.dao.rule.RuleChainService; 46 import org.thingsboard.server.dao.rule.RuleChainService;
46 import org.thingsboard.server.dao.tenant.TenantService; 47 import org.thingsboard.server.dao.tenant.TenantService;
@@ -213,6 +214,11 @@ class DefaultTbContext implements TbContext { @@ -213,6 +214,11 @@ class DefaultTbContext implements TbContext {
213 } 214 }
214 215
215 @Override 216 @Override
  217 + public EntityViewService getEntityViewService() {
  218 + return mainCtx.getEntityViewService();
  219 + }
  220 +
  221 + @Override
216 public MailService getMailService() { 222 public MailService getMailService() {
217 if (mainCtx.isAllowSystemMailService()) { 223 if (mainCtx.isAllowSystemMailService()) {
218 return mainCtx.getMailService(); 224 return mainCtx.getMailService();
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.entityview; @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.entityview;
17 17
18 import com.datastax.driver.core.Statement; 18 import com.datastax.driver.core.Statement;
19 import com.datastax.driver.core.querybuilder.Select; 19 import com.datastax.driver.core.querybuilder.Select;
  20 +import com.google.common.util.concurrent.ListenableFuture;
20 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.stereotype.Component; 22 import org.springframework.stereotype.Component;
22 import org.thingsboard.server.common.data.EntitySubtype; 23 import org.thingsboard.server.common.data.EntitySubtype;
@@ -105,4 +106,10 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit @@ -105,4 +106,10 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
105 public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) { 106 public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) {
106 return null; 107 return null;
107 } 108 }
  109 +
  110 + @Override
  111 + public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) {
  112 + // TODO: implement this
  113 + return null;
  114 + }
108 } 115 }
@@ -15,6 +15,8 @@ @@ -15,6 +15,8 @@
15 */ 15 */
16 package org.thingsboard.server.dao.entityview; 16 package org.thingsboard.server.dao.entityview;
17 17
  18 +import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.Device;
18 import org.thingsboard.server.common.data.EntityView; 20 import org.thingsboard.server.common.data.EntityView;
19 import org.thingsboard.server.common.data.page.TextPageLink; 21 import org.thingsboard.server.common.data.page.TextPageLink;
20 import org.thingsboard.server.dao.Dao; 22 import org.thingsboard.server.dao.Dao;
@@ -91,4 +93,6 @@ public interface EntityViewDao extends Dao<EntityView> { @@ -91,4 +93,6 @@ public interface EntityViewDao extends Dao<EntityView> {
91 UUID customerId, 93 UUID customerId,
92 UUID entityId, 94 UUID entityId,
93 TextPageLink pageLink); 95 TextPageLink pageLink);
  96 +
  97 + ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId);
94 } 98 }
@@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.Device; @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.Device;
20 import org.thingsboard.server.common.data.EntitySubtype; 20 import org.thingsboard.server.common.data.EntitySubtype;
21 import org.thingsboard.server.common.data.EntityType; 21 import org.thingsboard.server.common.data.EntityType;
22 import org.thingsboard.server.common.data.EntityView; 22 import org.thingsboard.server.common.data.EntityView;
  23 +import org.thingsboard.server.common.data.Tenant;
23 import org.thingsboard.server.common.data.device.DeviceSearchQuery; 24 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
24 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; 25 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
25 import org.thingsboard.server.common.data.id.*; 26 import org.thingsboard.server.common.data.id.*;
@@ -65,4 +66,6 @@ public interface EntityViewService { @@ -65,4 +66,6 @@ public interface EntityViewService {
65 ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId); 66 ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId);
66 67
67 ListenableFuture<List<EntityView>> findEntityViewsByQuery(EntityViewSearchQuery query); 68 ListenableFuture<List<EntityView>> findEntityViewsByQuery(EntityViewSearchQuery query);
  69 +
  70 + ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId);
68 } 71 }
@@ -25,11 +25,13 @@ import org.springframework.cache.CacheManager; @@ -25,11 +25,13 @@ import org.springframework.cache.CacheManager;
25 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
26 import org.thingsboard.server.common.data.Customer; 26 import org.thingsboard.server.common.data.Customer;
27 import org.thingsboard.server.common.data.DataConstants; 27 import org.thingsboard.server.common.data.DataConstants;
  28 +import org.thingsboard.server.common.data.Device;
28 import org.thingsboard.server.common.data.EntityType; 29 import org.thingsboard.server.common.data.EntityType;
29 import org.thingsboard.server.common.data.EntityView; 30 import org.thingsboard.server.common.data.EntityView;
30 import org.thingsboard.server.common.data.Tenant; 31 import org.thingsboard.server.common.data.Tenant;
31 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; 32 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
32 import org.thingsboard.server.common.data.id.CustomerId; 33 import org.thingsboard.server.common.data.id.CustomerId;
  34 +import org.thingsboard.server.common.data.id.DeviceId;
33 import org.thingsboard.server.common.data.id.EntityId; 35 import org.thingsboard.server.common.data.id.EntityId;
34 import org.thingsboard.server.common.data.id.EntityViewId; 36 import org.thingsboard.server.common.data.id.EntityViewId;
35 import org.thingsboard.server.common.data.id.TenantId; 37 import org.thingsboard.server.common.data.id.TenantId;
@@ -52,8 +54,10 @@ import java.util.Collection; @@ -52,8 +54,10 @@ import java.util.Collection;
52 import java.util.List; 54 import java.util.List;
53 import java.util.stream.Collectors; 55 import java.util.stream.Collectors;
54 56
  57 +import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
55 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; 58 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
56 import static org.thingsboard.server.dao.service.Validator.validateId; 59 import static org.thingsboard.server.dao.service.Validator.validateId;
  60 +import static org.thingsboard.server.dao.service.Validator.validateIds;
57 import static org.thingsboard.server.dao.service.Validator.validatePageLink; 61 import static org.thingsboard.server.dao.service.Validator.validatePageLink;
58 import static org.thingsboard.server.dao.service.Validator.validateString; 62 import static org.thingsboard.server.dao.service.Validator.validateString;
59 63
@@ -277,6 +281,14 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti @@ -277,6 +281,14 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
277 return entityViews; 281 return entityViews;
278 } 282 }
279 283
  284 + @Override
  285 + public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) {
  286 + log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId);
  287 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  288 + validateId(entityId.getId(), "Incorrect entityId" + entityId);
  289 + return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId());
  290 + }
  291 +
280 private DataValidator<EntityView> entityViewValidator = 292 private DataValidator<EntityView> entityViewValidator =
281 new DataValidator<EntityView>() { 293 new DataValidator<EntityView>() {
282 294
@@ -19,6 +19,7 @@ import org.springframework.data.domain.Pageable; @@ -19,6 +19,7 @@ import org.springframework.data.domain.Pageable;
19 import org.springframework.data.jpa.repository.Query; 19 import org.springframework.data.jpa.repository.Query;
20 import org.springframework.data.repository.CrudRepository; 20 import org.springframework.data.repository.CrudRepository;
21 import org.springframework.data.repository.query.Param; 21 import org.springframework.data.repository.query.Param;
  22 +import org.thingsboard.server.common.data.EntityView;
22 import org.thingsboard.server.common.data.id.EntityId; 23 import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.dao.model.sql.EntityViewEntity; 24 import org.thingsboard.server.dao.model.sql.EntityViewEntity;
24 import org.thingsboard.server.dao.util.SqlDao; 25 import org.thingsboard.server.dao.util.SqlDao;
@@ -78,4 +79,6 @@ public interface EntityViewRepository extends CrudRepository<EntityViewEntity, S @@ -78,4 +79,6 @@ public interface EntityViewRepository extends CrudRepository<EntityViewEntity, S
78 List<String> entityViewsIds); 79 List<String> entityViewsIds);
79 80
80 List<EntityViewEntity> findAllByTenantIdAndIdIn(String tenantId, List<String> entityViewsIds); 81 List<EntityViewEntity> findAllByTenantIdAndIdIn(String tenantId, List<String> entityViewsIds);
  82 +
  83 + List<EntityViewEntity> findAllByTenantIdAndEntityId(String tenantId, String entityId);
81 } 84 }
@@ -23,6 +23,7 @@ import org.springframework.stereotype.Component; @@ -23,6 +23,7 @@ import org.springframework.stereotype.Component;
23 import org.thingsboard.server.common.data.EntitySubtype; 23 import org.thingsboard.server.common.data.EntitySubtype;
24 import org.thingsboard.server.common.data.EntityType; 24 import org.thingsboard.server.common.data.EntityType;
25 import org.thingsboard.server.common.data.EntityView; 25 import org.thingsboard.server.common.data.EntityView;
  26 +import org.thingsboard.server.common.data.UUIDConverter;
26 import org.thingsboard.server.common.data.id.EntityId; 27 import org.thingsboard.server.common.data.id.EntityId;
27 import org.thingsboard.server.common.data.id.TenantId; 28 import org.thingsboard.server.common.data.id.TenantId;
28 import org.thingsboard.server.common.data.page.TextPageLink; 29 import org.thingsboard.server.common.data.page.TextPageLink;
@@ -40,6 +41,7 @@ import java.util.Optional; @@ -40,6 +41,7 @@ import java.util.Optional;
40 import java.util.UUID; 41 import java.util.UUID;
41 42
42 import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; 43 import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
  44 +import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUIDs;
43 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; 45 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR;
44 46
45 /** 47 /**
@@ -121,4 +123,10 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity, @@ -121,4 +123,10 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao<EntityViewEntity,
121 new PageRequest(0, pageLink.getLimit()) 123 new PageRequest(0, pageLink.getLimit())
122 )); 124 ));
123 } 125 }
  126 +
  127 + @Override
  128 + public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) {
  129 + return service.submit(() -> DaoUtil.convertDataList(
  130 + entityViewRepository.findAllByTenantIdAndEntityId(UUIDConverter.fromTimeUUID(tenantId), UUIDConverter.fromTimeUUID(entityId))));
  131 + }
124 } 132 }
@@ -26,6 +26,7 @@ import org.thingsboard.server.dao.asset.AssetService; @@ -26,6 +26,7 @@ import org.thingsboard.server.dao.asset.AssetService;
26 import org.thingsboard.server.dao.attributes.AttributesService; 26 import org.thingsboard.server.dao.attributes.AttributesService;
27 import org.thingsboard.server.dao.customer.CustomerService; 27 import org.thingsboard.server.dao.customer.CustomerService;
28 import org.thingsboard.server.dao.device.DeviceService; 28 import org.thingsboard.server.dao.device.DeviceService;
  29 +import org.thingsboard.server.dao.entityview.EntityViewService;
29 import org.thingsboard.server.dao.relation.RelationService; 30 import org.thingsboard.server.dao.relation.RelationService;
30 import org.thingsboard.server.dao.rule.RuleChainService; 31 import org.thingsboard.server.dao.rule.RuleChainService;
31 import org.thingsboard.server.dao.tenant.TenantService; 32 import org.thingsboard.server.dao.tenant.TenantService;
@@ -83,6 +84,8 @@ public interface TbContext { @@ -83,6 +84,8 @@ public interface TbContext {
83 84
84 RelationService getRelationService(); 85 RelationService getRelationService();
85 86
  87 + EntityViewService getEntityViewService();
  88 +
86 ListeningExecutor getJsExecutor(); 89 ListeningExecutor getJsExecutor();
87 90
88 ListeningExecutor getMailExecutor(); 91 ListeningExecutor getMailExecutor();
  1 +package org.thingsboard.rule.engine.action;
  2 +
  3 +import com.fasterxml.jackson.databind.ObjectMapper;
  4 +import com.google.common.base.Function;
  5 +import com.google.common.util.concurrent.Futures;
  6 +import com.google.common.util.concurrent.ListenableFuture;
  7 +import com.google.gson.JsonParser;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
  10 +import org.thingsboard.rule.engine.api.RuleNode;
  11 +import org.thingsboard.rule.engine.api.TbContext;
  12 +import org.thingsboard.rule.engine.api.TbNode;
  13 +import org.thingsboard.rule.engine.api.TbNodeConfiguration;
  14 +import org.thingsboard.rule.engine.api.TbNodeException;
  15 +import org.thingsboard.rule.engine.api.TbRelationTypes;
  16 +import org.thingsboard.rule.engine.api.util.TbNodeUtils;
  17 +import org.thingsboard.server.common.data.DataConstants;
  18 +import org.thingsboard.server.common.data.EntityView;
  19 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  20 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  21 +import org.thingsboard.server.common.data.plugin.ComponentType;
  22 +import org.thingsboard.server.common.msg.TbMsg;
  23 +import org.thingsboard.server.common.msg.session.SessionMsgType;
  24 +import org.thingsboard.server.common.transport.adaptor.JsonConverter;
  25 +
  26 +import javax.annotation.Nullable;
  27 +import java.util.ArrayList;
  28 +import java.util.List;
  29 +import java.util.Set;
  30 +import java.util.concurrent.ExecutionException;
  31 +import java.util.stream.Collectors;
  32 +
  33 +import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
  34 +
  35 +@Slf4j
  36 +@RuleNode(
  37 + type = ComponentType.ACTION,
  38 + name = "copy attributes",
  39 + configClazz = EmptyNodeConfiguration.class,
  40 + nodeDescription = "Copy attributes from asset/device to entity view",
  41 + nodeDetails = "Copy attributes from asset/device to related entity view according to entity view configuration. \n " +
  42 + "Copy will be done only for attributes that are between start and end dates and according to attribute keys configuration",
  43 + uiResources = {"static/rulenode/rulenode-core-config.js"},
  44 + configDirective = "tbNodeEmptyConfig",
  45 + icon = "content_copy"
  46 +)
  47 +public class TbCopyAttributesToEntityViewNode implements TbNode {
  48 +
  49 + EmptyNodeConfiguration config;
  50 +
  51 + @Override
  52 + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
  53 + this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
  54 + }
  55 +
  56 + @Override
  57 + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
  58 + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
  59 + msg.getType().equals(DataConstants.ATTRIBUTES_DELETED) ||
  60 + msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) {
  61 + long now = System.currentTimeMillis();
  62 + String scope;
  63 + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) {
  64 + scope = DataConstants.CLIENT_SCOPE;
  65 + } else {
  66 + scope = msg.getMetaData().getValue("scope");
  67 + }
  68 + ListenableFuture<List<EntityView>> entityViewsFuture =
  69 + ctx.getEntityViewService().findEntityViewsByTenantIdAndEntityIdAsync(ctx.getTenantId(), msg.getOriginator());
  70 + withCallback(entityViewsFuture,
  71 + entityViews -> {
  72 + List<ListenableFuture<List<Void>>> saveFutures = new ArrayList<>();
  73 + for (EntityView entityView : entityViews) {
  74 + if ((entityView.getEndTimeMs() != 0 && entityView.getEndTimeMs() > now && entityView.getStartTimeMs() < now) ||
  75 + (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < now)) {
  76 + Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes();
  77 + List<AttributeKvEntry> filteredAttributes =
  78 + attributes.stream()
  79 + .filter(attr -> {
  80 + switch (scope) {
  81 + case DataConstants.CLIENT_SCOPE:
  82 + if (entityView.getKeys().getAttributes().getCs().isEmpty()) {
  83 + return true;
  84 + }
  85 + return entityView.getKeys().getAttributes().getCs().contains(attr.getKey());
  86 + case DataConstants.SERVER_SCOPE:
  87 + if (entityView.getKeys().getAttributes().getSs().isEmpty()) {
  88 + return true;
  89 + }
  90 + return entityView.getKeys().getAttributes().getSs().contains(attr.getKey());
  91 + case DataConstants.SHARED_SCOPE:
  92 + if (entityView.getKeys().getAttributes().getSh().isEmpty()) {
  93 + return true;
  94 + }
  95 + return entityView.getKeys().getAttributes().getSh().contains(attr.getKey());
  96 + }
  97 + return false;
  98 + })
  99 + .collect(Collectors.toList());
  100 + saveFutures.add(ctx.getAttributesService().save(entityView.getId(), scope, new ArrayList<>(filteredAttributes)));
  101 + }
  102 + }
  103 + Futures.transform(Futures.allAsList(saveFutures), new Function<List<List<Void>>, Object>() {
  104 + @Nullable
  105 + @Override
  106 + public Object apply(@Nullable List<List<Void>> lists) {
  107 + ctx.tellNext(msg, TbRelationTypes.SUCCESS);
  108 + return null;
  109 + }
  110 + });
  111 + },
  112 + t -> ctx.tellFailure(msg, t));
  113 + } else {
  114 + ctx.tellNext(msg, TbRelationTypes.FAILURE);
  115 + }
  116 + }
  117 +
  118 + @Override
  119 + public void destroy() {
  120 +
  121 + }
  122 +}