Commit 020b7a4ec68a8e4006d78697cbb81480989209c9
1 parent
8f72adfb
Added copy attributes to entity view rule node
Showing
10 changed files
with
173 additions
and
0 deletions
... | ... | @@ -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 | +} | ... | ... |