From 8f72adfb1d08c03558d8e2a56b2e88fa3fab1e9c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 13 Sep 2018 14:08:55 +0300 Subject: [PATCH 1/3] Fixes for time picker --- .../entity-view/entity-view-fieldset.tpl.html | 8 ++++---- .../app/entity-view/entity-view.directive.js | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html index b9808e9cea..3894eb9d63 100644 --- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html +++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html @@ -98,19 +98,19 @@
diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js index 42b3a120fe..e1ae82fa6a 100644 --- a/ui/src/app/entity-view/entity-view.directive.js +++ b/ui/src/app/entity-view/entity-view.directive.js @@ -54,8 +54,8 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t if (scope.entityView.startTimeMs > 0) { scope.startTimeMs = new Date(scope.entityView.startTimeMs); } - if (scope.entityView.endTimeTs > 0) { - scope.endTimeTs = new Date(scope.entityView.endTimeTs); + if (scope.entityView.endTimeMs > 0) { + scope.endTimeMs = new Date(scope.entityView.endTimeMs); } if (!scope.entityView.keys) { scope.entityView.keys = {}; @@ -78,22 +78,22 @@ export default function EntityViewDirective($compile, $templateCache, $filter, t } }); - scope.$watch('endTimeTs', function (newDate) { + scope.$watch('endTimeMs', function (newDate) { if (newDate) { - if (newDate.getTime() < scope.minEndTimeTs) { - scope.endTimeTs = angular.copy(scope.minEndTimeTs); + if (newDate.getTime() < scope.minEndTimeMs) { + scope.endTimeMs = angular.copy(scope.minEndTimeMs); } updateMinMaxDates(); } }); function updateMinMaxDates() { - if (scope.endTimeTs) { - scope.maxStartTimeMs = angular.copy(new Date(scope.endTimeTs.getTime())); - scope.entityView.endTimeTs = scope.endTimeTs.getTime(); + if (scope.endTimeMs) { + scope.maxStartTimeMs = angular.copy(new Date(scope.endTimeMs.getTime())); + scope.entityView.endTimeMs = scope.endTimeMs.getTime(); } if (scope.startTimeMs) { - scope.minEndTimeTs = angular.copy(new Date(scope.startTimeMs.getTime())); + scope.minEndTimeMs = angular.copy(new Date(scope.startTimeMs.getTime())); scope.entityView.startTimeMs = scope.startTimeMs.getTime(); } } From 020b7a4ec68a8e4006d78697cbb81480989209c9 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 14 Sep 2018 14:04:12 +0300 Subject: [PATCH 2/3] Added copy attributes to entity view rule node --- .../server/actors/ActorSystemContext.java | 5 + .../actors/ruleChain/DefaultTbContext.java | 6 + .../entityview/CassandraEntityViewDao.java | 7 + .../server/dao/entityview/EntityViewDao.java | 4 + .../dao/entityview/EntityViewService.java | 3 + .../dao/entityview/EntityViewServiceImpl.java | 12 ++ .../sql/entityview/EntityViewRepository.java | 3 + .../dao/sql/entityview/JpaEntityViewDao.java | 8 ++ .../rule/engine/api/TbContext.java | 3 + .../TbCopyAttributesToEntityViewNode.java | 122 ++++++++++++++++++ 10 files changed, 173 insertions(+) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index d33734e14c..e3682dec8c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -48,6 +48,7 @@ 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.device.DeviceService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.event.EventService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; @@ -159,6 +160,10 @@ public class ActorSystemContext { @Getter private AuditLogService auditLogService; + @Autowired + @Getter + private EntityViewService entityViewService; + @Autowired @Getter private TelemetrySubscriptionService tsSubService; diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index 7279347b1c..acfc269fd5 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -41,6 +41,7 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; @@ -212,6 +213,11 @@ class DefaultTbContext implements TbContext { return mainCtx.getRelationService(); } + @Override + public EntityViewService getEntityViewService() { + return mainCtx.getEntityViewService(); + } + @Override public MailService getMailService() { if (mainCtx.isAllowSystemMailService()) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java index 5716460d20..5de34e4b71 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/CassandraEntityViewDao.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.entityview; import com.datastax.driver.core.Statement; import com.datastax.driver.core.querybuilder.Select; +import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EntitySubtype; @@ -105,4 +106,10 @@ public class CassandraEntityViewDao extends CassandraAbstractSearchTextDao findEntityViewsByTenantIdAndCustomerIdAndEntityId(UUID tenantId, UUID customerId, UUID entityId, TextPageLink pageLink) { return null; } + + @Override + public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { + // TODO: implement this + return null; + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java index 56a688ae47..be643ef363 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewDao.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.dao.entityview; +import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.dao.Dao; @@ -91,4 +93,6 @@ public interface EntityViewDao extends Dao { UUID customerId, UUID entityId, TextPageLink pageLink); + + ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index a60376e501..b9c238a79a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.id.*; @@ -65,4 +66,6 @@ public interface EntityViewService { ListenableFuture findEntityViewByIdAsync(EntityViewId entityViewId); ListenableFuture> findEntityViewsByQuery(EntityViewSearchQuery query); + + ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId); } 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 d86eabb510..598897aac5 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 @@ -25,11 +25,13 @@ import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; 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; @@ -52,8 +54,10 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +import static org.thingsboard.server.dao.DaoUtil.toUUIDs; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.service.Validator.validateId; +import static org.thingsboard.server.dao.service.Validator.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; @@ -277,6 +281,14 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti return entityViews; } + @Override + public ListenableFuture> findEntityViewsByTenantIdAndEntityIdAsync(TenantId tenantId, EntityId entityId) { + log.trace("Executing findEntityViewsByTenantIdAndEntityIdAsync, tenantId [{}], entityId [{}]", tenantId, entityId); + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); + validateId(entityId.getId(), "Incorrect entityId" + entityId); + return entityViewDao.findEntityViewsByTenantIdAndEntityIdAsync(tenantId.getId(), entityId.getId()); + } + private DataValidator entityViewValidator = new DataValidator() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java index 27bd8395ac..f1ee3fd272 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java @@ -19,6 +19,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; +import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.dao.model.sql.EntityViewEntity; import org.thingsboard.server.dao.util.SqlDao; @@ -78,4 +79,6 @@ public interface EntityViewRepository extends CrudRepository entityViewsIds); List findAllByTenantIdAndIdIn(String tenantId, List entityViewsIds); + + List findAllByTenantIdAndEntityId(String tenantId, String entityId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index 2f3edbe250..4ff21ab892 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -23,6 +23,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.TextPageLink; @@ -40,6 +41,7 @@ import java.util.Optional; import java.util.UUID; import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID; +import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUIDs; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID_STR; /** @@ -121,4 +123,10 @@ public class JpaEntityViewDao extends JpaAbstractSearchTextDao> findEntityViewsByTenantIdAndEntityIdAsync(UUID tenantId, UUID entityId) { + return service.submit(() -> DaoUtil.convertDataList( + entityViewRepository.findAllByTenantIdAndEntityId(UUIDConverter.fromTimeUUID(tenantId), UUIDConverter.fromTimeUUID(entityId)))); + } } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index e7ef0dd40f..f9d3c64211 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -26,6 +26,7 @@ import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; @@ -83,6 +84,8 @@ public interface TbContext { RelationService getRelationService(); + EntityViewService getEntityViewService(); + ListeningExecutor getJsExecutor(); ListeningExecutor getMailExecutor(); 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 new file mode 100644 index 0000000000..73999afb97 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java @@ -0,0 +1,122 @@ +package org.thingsboard.rule.engine.action; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.gson.JsonParser; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.TbRelationTypes; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.DataConstants; +import org.thingsboard.server.common.data.EntityView; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.plugin.ComponentType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.session.SessionMsgType; +import org.thingsboard.server.common.transport.adaptor.JsonConverter; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; + +@Slf4j +@RuleNode( + type = ComponentType.ACTION, + name = "copy attributes", + configClazz = EmptyNodeConfiguration.class, + nodeDescription = "Copy attributes from asset/device to entity view", + nodeDetails = "Copy attributes from asset/device to related entity view according to entity view configuration. \n " + + "Copy will be done only for attributes that are between start and end dates and according to attribute keys configuration", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbNodeEmptyConfig", + icon = "content_copy" +) +public class TbCopyAttributesToEntityViewNode implements TbNode { + + EmptyNodeConfiguration config; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) || + msg.getType().equals(DataConstants.ATTRIBUTES_DELETED) || + msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) { + long now = System.currentTimeMillis(); + String scope; + if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) { + scope = DataConstants.CLIENT_SCOPE; + } else { + scope = msg.getMetaData().getValue("scope"); + } + ListenableFuture> entityViewsFuture = + ctx.getEntityViewService().findEntityViewsByTenantIdAndEntityIdAsync(ctx.getTenantId(), msg.getOriginator()); + withCallback(entityViewsFuture, + entityViews -> { + List>> saveFutures = new ArrayList<>(); + for (EntityView entityView : entityViews) { + if ((entityView.getEndTimeMs() != 0 && entityView.getEndTimeMs() > now && entityView.getStartTimeMs() < now) || + (entityView.getEndTimeMs() == 0 && entityView.getStartTimeMs() < now)) { + Set attributes = JsonConverter.convertToAttributes(new JsonParser().parse(msg.getData())).getAttributes(); + List filteredAttributes = + attributes.stream() + .filter(attr -> { + switch (scope) { + case DataConstants.CLIENT_SCOPE: + if (entityView.getKeys().getAttributes().getCs().isEmpty()) { + return true; + } + return entityView.getKeys().getAttributes().getCs().contains(attr.getKey()); + case DataConstants.SERVER_SCOPE: + if (entityView.getKeys().getAttributes().getSs().isEmpty()) { + return true; + } + return entityView.getKeys().getAttributes().getSs().contains(attr.getKey()); + case DataConstants.SHARED_SCOPE: + if (entityView.getKeys().getAttributes().getSh().isEmpty()) { + return true; + } + return entityView.getKeys().getAttributes().getSh().contains(attr.getKey()); + } + return false; + }) + .collect(Collectors.toList()); + saveFutures.add(ctx.getAttributesService().save(entityView.getId(), scope, new ArrayList<>(filteredAttributes))); + } + } + Futures.transform(Futures.allAsList(saveFutures), new Function>, Object>() { + @Nullable + @Override + public Object apply(@Nullable List> lists) { + ctx.tellNext(msg, TbRelationTypes.SUCCESS); + return null; + } + }); + }, + t -> ctx.tellFailure(msg, t)); + } else { + ctx.tellNext(msg, TbRelationTypes.FAILURE); + } + } + + @Override + public void destroy() { + + } +} From 3b0d7204bc93c17ef837f3be748710ad85dbc528 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 14 Sep 2018 14:05:29 +0300 Subject: [PATCH 3/3] Added copy attributes to entity view rule node --- .../action/TbCopyAttributesToEntityViewNode.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 73999afb97..d609620edf 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 @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2018 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.thingsboard.rule.engine.action; import com.fasterxml.jackson.databind.ObjectMapper;