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 48 import org.thingsboard.server.dao.audit.AuditLogService;
49 49 import org.thingsboard.server.dao.customer.CustomerService;
50 50 import org.thingsboard.server.dao.device.DeviceService;
  51 +import org.thingsboard.server.dao.entityview.EntityViewService;
51 52 import org.thingsboard.server.dao.event.EventService;
52 53 import org.thingsboard.server.dao.relation.RelationService;
53 54 import org.thingsboard.server.dao.rule.RuleChainService;
... ... @@ -161,6 +162,10 @@ public class ActorSystemContext {
161 162
162 163 @Autowired
163 164 @Getter
  165 + private EntityViewService entityViewService;
  166 +
  167 + @Autowired
  168 + @Getter
164 169 private TelemetrySubscriptionService tsSubService;
165 170
166 171 @Autowired
... ...
... ... @@ -41,6 +41,7 @@ import org.thingsboard.server.dao.asset.AssetService;
41 41 import org.thingsboard.server.dao.attributes.AttributesService;
42 42 import org.thingsboard.server.dao.customer.CustomerService;
43 43 import org.thingsboard.server.dao.device.DeviceService;
  44 +import org.thingsboard.server.dao.entityview.EntityViewService;
44 45 import org.thingsboard.server.dao.relation.RelationService;
45 46 import org.thingsboard.server.dao.rule.RuleChainService;
46 47 import org.thingsboard.server.dao.tenant.TenantService;
... ... @@ -213,6 +214,11 @@ class DefaultTbContext implements TbContext {
213 214 }
214 215
215 216 @Override
  217 + public EntityViewService getEntityViewService() {
  218 + return mainCtx.getEntityViewService();
  219 + }
  220 +
  221 + @Override
216 222 public MailService getMailService() {
217 223 if (mainCtx.isAllowSystemMailService()) {
218 224 return mainCtx.getMailService();
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.entityview;
17 17
18 18 import com.datastax.driver.core.Statement;
19 19 import com.datastax.driver.core.querybuilder.Select;
  20 +import com.google.common.util.concurrent.ListenableFuture;
20 21 import lombok.extern.slf4j.Slf4j;
21 22 import org.springframework.stereotype.Component;
22 23 import org.thingsboard.server.common.data.EntitySubtype;
... ... @@ -105,4 +106,10 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao<Entit
105 106 public List<EntityView> findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) {
106 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 15 */
16 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 20 import org.thingsboard.server.common.data.EntityView;
19 21 import org.thingsboard.server.common.data.page.TextPageLink;
20 22 import org.thingsboard.server.dao.Dao;
... ... @@ -91,4 +93,6 @@ public interface EntityViewDao extends Dao<EntityView> {
91 93 UUID customerId,
92 94 UUID entityId,
93 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 20 import org.thingsboard.server.common.data.EntitySubtype;
21 21 import org.thingsboard.server.common.data.EntityType;
22 22 import org.thingsboard.server.common.data.EntityView;
  23 +import org.thingsboard.server.common.data.Tenant;
23 24 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
24 25 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
25 26 import org.thingsboard.server.common.data.id.*;
... ... @@ -65,4 +66,6 @@ public interface EntityViewService {
65 66 ListenableFuture<EntityView> findEntityViewByIdAsync(EntityViewId entityViewId);
66 67
67 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 25 import org.springframework.stereotype.Service;
26 26 import org.thingsboard.server.common.data.Customer;
27 27 import org.thingsboard.server.common.data.DataConstants;
  28 +import org.thingsboard.server.common.data.Device;
28 29 import org.thingsboard.server.common.data.EntityType;
29 30 import org.thingsboard.server.common.data.EntityView;
30 31 import org.thingsboard.server.common.data.Tenant;
31 32 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
32 33 import org.thingsboard.server.common.data.id.CustomerId;
  34 +import org.thingsboard.server.common.data.id.DeviceId;
33 35 import org.thingsboard.server.common.data.id.EntityId;
34 36 import org.thingsboard.server.common.data.id.EntityViewId;
35 37 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -52,8 +54,10 @@ import java.util.Collection;
52 54 import java.util.List;
53 55 import java.util.stream.Collectors;
54 56
  57 +import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
55 58 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
56 59 import static org.thingsboard.server.dao.service.Validator.validateId;
  60 +import static org.thingsboard.server.dao.service.Validator.validateIds;
57 61 import static org.thingsboard.server.dao.service.Validator.validatePageLink;
58 62 import static org.thingsboard.server.dao.service.Validator.validateString;
59 63
... ... @@ -277,6 +281,14 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
277 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 292 private DataValidator<EntityView> entityViewValidator =
281 293 new DataValidator<EntityView>() {
282 294
... ...
... ... @@ -19,6 +19,7 @@ import org.springframework.data.domain.Pageable;
19 19 import org.springframework.data.jpa.repository.Query;
20 20 import org.springframework.data.repository.CrudRepository;
21 21 import org.springframework.data.repository.query.Param;
  22 +import org.thingsboard.server.common.data.EntityView;
22 23 import org.thingsboard.server.common.data.id.EntityId;
23 24 import org.thingsboard.server.dao.model.sql.EntityViewEntity;
24 25 import org.thingsboard.server.dao.util.SqlDao;
... ... @@ -78,4 +79,6 @@ public interface EntityViewRepository extends CrudRepository<EntityViewEntity, S
78 79 List<String> entityViewsIds);
79 80
80 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 23 import org.thingsboard.server.common.data.EntitySubtype;
24 24 import org.thingsboard.server.common.data.EntityType;
25 25 import org.thingsboard.server.common.data.EntityView;
  26 +import org.thingsboard.server.common.data.UUIDConverter;
26 27 import org.thingsboard.server.common.data.id.EntityId;
27 28 import org.thingsboard.server.common.data.id.TenantId;
28 29 import org.thingsboard.server.common.data.page.TextPageLink;
... ... @@ -40,6 +41,7 @@ import java.util.Optional;
40 41 import java.util.UUID;
41 42
42 43 import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
  44 +import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUIDs;
43 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 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 26 import org.thingsboard.server.dao.attributes.AttributesService;
27 27 import org.thingsboard.server.dao.customer.CustomerService;
28 28 import org.thingsboard.server.dao.device.DeviceService;
  29 +import org.thingsboard.server.dao.entityview.EntityViewService;
29 30 import org.thingsboard.server.dao.relation.RelationService;
30 31 import org.thingsboard.server.dao.rule.RuleChainService;
31 32 import org.thingsboard.server.dao.tenant.TenantService;
... ... @@ -83,6 +84,8 @@ public interface TbContext {
83 84
84 85 RelationService getRelationService();
85 86
  87 + EntityViewService getEntityViewService();
  88 +
86 89 ListeningExecutor getJsExecutor();
87 90
88 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 +}
... ...