Commit 06d59ed62afacd4dea7d6943bf2b37fe9e352d18

Authored by viktorbasanets
2 parents 5180961e 3b0d7204

Was added new 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 }
... ...
... ... @@ -279,6 +279,14 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
279 279 return entityViews;
280 280 }
281 281
  282 + @Override
  283 + public ListenableFuture<List<EntityView>> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) {
  284 + log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId);
  285 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  286 + validateId(entityId.getId(), "Incorrect entityId" + entityId);
  287 + return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId());
  288 + }
  289 +
282 290 private DataValidator<EntityView> entityViewValidator =
283 291 new DataValidator<EntityView>() {
284 292
... ...
... ... @@ -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 +/**
  2 + * Copyright © 2016-2018 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.action;
  17 +
  18 +import com.fasterxml.jackson.databind.ObjectMapper;
  19 +import com.google.common.base.Function;
  20 +import com.google.common.util.concurrent.Futures;
  21 +import com.google.common.util.concurrent.ListenableFuture;
  22 +import com.google.gson.JsonParser;
  23 +import lombok.extern.slf4j.Slf4j;
  24 +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
  25 +import org.thingsboard.rule.engine.api.RuleNode;
  26 +import org.thingsboard.rule.engine.api.TbContext;
  27 +import org.thingsboard.rule.engine.api.TbNode;
  28 +import org.thingsboard.rule.engine.api.TbNodeConfiguration;
  29 +import org.thingsboard.rule.engine.api.TbNodeException;
  30 +import org.thingsboard.rule.engine.api.TbRelationTypes;
  31 +import org.thingsboard.rule.engine.api.util.TbNodeUtils;
  32 +import org.thingsboard.server.common.data.DataConstants;
  33 +import org.thingsboard.server.common.data.EntityView;
  34 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
  35 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  36 +import org.thingsboard.server.common.data.plugin.ComponentType;
  37 +import org.thingsboard.server.common.msg.TbMsg;
  38 +import org.thingsboard.server.common.msg.session.SessionMsgType;
  39 +import org.thingsboard.server.common.transport.adaptor.JsonConverter;
  40 +
  41 +import javax.annotation.Nullable;
  42 +import java.util.ArrayList;
  43 +import java.util.List;
  44 +import java.util.Set;
  45 +import java.util.concurrent.ExecutionException;
  46 +import java.util.stream.Collectors;
  47 +
  48 +import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
  49 +
  50 +@Slf4j
  51 +@RuleNode(
  52 + type = ComponentType.ACTION,
  53 + name = "copy attributes",
  54 + configClazz = EmptyNodeConfiguration.class,
  55 + nodeDescription = "Copy attributes from asset/device to entity view",
  56 + nodeDetails = "Copy attributes from asset/device to related entity view according to entity view configuration. \n " +
  57 + "Copy will be done only for attributes that are between start and end dates and according to attribute keys configuration",
  58 + uiResources = {"static/rulenode/rulenode-core-config.js"},
  59 + configDirective = "tbNodeEmptyConfig",
  60 + icon = "content_copy"
  61 +)
  62 +public class TbCopyAttributesToEntityViewNode implements TbNode {
  63 +
  64 + EmptyNodeConfiguration config;
  65 +
  66 + @Override
  67 + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
  68 + this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
  69 + }
  70 +
  71 + @Override
  72 + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
  73 + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
  74 + msg.getType().equals(DataConstants.ATTRIBUTES_DELETED) ||
  75 + msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) {
  76 + long now = System.currentTimeMillis();
  77 + String scope;
  78 + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) {
  79 + scope = DataConstants.CLIENT_SCOPE;
  80 + } else {
  81 + scope = msg.getMetaData().getValue("scope");
  82 + }
  83 + ListenableFuture<List<EntityView>> entityViewsFuture =
  84 + ctx.getEntityViewService().findEntityViewsByTenantIdAndEntityIdAsync(ctx.getTenantId(), msg.getOriginator());
  85 + withCallback(entityViewsFuture,
  86 + entityViews -> {
  87 + List<ListenableFuture<List<Void>>> saveFutures = new ArrayList<>();
  88 + for (EntityView entityView : entityViews) {
  89 + if ((entityView.getEndTimeMs() != 0 && entityView.getEndTimeMs() > now && entityView.getStartTimeMs() < now) ||
  90 + (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < now)) {
  91 + Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes();
  92 + List<AttributeKvEntry> filteredAttributes =
  93 + attributes.stream()
  94 + .filter(attr -> {
  95 + switch (scope) {
  96 + case DataConstants.CLIENT_SCOPE:
  97 + if (entityView.getKeys().getAttributes().getCs().isEmpty()) {
  98 + return true;
  99 + }
  100 + return entityView.getKeys().getAttributes().getCs().contains(attr.getKey());
  101 + case DataConstants.SERVER_SCOPE:
  102 + if (entityView.getKeys().getAttributes().getSs().isEmpty()) {
  103 + return true;
  104 + }
  105 + return entityView.getKeys().getAttributes().getSs().contains(attr.getKey());
  106 + case DataConstants.SHARED_SCOPE:
  107 + if (entityView.getKeys().getAttributes().getSh().isEmpty()) {
  108 + return true;
  109 + }
  110 + return entityView.getKeys().getAttributes().getSh().contains(attr.getKey());
  111 + }
  112 + return false;
  113 + })
  114 + .collect(Collectors.toList());
  115 + saveFutures.add(ctx.getAttributesService().save(entityView.getId(), scope, new ArrayList<>(filteredAttributes)));
  116 + }
  117 + }
  118 + Futures.transform(Futures.allAsList(saveFutures), new Function<List<List<Void>>, Object>() {
  119 + @Nullable
  120 + @Override
  121 + public Object apply(@Nullable List<List<Void>> lists) {
  122 + ctx.tellNext(msg, TbRelationTypes.SUCCESS);
  123 + return null;
  124 + }
  125 + });
  126 + },
  127 + t -> ctx.tellFailure(msg, t));
  128 + } else {
  129 + ctx.tellNext(msg, TbRelationTypes.FAILURE);
  130 + }
  131 + }
  132 +
  133 + @Override
  134 + public void destroy() {
  135 +
  136 + }
  137 +}
... ...
... ... @@ -98,19 +98,19 @@
98 98 <section layout="column">
99 99 <section layout="row" layout-align="start start">
100 100 <mdp-date-picker ng-model="startTimeMs"
101   - mdp-max-date="maxStartTimeTs"
  101 + mdp-max-date="maxStartTimeMs"
102 102 mdp-placeholder="{{ 'entity-view.start-ts' | translate }}"></mdp-date-picker>
103 103 <mdp-time-picker ng-model="startTimeMs"
104   - mdp-max-date="maxStartTimeTs"
  104 + mdp-max-date="maxStartTimeMs"
105 105 mdp-placeholder="{{ 'entity-view.start-ts' | translate }}"
106 106 mdp-auto-switch="true"></mdp-time-picker>
107 107 </section>
108 108 <section layout="row" layout-align="start start">
109 109 <mdp-date-picker ng-model="endTimeMs"
110   - mdp-min-date="minEndTimeTs"
  110 + mdp-min-date="minEndTimeMs"
111 111 mdp-placeholder="{{ 'entity-view.end-ts' | translate }}"></mdp-date-picker>
112 112 <mdp-time-picker ng-model="endTimeMs"
113   - mdp-min-date="minEndTimeTs"
  113 + mdp-min-date="minEndTimeMs"
114 114 mdp-placeholder="{{ 'entity-view.end-ts' | translate }}"
115 115 mdp-auto-switch="true"></mdp-time-picker>
116 116 </section>
... ...
... ... @@ -54,8 +54,8 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t
54 54 if (scope.entityView.startTimeMs > 0) {
55 55 scope.startTimeMs = new Date(scope.entityView.startTimeMs);
56 56 }
57   - if (scope.entityView.endTimeTs > 0) {
58   - scope.endTimeTs = new Date(scope.entityView.endTimeTs);
  57 + if (scope.entityView.endTimeMs > 0) {
  58 + scope.endTimeMs = new Date(scope.entityView.endTimeMs);
59 59 }
60 60 if (!scope.entityView.keys) {
61 61 scope.entityView.keys = {};
... ... @@ -78,22 +78,22 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t
78 78 }
79 79 });
80 80
81   - scope.$watch('endTimeTs', function (newDate) {
  81 + scope.$watch('endTimeMs', function (newDate) {
82 82 if (newDate) {
83   - if (newDate.getTime() < scope.minEndTimeTs) {
84   - scope.endTimeTs = angular.copy(scope.minEndTimeTs);
  83 + if (newDate.getTime() < scope.minEndTimeMs) {
  84 + scope.endTimeMs = angular.copy(scope.minEndTimeMs);
85 85 }
86 86 updateMinMaxDates();
87 87 }
88 88 });
89 89
90 90 function updateMinMaxDates() {
91   - if (scope.endTimeTs) {
92   - scope.maxStartTimeMs = angular.copy(new Date(scope.endTimeTs.getTime()));
93   - scope.entityView.endTimeTs = scope.endTimeTs.getTime();
  91 + if (scope.endTimeMs) {
  92 + scope.maxStartTimeMs = angular.copy(new Date(scope.endTimeMs.getTime()));
  93 + scope.entityView.endTimeMs = scope.endTimeMs.getTime();
94 94 }
95 95 if (scope.startTimeMs) {
96   - scope.minEndTimeTs = angular.copy(new Date(scope.startTimeMs.getTime()));
  96 + scope.minEndTimeMs = angular.copy(new Date(scope.startTimeMs.getTime()));
97 97 scope.entityView.startTimeMs = scope.startTimeMs.getTime();
98 98 }
99 99 }
... ...