Commit 0c7a51242d38989c9b593cdedb6930daf7c0d727
1 parent
69994adb
Tech depts. Added support for Edge entity on push to edge node
Showing
8 changed files
with
95 additions
and
81 deletions
... | ... | @@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; |
25 | 25 | import org.checkerframework.checker.nullness.qual.Nullable; |
26 | 26 | import org.springframework.beans.factory.annotation.Autowired; |
27 | 27 | import org.springframework.stereotype.Service; |
28 | +import org.thingsboard.server.common.data.EdgeUtils; | |
28 | 29 | import org.thingsboard.server.common.data.EntityType; |
29 | 30 | import org.thingsboard.server.common.data.User; |
30 | 31 | import org.thingsboard.server.common.data.alarm.Alarm; |
... | ... | @@ -445,7 +446,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { |
445 | 446 | @Override |
446 | 447 | public void onSuccess(@Nullable Alarm alarm) { |
447 | 448 | if (alarm != null) { |
448 | - EdgeEventType type = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); | |
449 | + EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType()); | |
449 | 450 | if (type != null) { |
450 | 451 | ListenableFuture<List<EdgeId>> relatedEdgeIdsByEntityIdFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator()); |
451 | 452 | Futures.addCallback(relatedEdgeIdsByEntityIdFuture, new FutureCallback<List<EdgeId>>() { |
... | ... | @@ -518,20 +519,6 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { |
518 | 519 | }, dbCallbackExecutorService); |
519 | 520 | } |
520 | 521 | } |
521 | - | |
522 | - private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { | |
523 | - switch (entityType) { | |
524 | - case DEVICE: | |
525 | - return EdgeEventType.DEVICE; | |
526 | - case ASSET: | |
527 | - return EdgeEventType.ASSET; | |
528 | - case ENTITY_VIEW: | |
529 | - return EdgeEventType.ENTITY_VIEW; | |
530 | - default: | |
531 | - log.debug("Unsupported entity type: [{}]", entityType); | |
532 | - return null; | |
533 | - } | |
534 | - } | |
535 | 522 | } |
536 | 523 | |
537 | 524 | ... | ... |
... | ... | @@ -431,6 +431,9 @@ public final class EdgeGrpcSession implements Closeable { |
431 | 431 | case CUSTOMER: |
432 | 432 | entityId = new CustomerId(edgeEvent.getEntityId()); |
433 | 433 | break; |
434 | + case EDGE: | |
435 | + entityId = new EdgeId(edgeEvent.getEntityId()); | |
436 | + break; | |
434 | 437 | } |
435 | 438 | DownlinkMsg downlinkMsg = null; |
436 | 439 | if (entityId != null) { | ... | ... |
... | ... | @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.AdminSettings; |
35 | 35 | import org.thingsboard.server.common.data.DashboardInfo; |
36 | 36 | import org.thingsboard.server.common.data.DataConstants; |
37 | 37 | import org.thingsboard.server.common.data.Device; |
38 | +import org.thingsboard.server.common.data.EdgeUtils; | |
38 | 39 | import org.thingsboard.server.common.data.EntityType; |
39 | 40 | import org.thingsboard.server.common.data.EntityView; |
40 | 41 | import org.thingsboard.server.common.data.User; |
... | ... | @@ -146,7 +147,7 @@ public class DefaultSyncEdgeService implements SyncEdgeService { |
146 | 147 | |
147 | 148 | @Override |
148 | 149 | public void sync(Edge edge) { |
149 | - log.trace("[{}] staring sync process for edge [{}]", edge.getTenantId(), edge.getName()); | |
150 | + log.trace("[{}][{}] Staring edge sync process", edge.getTenantId(), edge.getId()); | |
150 | 151 | try { |
151 | 152 | syncWidgetsBundleAndWidgetTypes(edge); |
152 | 153 | syncAdminSettings(edge); |
... | ... | @@ -157,7 +158,7 @@ public class DefaultSyncEdgeService implements SyncEdgeService { |
157 | 158 | syncEntityViews(edge, new TimePageLink(DEFAULT_LIMIT)); |
158 | 159 | syncDashboards(edge, new TimePageLink(DEFAULT_LIMIT)); |
159 | 160 | } catch (Exception e) { |
160 | - log.error("Exception during sync process", e); | |
161 | + log.error("[{}][{}] Exception during sync process", edge.getTenantId(), edge.getId(), e); | |
161 | 162 | } |
162 | 163 | } |
163 | 164 | |
... | ... | @@ -461,7 +462,7 @@ public class DefaultSyncEdgeService implements SyncEdgeService { |
461 | 462 | EntityId entityId = EntityIdFactory.getByTypeAndUuid( |
462 | 463 | EntityType.valueOf(attributesRequestMsg.getEntityType()), |
463 | 464 | new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB())); |
464 | - final EdgeEventType type = getEdgeQueueTypeByEntityType(entityId.getEntityType()); | |
465 | + final EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType()); | |
465 | 466 | if (type != null) { |
466 | 467 | SettableFuture<Void> futureToSet = SettableFuture.create(); |
467 | 468 | String scope = attributesRequestMsg.getScope(); |
... | ... | @@ -520,19 +521,6 @@ public class DefaultSyncEdgeService implements SyncEdgeService { |
520 | 521 | } |
521 | 522 | } |
522 | 523 | |
523 | - private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { | |
524 | - switch (entityType) { | |
525 | - case DEVICE: | |
526 | - return EdgeEventType.DEVICE; | |
527 | - case ASSET: | |
528 | - return EdgeEventType.ASSET; | |
529 | - case ENTITY_VIEW: | |
530 | - return EdgeEventType.ENTITY_VIEW; | |
531 | - default: | |
532 | - return null; | |
533 | - } | |
534 | - } | |
535 | - | |
536 | 524 | @Override |
537 | 525 | public ListenableFuture<Void> processRelationRequestMsg(Edge edge, RelationRequestMsg relationRequestMsg) { |
538 | 526 | log.trace("[{}] processRelationRequestMsg [{}][{}]", edge.getTenantId(), edge.getName(), relationRequestMsg); | ... | ... |
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | * you may not use this file except in compliance with the License. |
6 | 6 | * You may obtain a copy of the License at |
7 | 7 | * |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | 9 | * |
10 | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
... | ... | @@ -15,8 +15,10 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.data; |
17 | 17 | |
18 | +import lombok.extern.slf4j.Slf4j; | |
18 | 19 | import org.thingsboard.server.common.data.edge.EdgeEventType; |
19 | 20 | |
21 | +@Slf4j | |
20 | 22 | public final class EdgeUtils { |
21 | 23 | |
22 | 24 | private EdgeUtils() { |
... | ... | @@ -49,6 +51,7 @@ public final class EdgeUtils { |
49 | 51 | case WIDGET_TYPE: |
50 | 52 | return EdgeEventType.WIDGET_TYPE; |
51 | 53 | default: |
54 | + log.warn("Unsupported entity type [{}]", entityType); | |
52 | 55 | return null; |
53 | 56 | } |
54 | 57 | } | ... | ... |
... | ... | @@ -469,12 +469,16 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic |
469 | 469 | @Override |
470 | 470 | public ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) { |
471 | 471 | log.trace("[{}] Executing findRelatedEdgeIdsByEntityId [{}]", tenantId, entityId); |
472 | - if (EntityType.TENANT.equals(entityId.getEntityType())) { | |
472 | + if (EntityType.TENANT.equals(entityId.getEntityType()) || EntityType.CUSTOMER.equals(entityId.getEntityType())) { | |
473 | 473 | List<EdgeId> result = new ArrayList<>(); |
474 | 474 | TextPageLink pageLink = new TextPageLink(DEFAULT_LIMIT); |
475 | 475 | TextPageData<Edge> pageData; |
476 | 476 | do { |
477 | - pageData = findEdgesByTenantId(tenantId, pageLink); | |
477 | + if (EntityType.TENANT.equals(entityId.getEntityType())) { | |
478 | + pageData = findEdgesByTenantId(tenantId, pageLink); | |
479 | + } else { | |
480 | + pageData = findEdgesByTenantIdAndCustomerId(tenantId, new CustomerId(entityId.getId()), pageLink); | |
481 | + } | |
478 | 482 | if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { |
479 | 483 | for (Edge edge : pageData.getData()) { |
480 | 484 | result.add(edge.getId()); | ... | ... |
... | ... | @@ -90,6 +90,7 @@ public abstract class AbstractEntityService { |
90 | 90 | List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId).get(); |
91 | 91 | if (entityViews != null && !entityViews.isEmpty()) { |
92 | 92 | EntityView entityView = entityViews.get(0); |
93 | + // TODO: voba - refactor this blocking operation in 3.3+ | |
93 | 94 | Boolean relationExists = relationService.checkRelation(tenantId,edgeId, entityView.getId(), |
94 | 95 | EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE).get(); |
95 | 96 | if (relationExists) { |
... | ... | @@ -97,7 +98,7 @@ public abstract class AbstractEntityService { |
97 | 98 | } |
98 | 99 | } |
99 | 100 | } catch (ExecutionException | InterruptedException e) { |
100 | - log.error("Exception while finding entity views for entityId [{}]", entityId, e); | |
101 | + log.error("[{}] Exception while finding entity views for entityId [{}]", tenantId, entityId, e); | |
101 | 102 | throw new RuntimeException("Exception while finding entity views for entityId [" + entityId + "]", e); |
102 | 103 | } |
103 | 104 | } | ... | ... |
... | ... | @@ -59,7 +59,7 @@ public class BaseEventService implements EventService { |
59 | 59 | public Optional<Event> saveIfNotExists(Event event) { |
60 | 60 | eventValidator.validate(event, Event::getTenantId); |
61 | 61 | if (StringUtils.isEmpty(event.getUid())) { |
62 | - throw new DataValidationException("Event uid should be specified!"); | |
62 | + throw new DataValidationException("Event uid should be specified!."); | |
63 | 63 | } |
64 | 64 | checkAndTruncateDebugEvent(event); |
65 | 65 | return eventDao.saveIfNotExists(event); |
... | ... | @@ -79,16 +79,16 @@ public class BaseEventService implements EventService { |
79 | 79 | @Override |
80 | 80 | public Optional<Event> findEvent(TenantId tenantId, EntityId entityId, String eventType, String eventUid) { |
81 | 81 | if (tenantId == null) { |
82 | - throw new DataValidationException("Tenant id should be specified!"); | |
82 | + throw new DataValidationException("Tenant id should be specified!."); | |
83 | 83 | } |
84 | 84 | if (entityId == null) { |
85 | - throw new DataValidationException("Entity id should be specified!"); | |
85 | + throw new DataValidationException("Entity id should be specified!."); | |
86 | 86 | } |
87 | 87 | if (StringUtils.isEmpty(eventType)) { |
88 | - throw new DataValidationException("Event type should be specified!"); | |
88 | + throw new DataValidationException("Event type should be specified!."); | |
89 | 89 | } |
90 | 90 | if (StringUtils.isEmpty(eventUid)) { |
91 | - throw new DataValidationException("Event uid should be specified!"); | |
91 | + throw new DataValidationException("Event uid should be specified!."); | |
92 | 92 | } |
93 | 93 | Event event = eventDao.findEvent(tenantId.getId(), entityId, eventType, eventUid); |
94 | 94 | return event != null ? Optional.of(event) : Optional.empty(); |
... | ... | @@ -131,13 +131,13 @@ public class BaseEventService implements EventService { |
131 | 131 | @Override |
132 | 132 | protected void validateDataImpl(TenantId tenantId, Event event) { |
133 | 133 | if (event.getEntityId() == null) { |
134 | - throw new DataValidationException("Entity id should be specified!"); | |
134 | + throw new DataValidationException("Entity id should be specified!."); | |
135 | 135 | } |
136 | 136 | if (StringUtils.isEmpty(event.getType())) { |
137 | - throw new DataValidationException("Event type should be specified!"); | |
137 | + throw new DataValidationException("Event type should be specified!."); | |
138 | 138 | } |
139 | 139 | if (event.getBody() == null) { |
140 | - throw new DataValidationException("Event body should be specified!"); | |
140 | + throw new DataValidationException("Event body should be specified!."); | |
141 | 141 | } |
142 | 142 | } |
143 | 143 | }; | ... | ... |
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | * you may not use this file except in compliance with the License. |
6 | 6 | * You may obtain a copy of the License at |
7 | 7 | * |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | 9 | * |
10 | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
... | ... | @@ -57,7 +57,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; |
57 | 57 | name = "push to edge", |
58 | 58 | configClazz = EmptyNodeConfiguration.class, |
59 | 59 | nodeDescription = "Pushes messages to edge", |
60 | - nodeDetails = "Pushes messages to edge, if Message Originator assigned to particular edge or is EDGE entity. This node is used only on Cloud instances to push messages from Cloud to Edge. Supports only DEVICE, ENTITY_VIEW, ASSET and EDGE Message Originator(s).", | |
60 | + nodeDetails = "Pushes messages to edge, if Message Originator assigned to particular edge or is EDGE entity. This node is used only on Cloud instances to push messages from Cloud to Edge. Supports only DEVICE, ENTITY_VIEW, ASSET, ENTITY_VIEW, DASHBOARD, TENANT, CUSTOMER and EDGE Message Originator(s).", | |
61 | 61 | uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, |
62 | 62 | configDirective = "tbNodeEmptyConfig", |
63 | 63 | icon = "cloud_download", |
... | ... | @@ -97,48 +97,75 @@ public class TbMsgPushToEdgeNode implements TbNode { |
97 | 97 | } |
98 | 98 | |
99 | 99 | private void processMsg(TbContext ctx, TbMsg msg) { |
100 | - ListenableFuture<List<EdgeId>> getEdgeIdsFuture = ctx.getEdgeService().findRelatedEdgeIdsByEntityId(ctx.getTenantId(), msg.getOriginator()); | |
101 | - Futures.addCallback(getEdgeIdsFuture, new FutureCallback<List<EdgeId>>() { | |
102 | - @Override | |
103 | - public void onSuccess(@Nullable List<EdgeId> edgeIds) { | |
104 | - if (edgeIds != null && !edgeIds.isEmpty()) { | |
105 | - for (EdgeId edgeId : edgeIds) { | |
106 | - try { | |
107 | - EdgeEvent edgeEvent = buildEdgeEvent(msg, ctx); | |
108 | - if (edgeEvent == null) { | |
109 | - log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType()); | |
110 | - ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'")); | |
111 | - } else { | |
112 | - edgeEvent.setEdgeId(edgeId); | |
113 | - ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent); | |
114 | - Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() { | |
115 | - @Override | |
116 | - public void onSuccess(@Nullable EdgeEvent event) { | |
117 | - ctx.tellNext(msg, SUCCESS); | |
118 | - ctx.onEdgeEventUpdate(ctx.getTenantId(), edgeId); | |
119 | - } | |
120 | - | |
121 | - @Override | |
122 | - public void onFailure(Throwable th) { | |
123 | - log.warn("[{}] Can't save edge event [{}] for edge [{}]", ctx.getTenantId().getId(), edgeEvent, edgeId.getId(), th); | |
124 | - ctx.tellFailure(msg, th); | |
125 | - } | |
126 | - }, ctx.getDbCallbackExecutor()); | |
100 | + if (EntityType.EDGE.equals(msg.getOriginator().getEntityType())) { | |
101 | + try { | |
102 | + EdgeEvent edgeEvent = buildEdgeEvent(msg, ctx); | |
103 | + if (edgeEvent != null) { | |
104 | + EdgeId edgeId = new EdgeId(msg.getOriginator().getId()); | |
105 | + edgeEvent.setEdgeId(edgeId); | |
106 | + ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent); | |
107 | + Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() { | |
108 | + @Override | |
109 | + public void onSuccess(@Nullable EdgeEvent event) { | |
110 | + ctx.tellNext(msg, SUCCESS); | |
111 | + ctx.onEdgeEventUpdate(ctx.getTenantId(), edgeId); | |
112 | + } | |
113 | + | |
114 | + @Override | |
115 | + public void onFailure(Throwable th) { | |
116 | + log.warn("[{}] Can't save edge event [{}] for edge [{}]", ctx.getTenantId().getId(), edgeEvent, edgeId.getId(), th); | |
117 | + ctx.tellFailure(msg, th); | |
118 | + } | |
119 | + }, ctx.getDbCallbackExecutor()); | |
120 | + } | |
121 | + } catch (JsonProcessingException e) { | |
122 | + log.error("Failed to build edge event", e); | |
123 | + ctx.tellFailure(msg, e); | |
124 | + } | |
125 | + } else { | |
126 | + ListenableFuture<List<EdgeId>> getEdgeIdsFuture = ctx.getEdgeService().findRelatedEdgeIdsByEntityId(ctx.getTenantId(), msg.getOriginator()); | |
127 | + Futures.addCallback(getEdgeIdsFuture, new FutureCallback<List<EdgeId>>() { | |
128 | + @Override | |
129 | + public void onSuccess(@Nullable List<EdgeId> edgeIds) { | |
130 | + if (edgeIds != null && !edgeIds.isEmpty()) { | |
131 | + for (EdgeId edgeId : edgeIds) { | |
132 | + try { | |
133 | + EdgeEvent edgeEvent = buildEdgeEvent(msg, ctx); | |
134 | + if (edgeEvent == null) { | |
135 | + log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType()); | |
136 | + ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'")); | |
137 | + } else { | |
138 | + edgeEvent.setEdgeId(edgeId); | |
139 | + ListenableFuture<EdgeEvent> saveFuture = ctx.getEdgeEventService().saveAsync(edgeEvent); | |
140 | + Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() { | |
141 | + @Override | |
142 | + public void onSuccess(@Nullable EdgeEvent event) { | |
143 | + ctx.tellNext(msg, SUCCESS); | |
144 | + ctx.onEdgeEventUpdate(ctx.getTenantId(), edgeId); | |
145 | + } | |
146 | + | |
147 | + @Override | |
148 | + public void onFailure(Throwable th) { | |
149 | + log.warn("[{}] Can't save edge event [{}] for edge [{}]", ctx.getTenantId().getId(), edgeEvent, edgeId.getId(), th); | |
150 | + ctx.tellFailure(msg, th); | |
151 | + } | |
152 | + }, ctx.getDbCallbackExecutor()); | |
153 | + } | |
154 | + } catch (JsonProcessingException e) { | |
155 | + log.error("Failed to build edge event", e); | |
156 | + ctx.tellFailure(msg, e); | |
127 | 157 | } |
128 | - } catch (JsonProcessingException e) { | |
129 | - log.error("Failed to build edge event", e); | |
130 | - ctx.tellFailure(msg, e); | |
131 | 158 | } |
132 | 159 | } |
133 | 160 | } |
134 | - } | |
135 | 161 | |
136 | - @Override | |
137 | - public void onFailure(Throwable t) { | |
138 | - ctx.tellFailure(msg, t); | |
139 | - } | |
162 | + @Override | |
163 | + public void onFailure(Throwable t) { | |
164 | + ctx.tellFailure(msg, t); | |
165 | + } | |
140 | 166 | |
141 | - }, ctx.getDbCallbackExecutor()); | |
167 | + }, ctx.getDbCallbackExecutor()); | |
168 | + } | |
142 | 169 | } |
143 | 170 | |
144 | 171 | private EdgeEvent buildEdgeEvent(TbMsg msg, TbContext ctx) throws JsonProcessingException { |
... | ... | @@ -221,6 +248,7 @@ public class TbMsgPushToEdgeNode implements TbNode { |
221 | 248 | case DASHBOARD: |
222 | 249 | case TENANT: |
223 | 250 | case CUSTOMER: |
251 | + case EDGE: | |
224 | 252 | return true; |
225 | 253 | default: |
226 | 254 | return false; | ... | ... |