thingsboard-aplcache
Changes
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java 16(+4 -12)
ui/src/app/api/entity.service.js 4(+4 -0)
ui/src/app/api/entity-view.service.js 27(+0 -27)
Details
diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
index 889630b..154ed3a 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -51,6 +51,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService;
+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.dashboard.DashboardService;
@@ -70,6 +71,7 @@ import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.state.DeviceStateService;
+import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
@@ -143,6 +145,12 @@ public abstract class BaseController {
@Autowired
protected EntityViewService entityViewService;
+ @Autowired
+ protected TelemetrySubscriptionService tsSubService;
+
+ @Autowired
+ protected AttributesService attributesService;
+
@ExceptionHandler(ThingsboardException.class)
public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) {
errorResponseHandler.handle(ex, response);
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
index a1ba1c6..69e28db 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
@@ -15,7 +15,10 @@
*/
package org.thingsboard.server.controller;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@@ -26,7 +29,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
+import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
@@ -34,15 +39,24 @@ import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.exception.ThingsboardException;
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;
+import org.thingsboard.server.common.data.id.UUIDBased;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
+import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.service.security.model.SecurityUser;
+import javax.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID;
@@ -52,6 +66,7 @@ import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID;
*/
@RestController
@RequestMapping("/api")
+@Slf4j
public class EntityViewController extends BaseController {
public static final String ENTITY_VIEW_ID = "entityViewId";
@@ -75,6 +90,20 @@ public class EntityViewController extends BaseController {
try {
entityView.setTenantId(getCurrentUser().getTenantId());
EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView));
+ List<ListenableFuture<List<Void>>> futures = new ArrayList<>();
+ if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) {
+ futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), getCurrentUser()));
+ futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), getCurrentUser()));
+ futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), getCurrentUser()));
+ }
+ for (ListenableFuture<List<Void>> future : futures) {
+ try {
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException("Failed to copy attributes to entity view", e);
+ }
+ }
+
logEntityAction(savedEntityView.getId(), savedEntityView, null,
entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
return savedEntityView;
@@ -85,6 +114,62 @@ public class EntityViewController extends BaseController {
}
}
+ private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys, SecurityUser user) throws ThingsboardException {
+ EntityViewId entityId = entityView.getId();
+ if (keys != null && !keys.isEmpty()) {
+ ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys);
+ return Futures.transform(getAttrFuture, attributeKvEntries -> {
+ List<AttributeKvEntry> attributes;
+ if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) {
+ attributes =
+ attributeKvEntries.stream()
+ .filter(attributeKvEntry -> {
+ long startTime = entityView.getStartTimeMs();
+ long endTime = entityView.getEndTimeMs();
+ long lastUpdateTs = attributeKvEntry.getLastUpdateTs();
+ return startTime == 0 && endTime == 0 ||
+ (endTime == 0 && startTime < lastUpdateTs) ||
+ (startTime == 0 && endTime > lastUpdateTs)
+ ? true : startTime < lastUpdateTs && endTime > lastUpdateTs;
+ }).collect(Collectors.toList());
+ tsSubService.saveAndNotify(entityId, scope, attributes, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable Void tmp) {
+ try {
+ logAttributesUpdated(user, entityId, scope, attributes, null);
+ } catch (ThingsboardException e) {
+ log.error("Failed to log attribute updates", e);
+ }
+ if (entityId.getEntityType() == EntityType.ENTITY_VIEW) {
+ DeviceId deviceId = new DeviceId(entityId.getId());
+ DeviceAttributesEventNotificationMsg notificationMsg = DeviceAttributesEventNotificationMsg.onUpdate(
+ user.getTenantId(), deviceId, scope, attributes);
+ actorService.onMsg(new SendToClusterMsg(deviceId, notificationMsg));
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ try {
+ logAttributesUpdated(user, entityId, scope, attributes, t);
+ } catch (ThingsboardException e) {
+ log.error("Failed to log attribute updates", e);
+ }
+ }
+ });
+ }
+ return null;
+ });
+ } else {
+ return Futures.immediateFuture(null);
+ }
+ }
+
+ private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) throws ThingsboardException {
+ logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e),
+ scope, attributes);
+ }
+
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
index 7062ca9..9f92019 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
@@ -94,15 +94,9 @@ import java.util.stream.Collectors;
public class TelemetryController extends BaseController {
@Autowired
- private AttributesService attributesService;
-
- @Autowired
private TimeseriesService tsService;
@Autowired
- private TelemetrySubscriptionService tsSubService;
-
- @Autowired
private AccessValidator accessValidator;
private ExecutorService executor;
diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
index 1b67ca0..33a2699 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
@@ -29,6 +29,7 @@ import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
+import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.user.UserService;
@@ -47,6 +48,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
private DeviceService deviceService;
@Autowired
+ private EntityViewService entityViewService;
+
+ @Autowired
private TenantService tenantService;
@Autowired
@@ -81,6 +85,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
case DEVICE:
hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
break;
+ case ENTITY_VIEW:
+ hasName = entityViewService.findEntityViewByIdAsync(new EntityViewId(entityId.getId()));
+ break;
case TENANT:
hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
break;
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 a44a434..0cc6008 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
@@ -105,21 +105,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
log.trace("Executing save entity view [{}]", entityView);
entityViewValidator.validate(entityView);
EntityView savedEntityView = entityViewDao.save(entityView);
-
- List<ListenableFuture<List<Void>>> futures = new ArrayList<>();
- if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) {
- futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs()));
- futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs()));
- futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh()));
- }
- for (ListenableFuture<List<Void>> future : futures) {
- try {
- future.get();
- } catch (InterruptedException | ExecutionException e) {
- log.error("Failed to copy attributes to entity view", e);
- throw new RuntimeException("Failed to copy attributes to entity view", e);
- }
- }
return savedEntityView;
}
@@ -294,36 +279,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
});
}
- private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys) {
- if (keys != null && !keys.isEmpty()) {
- ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys);
- return Futures.transform(getAttrFuture, attributeKvEntries -> {
- List<AttributeKvEntry> filteredAttributes = new ArrayList<>();
- if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) {
- filteredAttributes =
- attributeKvEntries.stream()
- .filter(attributeKvEntry -> {
- long startTime = entityView.getStartTimeMs();
- long endTime = entityView.getEndTimeMs();
- long lastUpdateTs = attributeKvEntry.getLastUpdateTs();
- return startTime == 0 && endTime == 0 ||
- (endTime == 0 && startTime < lastUpdateTs) ||
- (startTime == 0 && endTime > lastUpdateTs)
- ? true : startTime < lastUpdateTs && endTime > lastUpdateTs;
- }).collect(Collectors.toList());
- }
- try {
- return attributesService.save(entityView.getId(), scope, filteredAttributes).get();
- } catch (InterruptedException | ExecutionException e) {
- log.error("Failed to copy attributes to entity view", e);
- throw new RuntimeException("Failed to copy attributes to entity view", e);
- }
- });
- } else {
- return Futures.immediateFuture(null);
- }
- }
-
private DataValidator<EntityView> entityViewValidator =
new DataValidator<EntityView>() {
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 1ab7605..fc0ff28 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
@@ -116,8 +116,10 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
}
List<String> filteredAttributes =
attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr, entityView)).collect(Collectors.toList());
- ctx.getAttributesService().removeAll(entityView.getId(), scope, filteredAttributes);
- transformAndTellNext(ctx, msg, entityView);
+ if (filteredAttributes != null && !filteredAttributes.isEmpty()) {
+ ctx.getAttributesService().removeAll(entityView.getId(), scope, filteredAttributes);
+ transformAndTellNext(ctx, msg, entityView);
+ }
}
}
}
@@ -139,19 +141,10 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) {
switch (scope) {
case DataConstants.CLIENT_SCOPE:
- if (entityView.getKeys().getAttributes().getCs().isEmpty()) {
- return true;
- }
return entityView.getKeys().getAttributes().getCs().contains(attrKey);
case DataConstants.SERVER_SCOPE:
- if (entityView.getKeys().getAttributes().getSs().isEmpty()) {
- return true;
- }
return entityView.getKeys().getAttributes().getSs().contains(attrKey);
case DataConstants.SHARED_SCOPE:
- if (entityView.getKeys().getAttributes().getSh().isEmpty()) {
- return true;
- }
return entityView.getKeys().getAttributes().getSh().contains(attrKey);
}
return false;
@@ -159,6 +152,5 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
@Override
public void destroy() {
-
}
}
ui/src/app/api/entity.service.js 4(+4 -0)
diff --git a/ui/src/app/api/entity.service.js b/ui/src/app/api/entity.service.js
index 205abc9..00c7ecf 100644
--- a/ui/src/app/api/entity.service.js
+++ b/ui/src/app/api/entity.service.js
@@ -135,6 +135,10 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
case types.entityType.asset:
promise = assetService.getAssets(entityIds, config);
break;
+ case types.entityType.entityView:
+ promise = getEntitiesByIdsPromise(
+ (id) => entityViewService.getEntityView(id, config), entityIds);
+ break;
case types.entityType.tenant:
promise = getEntitiesByIdsPromise(
(id) => tenantService.getTenant(id, config), entityIds);
ui/src/app/api/entity-view.service.js 27(+0 -27)
diff --git a/ui/src/app/api/entity-view.service.js b/ui/src/app/api/entity-view.service.js
index e34d3a4..23fefbc 100644
--- a/ui/src/app/api/entity-view.service.js
+++ b/ui/src/app/api/entity-view.service.js
@@ -27,7 +27,6 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu
deleteEntityView: deleteEntityView,
getCustomerEntityViews: getCustomerEntityViews,
getEntityView: getEntityView,
- getEntityViews: getEntityViews,
getTenantEntityViews: getTenantEntityViews,
saveEntityView: saveEntityView,
unassignEntityViewFromCustomer: unassignEntityViewFromCustomer,
@@ -126,32 +125,6 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu
return deferred.promise;
}
- function getEntityViews(entityViewIds, config) {
- var deferred = $q.defer();
- var ids = '';
- for (var i=0;i<entityViewIds.length;i++) {
- if (i>0) {
- ids += ',';
- }
- ids += entityViewIds[i];
- }
- var url = '/api/entityViews?entityViewIds=' + ids;
- $http.get(url, config).then(function success(response) {
- var entityViews = response.data;
- entityViews.sort(function (entityView1, entityView2) {
- var id1 = entityView1.id.id;
- var id2 = entityView2.id.id;
- var index1 = entityViewIds.indexOf(id1);
- var index2 = entityViewIds.indexOf(id2);
- return index1 - index2;
- });
- deferred.resolve(entityViews);
- }, function fail(response) {
- deferred.reject(response.data);
- });
- return deferred.promise;
- }
-
function saveEntityView(entityView) {
var deferred = $q.defer();
var url = '/api/entityView';