Commit 8b1a9351f34717de9fc8f799fdee691a39ce9081

Authored by Volodymyr Babak
1 parent 88a171d7

Fixed for entity view afte testing

... ... @@ -51,6 +51,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
51 51 import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
52 52 import org.thingsboard.server.dao.alarm.AlarmService;
53 53 import org.thingsboard.server.dao.asset.AssetService;
  54 +import org.thingsboard.server.dao.attributes.AttributesService;
54 55 import org.thingsboard.server.dao.audit.AuditLogService;
55 56 import org.thingsboard.server.dao.customer.CustomerService;
56 57 import org.thingsboard.server.dao.dashboard.DashboardService;
... ... @@ -70,6 +71,7 @@ import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
70 71 import org.thingsboard.server.service.component.ComponentDiscoveryService;
71 72 import org.thingsboard.server.service.security.model.SecurityUser;
72 73 import org.thingsboard.server.service.state.DeviceStateService;
  74 +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
73 75
74 76 import javax.mail.MessagingException;
75 77 import javax.servlet.http.HttpServletRequest;
... ... @@ -143,6 +145,12 @@ public abstract class BaseController {
143 145 @Autowired
144 146 protected EntityViewService entityViewService;
145 147
  148 + @Autowired
  149 + protected TelemetrySubscriptionService tsSubService;
  150 +
  151 + @Autowired
  152 + protected AttributesService attributesService;
  153 +
146 154 @ExceptionHandler(ThingsboardException.class)
147 155 public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) {
148 156 errorResponseHandler.handle(ex, response);
... ...
... ... @@ -15,7 +15,10 @@
15 15 */
16 16 package org.thingsboard.server.controller;
17 17
  18 +import com.google.common.util.concurrent.FutureCallback;
  19 +import com.google.common.util.concurrent.Futures;
18 20 import com.google.common.util.concurrent.ListenableFuture;
  21 +import lombok.extern.slf4j.Slf4j;
19 22 import org.springframework.http.HttpStatus;
20 23 import org.springframework.security.access.prepost.PreAuthorize;
21 24 import org.springframework.web.bind.annotation.PathVariable;
... ... @@ -26,7 +29,9 @@ import org.springframework.web.bind.annotation.RequestParam;
26 29 import org.springframework.web.bind.annotation.ResponseBody;
27 30 import org.springframework.web.bind.annotation.ResponseStatus;
28 31 import org.springframework.web.bind.annotation.RestController;
  32 +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
29 33 import org.thingsboard.server.common.data.Customer;
  34 +import org.thingsboard.server.common.data.DataConstants;
30 35 import org.thingsboard.server.common.data.EntitySubtype;
31 36 import org.thingsboard.server.common.data.EntityType;
32 37 import org.thingsboard.server.common.data.EntityView;
... ... @@ -34,15 +39,24 @@ import org.thingsboard.server.common.data.audit.ActionType;
34 39 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
35 40 import org.thingsboard.server.common.data.exception.ThingsboardException;
36 41 import org.thingsboard.server.common.data.id.CustomerId;
  42 +import org.thingsboard.server.common.data.id.DeviceId;
  43 +import org.thingsboard.server.common.data.id.EntityId;
37 44 import org.thingsboard.server.common.data.id.EntityViewId;
38 45 import org.thingsboard.server.common.data.id.TenantId;
  46 +import org.thingsboard.server.common.data.id.UUIDBased;
  47 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
39 48 import org.thingsboard.server.common.data.page.TextPageData;
40 49 import org.thingsboard.server.common.data.page.TextPageLink;
  50 +import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
41 51 import org.thingsboard.server.dao.exception.IncorrectParameterException;
42 52 import org.thingsboard.server.dao.model.ModelConstants;
43 53 import org.thingsboard.server.service.security.model.SecurityUser;
44 54
  55 +import javax.annotation.Nullable;
  56 +import java.util.ArrayList;
  57 +import java.util.Collection;
45 58 import java.util.List;
  59 +import java.util.concurrent.ExecutionException;
46 60 import java.util.stream.Collectors;
47 61
48 62 import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID;
... ... @@ -52,6 +66,7 @@ import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID;
52 66 */
53 67 @RestController
54 68 @RequestMapping("/api")
  69 +@Slf4j
55 70 public class EntityViewController extends BaseController {
56 71
57 72 public static final String ENTITY_VIEW_ID = "entityViewId";
... ... @@ -75,6 +90,20 @@ public class EntityViewController extends BaseController {
75 90 try {
76 91 entityView.setTenantId(getCurrentUser().getTenantId());
77 92 EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView));
  93 + List<ListenableFuture<List<Void>>> futures = new ArrayList<>();
  94 + if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) {
  95 + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs(), getCurrentUser()));
  96 + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs(), getCurrentUser()));
  97 + futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh(), getCurrentUser()));
  98 + }
  99 + for (ListenableFuture<List<Void>> future : futures) {
  100 + try {
  101 + future.get();
  102 + } catch (InterruptedException | ExecutionException e) {
  103 + throw new RuntimeException("Failed to copy attributes to entity view", e);
  104 + }
  105 + }
  106 +
78 107 logEntityAction(savedEntityView.getId(), savedEntityView, null,
79 108 entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
80 109 return savedEntityView;
... ... @@ -85,6 +114,62 @@ public class EntityViewController extends BaseController {
85 114 }
86 115 }
87 116
  117 + private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys, SecurityUser user) throws ThingsboardException {
  118 + EntityViewId entityId = entityView.getId();
  119 + if (keys != null && !keys.isEmpty()) {
  120 + ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys);
  121 + return Futures.transform(getAttrFuture, attributeKvEntries -> {
  122 + List<AttributeKvEntry> attributes;
  123 + if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) {
  124 + attributes =
  125 + attributeKvEntries.stream()
  126 + .filter(attributeKvEntry -> {
  127 + long startTime = entityView.getStartTimeMs();
  128 + long endTime = entityView.getEndTimeMs();
  129 + long lastUpdateTs = attributeKvEntry.getLastUpdateTs();
  130 + return startTime == 0 && endTime == 0 ||
  131 + (endTime == 0 && startTime < lastUpdateTs) ||
  132 + (startTime == 0 && endTime > lastUpdateTs)
  133 + ? true : startTime < lastUpdateTs && endTime > lastUpdateTs;
  134 + }).collect(Collectors.toList());
  135 + tsSubService.saveAndNotify(entityId, scope, attributes, new FutureCallback<Void>() {
  136 + @Override
  137 + public void onSuccess(@Nullable Void tmp) {
  138 + try {
  139 + logAttributesUpdated(user, entityId, scope, attributes, null);
  140 + } catch (ThingsboardException e) {
  141 + log.error("Failed to log attribute updates", e);
  142 + }
  143 + if (entityId.getEntityType() == EntityType.ENTITY_VIEW) {
  144 + DeviceId deviceId = new DeviceId(entityId.getId());
  145 + DeviceAttributesEventNotificationMsg notificationMsg = DeviceAttributesEventNotificationMsg.onUpdate(
  146 + user.getTenantId(), deviceId, scope, attributes);
  147 + actorService.onMsg(new SendToClusterMsg(deviceId, notificationMsg));
  148 + }
  149 + }
  150 +
  151 + @Override
  152 + public void onFailure(Throwable t) {
  153 + try {
  154 + logAttributesUpdated(user, entityId, scope, attributes, t);
  155 + } catch (ThingsboardException e) {
  156 + log.error("Failed to log attribute updates", e);
  157 + }
  158 + }
  159 + });
  160 + }
  161 + return null;
  162 + });
  163 + } else {
  164 + return Futures.immediateFuture(null);
  165 + }
  166 + }
  167 +
  168 + private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) throws ThingsboardException {
  169 + logEntityAction(user, (UUIDBased & EntityId) entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e),
  170 + scope, attributes);
  171 + }
  172 +
88 173 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
89 174 @RequestMapping(value = "/entityView/{entityViewId}", method = RequestMethod.DELETE)
90 175 @ResponseStatus(value = HttpStatus.OK)
... ...
... ... @@ -94,15 +94,9 @@ import java.util.stream.Collectors;
94 94 public class TelemetryController extends BaseController {
95 95
96 96 @Autowired
97   - private AttributesService attributesService;
98   -
99   - @Autowired
100 97 private TimeseriesService tsService;
101 98
102 99 @Autowired
103   - private TelemetrySubscriptionService tsSubService;
104   -
105   - @Autowired
106 100 private AccessValidator accessValidator;
107 101
108 102 private ExecutorService executor;
... ...
... ... @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.asset.AssetService;
29 29 import org.thingsboard.server.dao.customer.CustomerService;
30 30 import org.thingsboard.server.dao.dashboard.DashboardService;
31 31 import org.thingsboard.server.dao.device.DeviceService;
  32 +import org.thingsboard.server.dao.entityview.EntityViewService;
32 33 import org.thingsboard.server.dao.rule.RuleChainService;
33 34 import org.thingsboard.server.dao.tenant.TenantService;
34 35 import org.thingsboard.server.dao.user.UserService;
... ... @@ -47,6 +48,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
47 48 private DeviceService deviceService;
48 49
49 50 @Autowired
  51 + private EntityViewService entityViewService;
  52 +
  53 + @Autowired
50 54 private TenantService tenantService;
51 55
52 56 @Autowired
... ... @@ -81,6 +85,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
81 85 case DEVICE:
82 86 hasName = deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId()));
83 87 break;
  88 + case ENTITY_VIEW:
  89 + hasName = entityViewService.findEntityViewByIdAsync(new EntityViewId(entityId.getId()));
  90 + break;
84 91 case TENANT:
85 92 hasName = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
86 93 break;
... ...
... ... @@ -105,21 +105,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
105 105 log.trace("Executing save entity view [{}]", entityView);
106 106 entityViewValidator.validate(entityView);
107 107 EntityView savedEntityView = entityViewDao.save(entityView);
108   -
109   - List<ListenableFuture<List<Void>>> futures = new ArrayList<>();
110   - if (savedEntityView.getKeys() != null && savedEntityView.getKeys().getAttributes() != null) {
111   - futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.CLIENT_SCOPE, savedEntityView.getKeys().getAttributes().getCs()));
112   - futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SERVER_SCOPE, savedEntityView.getKeys().getAttributes().getSs()));
113   - futures.add(copyAttributesFromEntityToEntityView(savedEntityView, DataConstants.SHARED_SCOPE, savedEntityView.getKeys().getAttributes().getSh()));
114   - }
115   - for (ListenableFuture<List<Void>> future : futures) {
116   - try {
117   - future.get();
118   - } catch (InterruptedException | ExecutionException e) {
119   - log.error("Failed to copy attributes to entity view", e);
120   - throw new RuntimeException("Failed to copy attributes to entity view", e);
121   - }
122   - }
123 108 return savedEntityView;
124 109 }
125 110
... ... @@ -294,36 +279,6 @@ public class EntityViewServiceImpl extends AbstractEntityService implements Enti
294 279 });
295 280 }
296 281
297   - private ListenableFuture<List<Void>> copyAttributesFromEntityToEntityView(EntityView entityView, String scope, Collection<String> keys) {
298   - if (keys != null && !keys.isEmpty()) {
299   - ListenableFuture<List<AttributeKvEntry>> getAttrFuture = attributesService.find(entityView.getEntityId(), scope, keys);
300   - return Futures.transform(getAttrFuture, attributeKvEntries -> {
301   - List<AttributeKvEntry> filteredAttributes = new ArrayList<>();
302   - if (attributeKvEntries != null && !attributeKvEntries.isEmpty()) {
303   - filteredAttributes =
304   - attributeKvEntries.stream()
305   - .filter(attributeKvEntry -> {
306   - long startTime = entityView.getStartTimeMs();
307   - long endTime = entityView.getEndTimeMs();
308   - long lastUpdateTs = attributeKvEntry.getLastUpdateTs();
309   - return startTime == 0 && endTime == 0 ||
310   - (endTime == 0 && startTime < lastUpdateTs) ||
311   - (startTime == 0 && endTime > lastUpdateTs)
312   - ? true : startTime < lastUpdateTs && endTime > lastUpdateTs;
313   - }).collect(Collectors.toList());
314   - }
315   - try {
316   - return attributesService.save(entityView.getId(), scope, filteredAttributes).get();
317   - } catch (InterruptedException | ExecutionException e) {
318   - log.error("Failed to copy attributes to entity view", e);
319   - throw new RuntimeException("Failed to copy attributes to entity view", e);
320   - }
321   - });
322   - } else {
323   - return Futures.immediateFuture(null);
324   - }
325   - }
326   -
327 282 private DataValidator<EntityView> entityViewValidator =
328 283 new DataValidator<EntityView>() {
329 284
... ...
... ... @@ -116,8 +116,10 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
116 116 }
117 117 List<String> filteredAttributes =
118 118 attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr, entityView)).collect(Collectors.toList());
119   - ctx.getAttributesService().removeAll(entityView.getId(), scope, filteredAttributes);
120   - transformAndTellNext(ctx, msg, entityView);
  119 + if (filteredAttributes != null && !filteredAttributes.isEmpty()) {
  120 + ctx.getAttributesService().removeAll(entityView.getId(), scope, filteredAttributes);
  121 + transformAndTellNext(ctx, msg, entityView);
  122 + }
121 123 }
122 124 }
123 125 }
... ... @@ -139,19 +141,10 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
139 141 private boolean attributeContainsInEntityView(String scope, String attrKey, EntityView entityView) {
140 142 switch (scope) {
141 143 case DataConstants.CLIENT_SCOPE:
142   - if (entityView.getKeys().getAttributes().getCs().isEmpty()) {
143   - return true;
144   - }
145 144 return entityView.getKeys().getAttributes().getCs().contains(attrKey);
146 145 case DataConstants.SERVER_SCOPE:
147   - if (entityView.getKeys().getAttributes().getSs().isEmpty()) {
148   - return true;
149   - }
150 146 return entityView.getKeys().getAttributes().getSs().contains(attrKey);
151 147 case DataConstants.SHARED_SCOPE:
152   - if (entityView.getKeys().getAttributes().getSh().isEmpty()) {
153   - return true;
154   - }
155 148 return entityView.getKeys().getAttributes().getSh().contains(attrKey);
156 149 }
157 150 return false;
... ... @@ -159,6 +152,5 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
159 152
160 153 @Override
161 154 public void destroy() {
162   -
163 155 }
164 156 }
... ...
... ... @@ -27,7 +27,6 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu
27 27 deleteEntityView: deleteEntityView,
28 28 getCustomerEntityViews: getCustomerEntityViews,
29 29 getEntityView: getEntityView,
30   - getEntityViews: getEntityViews,
31 30 getTenantEntityViews: getTenantEntityViews,
32 31 saveEntityView: saveEntityView,
33 32 unassignEntityViewFromCustomer: unassignEntityViewFromCustomer,
... ... @@ -126,32 +125,6 @@ function EntityViewService($http, $q, $window, userService, attributeService, cu
126 125 return deferred.promise;
127 126 }
128 127
129   - function getEntityViews(entityViewIds, config) {
130   - var deferred = $q.defer();
131   - var ids = '';
132   - for (var i=0;i<entityViewIds.length;i++) {
133   - if (i>0) {
134   - ids += ',';
135   - }
136   - ids += entityViewIds[i];
137   - }
138   - var url = '/api/entityViews?entityViewIds=' + ids;
139   - $http.get(url, config).then(function success(response) {
140   - var entityViews = response.data;
141   - entityViews.sort(function (entityView1, entityView2) {
142   - var id1 = entityView1.id.id;
143   - var id2 = entityView2.id.id;
144   - var index1 = entityViewIds.indexOf(id1);
145   - var index2 = entityViewIds.indexOf(id2);
146   - return index1 - index2;
147   - });
148   - deferred.resolve(entityViews);
149   - }, function fail(response) {
150   - deferred.reject(response.data);
151   - });
152   - return deferred.promise;
153   - }
154   -
155 128 function saveEntityView(entityView) {
156 129 var deferred = $q.defer();
157 130 var url = '/api/entityView';
... ...
... ... @@ -135,6 +135,10 @@ function EntityService($http, $q, $filter, $translate, $log, userService, device
135 135 case types.entityType.asset:
136 136 promise = assetService.getAssets(entityIds, config);
137 137 break;
  138 + case types.entityType.entityView:
  139 + promise = getEntitiesByIdsPromise(
  140 + (id) => entityViewService.getEntityView(id, config), entityIds);
  141 + break;
138 142 case types.entityType.tenant:
139 143 promise = getEntitiesByIdsPromise(
140 144 (id) => tenantService.getTenant(id, config), entityIds);
... ...