Showing
12 changed files
with
645 additions
and
529 deletions
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | "ruleChain": { | 2 | "ruleChain": { |
3 | "additionalInfo": null, | 3 | "additionalInfo": null, |
4 | "name": "Thermostat Alarms", | 4 | "name": "Thermostat Alarms", |
5 | - "type": "SYSTEM", | 5 | + "type": "CORE", |
6 | "firstRuleNodeId": null, | 6 | "firstRuleNodeId": null, |
7 | "root": false, | 7 | "root": false, |
8 | "debugMode": false, | 8 | "debugMode": false, |
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | "ruleChain": { | 2 | "ruleChain": { |
3 | "additionalInfo": null, | 3 | "additionalInfo": null, |
4 | "name": "Root Rule Chain", | 4 | "name": "Root Rule Chain", |
5 | - "type": "SYSTEM", | 5 | + "type": "CORE", |
6 | "firstRuleNodeId": null, | 6 | "firstRuleNodeId": null, |
7 | "root": true, | 7 | "root": true, |
8 | "debugMode": false, | 8 | "debugMode": false, |
@@ -15,29 +15,25 @@ | @@ -15,29 +15,25 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.service.edge; | 16 | package org.thingsboard.server.service.edge; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
18 | import com.fasterxml.jackson.databind.ObjectMapper; | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
19 | -import com.google.common.util.concurrent.FutureCallback; | ||
20 | import com.google.common.util.concurrent.Futures; | 20 | import com.google.common.util.concurrent.Futures; |
21 | import com.google.common.util.concurrent.ListenableFuture; | 21 | import com.google.common.util.concurrent.ListenableFuture; |
22 | -import com.google.common.util.concurrent.MoreExecutors; | ||
23 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
24 | -import org.apache.commons.codec.binary.Base64; | ||
25 | import org.springframework.beans.factory.annotation.Autowired; | 23 | import org.springframework.beans.factory.annotation.Autowired; |
26 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
27 | -import org.thingsboard.server.common.data.Dashboard; | ||
28 | -import org.thingsboard.server.common.data.DataConstants; | ||
29 | -import org.thingsboard.server.common.data.Device; | ||
30 | import org.thingsboard.server.common.data.EntityType; | 25 | import org.thingsboard.server.common.data.EntityType; |
31 | -import org.thingsboard.server.common.data.EntityView; | ||
32 | -import org.thingsboard.server.common.data.Event; | ||
33 | import org.thingsboard.server.common.data.alarm.Alarm; | 26 | import org.thingsboard.server.common.data.alarm.Alarm; |
34 | -import org.thingsboard.server.common.data.asset.Asset; | ||
35 | import org.thingsboard.server.common.data.audit.ActionType; | 27 | import org.thingsboard.server.common.data.audit.ActionType; |
36 | import org.thingsboard.server.common.data.edge.Edge; | 28 | import org.thingsboard.server.common.data.edge.Edge; |
37 | import org.thingsboard.server.common.data.edge.EdgeEvent; | 29 | import org.thingsboard.server.common.data.edge.EdgeEvent; |
38 | import org.thingsboard.server.common.data.edge.EdgeEventType; | 30 | import org.thingsboard.server.common.data.edge.EdgeEventType; |
31 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
32 | +import org.thingsboard.server.common.data.id.DashboardId; | ||
39 | import org.thingsboard.server.common.data.id.EdgeId; | 33 | import org.thingsboard.server.common.data.id.EdgeId; |
40 | import org.thingsboard.server.common.data.id.EntityId; | 34 | import org.thingsboard.server.common.data.id.EntityId; |
35 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | ||
36 | +import org.thingsboard.server.common.data.id.IdBased; | ||
41 | import org.thingsboard.server.common.data.id.RuleChainId; | 37 | import org.thingsboard.server.common.data.id.RuleChainId; |
42 | import org.thingsboard.server.common.data.id.TenantId; | 38 | import org.thingsboard.server.common.data.id.TenantId; |
43 | import org.thingsboard.server.common.data.page.TimePageData; | 39 | import org.thingsboard.server.common.data.page.TimePageData; |
@@ -46,29 +42,28 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | @@ -46,29 +42,28 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | ||
46 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; | 42 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
47 | import org.thingsboard.server.common.data.rule.RuleChain; | 43 | import org.thingsboard.server.common.data.rule.RuleChain; |
48 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; | 44 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
49 | -import org.thingsboard.server.common.data.rule.RuleChainType; | ||
50 | -import org.thingsboard.server.common.msg.TbMsg; | ||
51 | import org.thingsboard.server.common.msg.queue.TbCallback; | 45 | import org.thingsboard.server.common.msg.queue.TbCallback; |
52 | -import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
53 | -import org.thingsboard.server.dao.asset.AssetService; | ||
54 | -import org.thingsboard.server.dao.device.DeviceService; | 46 | +import org.thingsboard.server.dao.alarm.AlarmService; |
55 | import org.thingsboard.server.dao.edge.EdgeEventService; | 47 | import org.thingsboard.server.dao.edge.EdgeEventService; |
56 | import org.thingsboard.server.dao.edge.EdgeService; | 48 | import org.thingsboard.server.dao.edge.EdgeService; |
57 | -import org.thingsboard.server.dao.entityview.EntityViewService; | ||
58 | -import org.thingsboard.server.dao.event.EventService; | ||
59 | import org.thingsboard.server.dao.relation.RelationService; | 49 | import org.thingsboard.server.dao.relation.RelationService; |
60 | import org.thingsboard.server.dao.rule.RuleChainService; | 50 | import org.thingsboard.server.dao.rule.RuleChainService; |
61 | import org.thingsboard.server.gen.transport.TransportProtos; | 51 | import org.thingsboard.server.gen.transport.TransportProtos; |
62 | import org.thingsboard.server.queue.util.TbCoreComponent; | 52 | import org.thingsboard.server.queue.util.TbCoreComponent; |
53 | +import org.thingsboard.server.service.executors.DbCallbackExecutorService; | ||
63 | 54 | ||
64 | -import javax.annotation.Nullable; | ||
65 | import javax.annotation.PostConstruct; | 55 | import javax.annotation.PostConstruct; |
66 | import javax.annotation.PreDestroy; | 56 | import javax.annotation.PreDestroy; |
67 | import java.io.IOException; | 57 | import java.io.IOException; |
58 | +import java.util.ArrayList; | ||
59 | +import java.util.Collections; | ||
60 | +import java.util.HashSet; | ||
68 | import java.util.List; | 61 | import java.util.List; |
62 | +import java.util.Set; | ||
69 | import java.util.UUID; | 63 | import java.util.UUID; |
70 | import java.util.concurrent.ExecutorService; | 64 | import java.util.concurrent.ExecutorService; |
71 | import java.util.concurrent.Executors; | 65 | import java.util.concurrent.Executors; |
66 | +import java.util.stream.Collectors; | ||
72 | 67 | ||
73 | @Service | 68 | @Service |
74 | @TbCoreComponent | 69 | @TbCoreComponent |
@@ -81,16 +76,10 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -81,16 +76,10 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
81 | private EdgeService edgeService; | 76 | private EdgeService edgeService; |
82 | 77 | ||
83 | @Autowired | 78 | @Autowired |
84 | - private DeviceService deviceService; | ||
85 | - | ||
86 | - @Autowired | ||
87 | - private AssetService assetService; | ||
88 | - | ||
89 | - @Autowired | ||
90 | - private EntityViewService entityViewService; | 79 | + private RuleChainService ruleChainService; |
91 | 80 | ||
92 | @Autowired | 81 | @Autowired |
93 | - private RuleChainService ruleChainService; | 82 | + private AlarmService alarmService; |
94 | 83 | ||
95 | @Autowired | 84 | @Autowired |
96 | private RelationService relationService; | 85 | private RelationService relationService; |
@@ -98,6 +87,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -98,6 +87,9 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
98 | @Autowired | 87 | @Autowired |
99 | private EdgeEventService edgeEventService; | 88 | private EdgeEventService edgeEventService; |
100 | 89 | ||
90 | + @Autowired | ||
91 | + private DbCallbackExecutorService dbCallbackExecutorService; | ||
92 | + | ||
101 | private ExecutorService tsCallBackExecutor; | 93 | private ExecutorService tsCallBackExecutor; |
102 | 94 | ||
103 | @PostConstruct | 95 | @PostConstruct |
@@ -121,315 +113,160 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -121,315 +113,160 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
121 | public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException { | 113 | public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException { |
122 | edge.setRootRuleChainId(ruleChainId); | 114 | edge.setRootRuleChainId(ruleChainId); |
123 | Edge savedEdge = edgeService.saveEdge(edge); | 115 | Edge savedEdge = edgeService.saveEdge(edge); |
124 | - RuleChain ruleChain = ruleChainService.findRuleChainById(tenantId, ruleChainId); | ||
125 | - saveEventToEdgeQueue(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, DataConstants.ENTITY_UPDATED, mapper.writeValueAsString(ruleChain), new FutureCallback<Void>() { | ||
126 | - @Override | ||
127 | - public void onSuccess(@Nullable Void aVoid) { | ||
128 | - log.debug("Event saved successfully!"); | ||
129 | - } | ||
130 | - | ||
131 | - @Override | ||
132 | - public void onFailure(Throwable t) { | ||
133 | - log.debug("Failure during event save", t); | ||
134 | - } | ||
135 | - }); | 116 | + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, ActionType.UPDATED, ruleChainId, null); |
136 | return savedEdge; | 117 | return savedEdge; |
137 | } | 118 | } |
138 | 119 | ||
139 | - private void saveEventToEdgeQueue(TenantId tenantId, EdgeId edgeId, EdgeEventType entityType, String type, String data, FutureCallback<Void> callback) throws IOException { | ||
140 | - log.debug("Pushing single event to edge queue. tenantId [{}], edgeId [{}], entityType [{}], type[{}], data [{}]", tenantId, edgeId, entityType, type, data); | ||
141 | - | ||
142 | -// EdgeEQueueEntry queueEntry = new EdgeQueueEntry(); | ||
143 | -// queueEntry.setEntityType(entityType); | ||
144 | -// queueEntry.setType(type); | ||
145 | -// queueEntry.setData(data); | 120 | + private void saveEdgeEvent(TenantId tenantId, |
121 | + EdgeId edgeId, | ||
122 | + EdgeEventType edgeEventType, | ||
123 | + ActionType edgeEventAction, | ||
124 | + EntityId entityId, | ||
125 | + JsonNode entityBody) { | ||
126 | + log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], edgeEventType [{}], edgeEventAction[{}], entityId [{}], entityBody [{}]", | ||
127 | + tenantId, edgeId, edgeEventType, edgeEventAction, entityId, entityBody); | ||
146 | 128 | ||
147 | EdgeEvent edgeEvent = new EdgeEvent(); | 129 | EdgeEvent edgeEvent = new EdgeEvent(); |
148 | edgeEvent.setEdgeId(edgeId); | 130 | edgeEvent.setEdgeId(edgeId); |
149 | edgeEvent.setTenantId(tenantId); | 131 | edgeEvent.setTenantId(tenantId); |
150 | -// event.setType(DataConstants.EDGE_QUEUE_EVENT_TYPE); | ||
151 | -// event.setBody(mapper.valueToTree(queueEntry)); | ||
152 | - ListenableFuture<EdgeEvent> saveFuture = edgeEventService.saveAsync(edgeEvent); | ||
153 | - | ||
154 | - addMainCallback(saveFuture, callback); | ||
155 | - } | ||
156 | - | ||
157 | - private void addMainCallback(ListenableFuture<EdgeEvent> saveFuture, final FutureCallback<Void> callback) { | ||
158 | - Futures.addCallback(saveFuture, new FutureCallback<EdgeEvent>() { | ||
159 | - @Override | ||
160 | - public void onSuccess(@Nullable EdgeEvent result) { | ||
161 | - callback.onSuccess(null); | ||
162 | - } | ||
163 | - | ||
164 | - @Override | ||
165 | - public void onFailure(Throwable t) { | ||
166 | - callback.onFailure(t); | ||
167 | - } | ||
168 | - }, tsCallBackExecutor); | 132 | + edgeEvent.setEdgeEventType(edgeEventType); |
133 | + edgeEvent.setEdgeEventAction(edgeEventAction.name()); | ||
134 | + if (entityId != null) { | ||
135 | + edgeEvent.setEntityId(entityId.getId()); | ||
136 | + } | ||
137 | + edgeEvent.setEntityBody(entityBody); | ||
138 | + edgeEventService.saveAsync(edgeEvent); | ||
169 | } | 139 | } |
170 | 140 | ||
171 | @Override | 141 | @Override |
172 | public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { | 142 | public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { |
173 | -// if (tbMsg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) || | ||
174 | -// tbMsg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) || | ||
175 | -// tbMsg.getType().equals(DataConstants.ATTRIBUTES_UPDATED) || | ||
176 | -// tbMsg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) { | ||
177 | -// processCustomTbMsg(tenantId, tbMsg, callback); | ||
178 | -// } else { | ||
179 | -// try { | ||
180 | -// switch (tbMsg.getOriginator().getEntityType()) { | ||
181 | -// case EDGE: | ||
182 | -// processEdge(tenantId, tbMsg, callback); | ||
183 | -// break; | ||
184 | -// case ASSET: | ||
185 | -// processAsset(tenantId, tbMsg, callback); | ||
186 | -// break; | ||
187 | -// case DEVICE: | ||
188 | -// processDevice(tenantId, tbMsg, callback); | ||
189 | -// break; | ||
190 | -// case DASHBOARD: | ||
191 | -// processDashboard(tenantId, tbMsg, callback); | ||
192 | -// break; | ||
193 | -// case RULE_CHAIN: | ||
194 | -// processRuleChain(tenantId, tbMsg, callback); | ||
195 | -// break; | ||
196 | -// case ENTITY_VIEW: | ||
197 | -// processEntityView(tenantId, tbMsg, callback); | ||
198 | -// break; | ||
199 | -// case ALARM: | ||
200 | -// processAlarm(tenantId, tbMsg, callback); | ||
201 | -// break; | ||
202 | -// default: | ||
203 | -// log.debug("Entity type [{}] is not designed to be pushed to edge", tbMsg.getOriginator().getEntityType()); | ||
204 | -// } | ||
205 | -// } catch (IOException e) { | ||
206 | -// log.error("Can't push to edge updates, entity type [{}], data [{}]", tbMsg.getOriginator().getEntityType(), tbMsg.getData(), e); | ||
207 | -// } | ||
208 | -// } | ||
209 | - } | ||
210 | - | ||
211 | - | ||
212 | - private void processCustomTbMsg(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) { | ||
213 | - ListenableFuture<EdgeId> edgeIdFuture = getEdgeIdByOriginatorId(tenantId, tbMsg.getOriginator()); | ||
214 | - Futures.transform(edgeIdFuture, edgeId -> { | ||
215 | - EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(tbMsg.getOriginator().getEntityType()); | ||
216 | - if (edgeId != null && edgeEventType != null) { | ||
217 | - try { | ||
218 | - saveEventToEdgeQueue(tenantId, edgeId, edgeEventType, tbMsg.getType(), Base64.encodeBase64String(TbMsg.toByteArray(tbMsg)), callback); | ||
219 | - } catch (IOException e) { | ||
220 | - log.error("Error while saving custom tbMsg into Edge Queue", e); | ||
221 | - } | 143 | + try { |
144 | + EdgeEventType edgeEventType = EdgeEventType.valueOf(edgeNotificationMsg.getEdgeEventType()); | ||
145 | + ActionType edgeEventAction = ActionType.valueOf(edgeNotificationMsg.getEdgeEventAction()); | ||
146 | + TenantId tenantId = new TenantId(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); | ||
147 | + switch (edgeEventType) { | ||
148 | + // TODO: voba - handle edge updates | ||
149 | + // case EDGE: | ||
150 | + case ASSET: | ||
151 | + case DEVICE: | ||
152 | + case ENTITY_VIEW: | ||
153 | + case DASHBOARD: | ||
154 | + case RULE_CHAIN: | ||
155 | + EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(edgeEventType, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); | ||
156 | + ListenableFuture<List<EdgeId>> edgeIdsFuture = findRelatedEdgeIdsEntityId(tenantId, entityId); | ||
157 | + Futures.transform(edgeIdsFuture, edgeIds -> { | ||
158 | + if (edgeIds != null && !edgeIds.isEmpty()) { | ||
159 | + for (EdgeId edgeId : edgeIds) { | ||
160 | + try { | ||
161 | + saveEdgeEvent(tenantId, edgeId, edgeEventType, edgeEventAction, entityId, null); | ||
162 | + if (edgeEventType.equals(EdgeEventType.RULE_CHAIN) && | ||
163 | + (ActionType.UPDATED.equals(edgeEventAction) || ActionType.ADDED.equals(edgeEventAction))) { | ||
164 | + RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, new RuleChainId(entityId.getId())); | ||
165 | + saveEdgeEvent(tenantId, edgeId, EdgeEventType.RULE_CHAIN_METADATA, edgeEventAction, ruleChainMetaData.getRuleChainId(), null); | ||
166 | + } | ||
167 | + } catch (Exception e) { | ||
168 | + log.error("[{}] Failed to push event to edge, edgeId [{}], edgeEventType [{}], edgeEventAction [{}], entityId [{}]", | ||
169 | + tenantId, edgeId, edgeEventType, edgeEventAction, entityId, e); | ||
170 | + } | ||
171 | + } | ||
172 | + } | ||
173 | + return null; | ||
174 | + }, dbCallbackExecutorService); | ||
175 | + break; | ||
176 | + case ALARM: | ||
177 | + EntityId alarmId = EntityIdFactory.getByEdgeEventTypeAndUuid(edgeEventType, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); | ||
178 | + processAlarm(tenantId, edgeEventAction, alarmId); | ||
179 | + break; | ||
180 | + case RELATION: | ||
181 | + EntityRelation entityRelation = mapper.convertValue(edgeNotificationMsg.getEntityBody(), EntityRelation.class); | ||
182 | + processRelation(tenantId, edgeEventAction, entityRelation); | ||
183 | + break; | ||
184 | + default: | ||
185 | + log.debug("Edge event type [{}] is not designed to be pushed to edge", edgeEventType); | ||
222 | } | 186 | } |
223 | - return null; | ||
224 | - }, MoreExecutors.directExecutor()); | ||
225 | - } | ||
226 | - | ||
227 | - private void processDevice(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
228 | - switch (tbMsg.getType()) { | ||
229 | - case DataConstants.ENTITY_ASSIGNED_TO_EDGE: | ||
230 | - case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: | ||
231 | - processAssignedEntity(tenantId, tbMsg, EdgeEventType.DEVICE, callback); | ||
232 | - break; | ||
233 | - case DataConstants.ENTITY_DELETED: | ||
234 | - case DataConstants.ENTITY_CREATED: | ||
235 | - case DataConstants.ENTITY_UPDATED: | ||
236 | - Device device = mapper.readValue(tbMsg.getData(), Device.class); | ||
237 | - pushEventToEdge(tenantId, device.getId(), EdgeEventType.DEVICE, tbMsg, callback); | ||
238 | - break; | ||
239 | - default: | ||
240 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | ||
241 | - } | ||
242 | - } | ||
243 | - | ||
244 | - private void processEdge(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
245 | - switch (tbMsg.getType()) { | ||
246 | - case DataConstants.ENTITY_DELETED: | ||
247 | - case DataConstants.ENTITY_CREATED: | ||
248 | - case DataConstants.ENTITY_UPDATED: | ||
249 | - // TODO: voba - handle properly edge creation | ||
250 | - break; | ||
251 | - default: | ||
252 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | ||
253 | - } | ||
254 | - } | ||
255 | - | ||
256 | - private void processAsset(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
257 | - switch (tbMsg.getType()) { | ||
258 | - case DataConstants.ENTITY_ASSIGNED_TO_EDGE: | ||
259 | - case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: | ||
260 | - processAssignedEntity(tenantId, tbMsg, EdgeEventType.ASSET, callback); | ||
261 | - break; | ||
262 | - case DataConstants.ENTITY_DELETED: | ||
263 | - case DataConstants.ENTITY_CREATED: | ||
264 | - case DataConstants.ENTITY_UPDATED: | ||
265 | - Asset asset = mapper.readValue(tbMsg.getData(), Asset.class); | ||
266 | - pushEventToEdge(tenantId, asset.getId(), EdgeEventType.ASSET, tbMsg, callback); | ||
267 | - break; | ||
268 | - default: | ||
269 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | 187 | + } catch (Exception e) { |
188 | + callback.onFailure(e); | ||
189 | + log.error("Can't push to edge updates, edgeNotificationMsg [{}]", edgeNotificationMsg, e); | ||
190 | + } finally { | ||
191 | + callback.onSuccess(); | ||
270 | } | 192 | } |
271 | } | 193 | } |
272 | 194 | ||
273 | - private void processEntityView(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
274 | - switch (tbMsg.getType()) { | ||
275 | - case DataConstants.ENTITY_ASSIGNED_TO_EDGE: | ||
276 | - case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: | ||
277 | - processAssignedEntity(tenantId, tbMsg, EdgeEventType.ENTITY_VIEW, callback); | ||
278 | - break; | ||
279 | - case DataConstants.ENTITY_DELETED: | ||
280 | - case DataConstants.ENTITY_CREATED: | ||
281 | - case DataConstants.ENTITY_UPDATED: | ||
282 | - EntityView entityView = mapper.readValue(tbMsg.getData(), EntityView.class); | ||
283 | - pushEventToEdge(tenantId, entityView.getId(), EdgeEventType.ENTITY_VIEW, tbMsg, callback); | ||
284 | - break; | ||
285 | - default: | ||
286 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | ||
287 | - } | ||
288 | - } | ||
289 | - | ||
290 | - private void processAlarm(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
291 | - switch (tbMsg.getType()) { | ||
292 | - case DataConstants.ENTITY_DELETED: | ||
293 | - case DataConstants.ENTITY_CREATED: | ||
294 | - case DataConstants.ENTITY_UPDATED: | ||
295 | - case DataConstants.ALARM_ACK: | ||
296 | - case DataConstants.ALARM_CLEAR: | ||
297 | - Alarm alarm = mapper.readValue(tbMsg.getData(), Alarm.class); | 195 | + private void processAlarm(TenantId tenantId, ActionType edgeActionType, EntityId alarmId) { |
196 | + ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, new AlarmId(alarmId.getId())); | ||
197 | + Futures.transform(alarmFuture, alarm -> { | ||
198 | + if (alarm != null) { | ||
298 | EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); | 199 | EdgeEventType edgeEventType = getEdgeQueueTypeByEntityType(alarm.getOriginator().getEntityType()); |
299 | if (edgeEventType != null) { | 200 | if (edgeEventType != null) { |
300 | - pushEventToEdge(tenantId, alarm.getOriginator(), EdgeEventType.ALARM, tbMsg, callback); | ||
301 | - } | ||
302 | - break; | ||
303 | - default: | ||
304 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | ||
305 | - } | ||
306 | - } | ||
307 | - | ||
308 | - private void processDashboard(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
309 | - switch (tbMsg.getType()) { | ||
310 | - case DataConstants.ENTITY_ASSIGNED_TO_EDGE: | ||
311 | - case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: | ||
312 | - processAssignedEntity(tenantId, tbMsg, EdgeEventType.DASHBOARD, callback); | ||
313 | - break; | ||
314 | - case DataConstants.ENTITY_DELETED: | ||
315 | - case DataConstants.ENTITY_CREATED: | ||
316 | - case DataConstants.ENTITY_UPDATED: | ||
317 | - Dashboard dashboard = mapper.readValue(tbMsg.getData(), Dashboard.class); | ||
318 | - ListenableFuture<TimePageData<Edge>> future = edgeService.findEdgesByTenantIdAndDashboardId(tenantId, dashboard.getId(), new TimePageLink(Integer.MAX_VALUE)); | ||
319 | - Futures.transform(future, edges -> { | ||
320 | - if (edges != null && edges.getData() != null && !edges.getData().isEmpty()) { | ||
321 | - try { | ||
322 | - for (Edge edge : edges.getData()) { | ||
323 | - pushEventToEdge(tenantId, edge.getId(), EdgeEventType.DASHBOARD, tbMsg, callback); | ||
324 | - } | ||
325 | - } catch (IOException e) { | ||
326 | - log.error("Can't push event to edge", e); | ||
327 | - } | ||
328 | - } | ||
329 | - return null; | ||
330 | - }, MoreExecutors.directExecutor()); | ||
331 | - break; | ||
332 | - default: | ||
333 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | ||
334 | - } | ||
335 | - } | ||
336 | - | ||
337 | - private void processRuleChain(TenantId tenantId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
338 | - switch (tbMsg.getType()) { | ||
339 | - case DataConstants.ENTITY_ASSIGNED_TO_EDGE: | ||
340 | - case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: | ||
341 | - processAssignedEntity(tenantId, tbMsg, EdgeEventType.RULE_CHAIN, callback); | ||
342 | - break; | ||
343 | - case DataConstants.ENTITY_DELETED: | ||
344 | - case DataConstants.ENTITY_CREATED: | ||
345 | - case DataConstants.ENTITY_UPDATED: | ||
346 | - RuleChain ruleChain = mapper.readValue(tbMsg.getData(), RuleChain.class); | ||
347 | - if (RuleChainType.EDGE.equals(ruleChain.getType())) { | ||
348 | - ListenableFuture<TimePageData<Edge>> future = edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, ruleChain.getId(), new TimePageLink(Integer.MAX_VALUE)); | ||
349 | - Futures.transform(future, edges -> { | ||
350 | - if (edges != null && edges.getData() != null && !edges.getData().isEmpty()) { | ||
351 | - try { | ||
352 | - for (Edge edge : edges.getData()) { | ||
353 | - pushEventToEdge(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, tbMsg, callback); | ||
354 | - } | ||
355 | - } catch (IOException e) { | ||
356 | - log.error("Can't push event to edge", e); | 201 | + ListenableFuture<List<EdgeId>> relatedEdgeIdsEntityIdFuture = findRelatedEdgeIdsEntityId(tenantId, alarm.getOriginator()); |
202 | + Futures.transform(relatedEdgeIdsEntityIdFuture, relatedEdgeIdsEntityId -> { | ||
203 | + if (relatedEdgeIdsEntityId != null) { | ||
204 | + for (EdgeId edgeId : relatedEdgeIdsEntityId) { | ||
205 | + saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, edgeActionType, alarmId, null); | ||
357 | } | 206 | } |
358 | } | 207 | } |
359 | return null; | 208 | return null; |
360 | - }, MoreExecutors.directExecutor()); | 209 | + }, dbCallbackExecutorService); |
361 | } | 210 | } |
362 | - break; | ||
363 | - default: | ||
364 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | ||
365 | - } | ||
366 | - } | ||
367 | - | ||
368 | - | ||
369 | - private void processAssignedEntity(TenantId tenantId, TbMsg tbMsg, EdgeEventType entityType, FutureCallback<Void> callback) throws IOException { | ||
370 | - EdgeId edgeId; | ||
371 | - switch (tbMsg.getType()) { | ||
372 | - case DataConstants.ENTITY_ASSIGNED_TO_EDGE: | ||
373 | - edgeId = new EdgeId(UUID.fromString(tbMsg.getMetaData().getValue("assignedEdgeId"))); | ||
374 | - pushEventToEdge(tenantId, edgeId, entityType, tbMsg, callback); | ||
375 | - break; | ||
376 | - case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: | ||
377 | - edgeId = new EdgeId(UUID.fromString(tbMsg.getMetaData().getValue("unassignedEdgeId"))); | ||
378 | - pushEventToEdge(tenantId, edgeId, entityType, tbMsg, callback); | ||
379 | - break; | ||
380 | - | ||
381 | - } | 211 | + } |
212 | + return null; | ||
213 | + }, dbCallbackExecutorService); | ||
382 | } | 214 | } |
383 | 215 | ||
384 | - private void pushEventToEdge(TenantId tenantId, EntityId originatorId, EdgeEventType edgeEventType, TbMsg tbMsg, FutureCallback<Void> callback) { | ||
385 | - ListenableFuture<EdgeId> edgeIdFuture = getEdgeIdByOriginatorId(tenantId, originatorId); | ||
386 | - Futures.transform(edgeIdFuture, edgeId -> { | ||
387 | - if (edgeId != null) { | ||
388 | - try { | ||
389 | - pushEventToEdge(tenantId, edgeId, edgeEventType, tbMsg, callback); | ||
390 | - } catch (Exception e) { | ||
391 | - log.error("Failed to push event to edge, edgeId [{}], tbMsg [{}]", edgeId, tbMsg, e); | ||
392 | - } | 216 | + private void processRelation(TenantId tenantId, ActionType edgeActionType, EntityRelation entityRelation) { |
217 | + List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>(); | ||
218 | + futures.add(findRelatedEdgeIdsEntityId(tenantId, entityRelation.getTo())); | ||
219 | + futures.add(findRelatedEdgeIdsEntityId(tenantId, entityRelation.getFrom())); | ||
220 | + ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures); | ||
221 | + Futures.transform(combinedFuture, listOfListsEdgeIds -> { | ||
222 | + Set<EdgeId> uniqueEdgeIds = new HashSet<>(); | ||
223 | + if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) { | ||
224 | + for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) { | ||
225 | + if (listOfListsEdgeId != null) { | ||
226 | + uniqueEdgeIds.addAll(listOfListsEdgeId); | ||
393 | } | 227 | } |
394 | - return null; | ||
395 | - }, | ||
396 | - MoreExecutors.directExecutor()); | ||
397 | - } | ||
398 | - | ||
399 | - private ListenableFuture<EdgeId> getEdgeIdByOriginatorId(TenantId tenantId, EntityId originatorId) { | ||
400 | - List<EntityRelation> originatorEdgeRelations = relationService.findByToAndType(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); | ||
401 | - if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { | ||
402 | - return Futures.immediateFuture(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); | ||
403 | - } else { | ||
404 | - return Futures.immediateFuture(null); | ||
405 | - } | ||
406 | - } | ||
407 | - | ||
408 | - | ||
409 | - private void pushEventToEdge(TenantId tenantId, EdgeId edgeId, EdgeEventType entityType, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
410 | - log.debug("Pushing event(s) to edge queue. tenantId [{}], edgeId [{}], entityType [{}], tbMsg [{}]", tenantId, edgeId, entityType, tbMsg); | ||
411 | - | ||
412 | - saveEventToEdgeQueue(tenantId, edgeId, entityType, tbMsg.getType(), tbMsg.getData(), callback); | ||
413 | - | ||
414 | - if (entityType.equals(EdgeEventType.RULE_CHAIN)) { | ||
415 | - pushRuleChainMetadataToEdge(tenantId, edgeId, tbMsg, callback); | ||
416 | - } | 228 | + } |
229 | + } | ||
230 | + if (!uniqueEdgeIds.isEmpty()) { | ||
231 | + for (EdgeId edgeId : uniqueEdgeIds) { | ||
232 | + saveEdgeEvent(tenantId, edgeId, EdgeEventType.RELATION, edgeActionType, null, mapper.valueToTree(entityRelation)); | ||
233 | + } | ||
234 | + } | ||
235 | + return null; | ||
236 | + }, dbCallbackExecutorService); | ||
417 | } | 237 | } |
418 | 238 | ||
419 | - private void pushRuleChainMetadataToEdge(TenantId tenantId, EdgeId edgeId, TbMsg tbMsg, FutureCallback<Void> callback) throws IOException { | ||
420 | - RuleChain ruleChain = mapper.readValue(tbMsg.getData(), RuleChain.class); | ||
421 | - switch (tbMsg.getType()) { | ||
422 | - case DataConstants.ENTITY_ASSIGNED_TO_EDGE: | ||
423 | - case DataConstants.ENTITY_UNASSIGNED_FROM_EDGE: | ||
424 | - case DataConstants.ENTITY_UPDATED: | ||
425 | - RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(tenantId, ruleChain.getId()); | ||
426 | - saveEventToEdgeQueue(tenantId, edgeId, EdgeEventType.RULE_CHAIN_METADATA, tbMsg.getType(), mapper.writeValueAsString(ruleChainMetaData), callback); | ||
427 | - break; | 239 | + private ListenableFuture<List<EdgeId>> findRelatedEdgeIdsEntityId(TenantId tenantId, EntityId entityId) { |
240 | + switch (entityId.getEntityType()) { | ||
241 | + case DEVICE: | ||
242 | + case ASSET: | ||
243 | + case ENTITY_VIEW: | ||
244 | + ListenableFuture<List<EntityRelation>> originatorEdgeRelationsFuture = relationService.findByToAndTypeAsync(tenantId, entityId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); | ||
245 | + return Futures.transform(originatorEdgeRelationsFuture, originatorEdgeRelations -> { | ||
246 | + if (originatorEdgeRelations != null && originatorEdgeRelations.size() > 0) { | ||
247 | + return Collections.singletonList(new EdgeId(originatorEdgeRelations.get(0).getFrom().getId())); | ||
248 | + } else { | ||
249 | + return Collections.emptyList(); | ||
250 | + } | ||
251 | + }, dbCallbackExecutorService); | ||
252 | + case DASHBOARD: | ||
253 | + return convertToEdgeIds(edgeService.findEdgesByTenantIdAndDashboardId(tenantId, new DashboardId(entityId.getId()), new TimePageLink(Integer.MAX_VALUE))); | ||
254 | + case RULE_CHAIN: | ||
255 | + return convertToEdgeIds(edgeService.findEdgesByTenantIdAndRuleChainId(tenantId, new RuleChainId(entityId.getId()), new TimePageLink(Integer.MAX_VALUE))); | ||
428 | default: | 256 | default: |
429 | - log.warn("Unsupported msgType [{}], tbMsg [{}]", tbMsg.getType(), tbMsg); | 257 | + return Futures.immediateFuture(Collections.emptyList()); |
430 | } | 258 | } |
431 | } | 259 | } |
432 | 260 | ||
261 | + private ListenableFuture<List<EdgeId>> convertToEdgeIds(ListenableFuture<TimePageData<Edge>> future) { | ||
262 | + return Futures.transform(future, edges -> { | ||
263 | + if (edges != null && edges.getData() != null && !edges.getData().isEmpty()) { | ||
264 | + return edges.getData().stream().map(IdBased::getId).collect(Collectors.toList()); | ||
265 | + } else { | ||
266 | + return Collections.emptyList(); | ||
267 | + } | ||
268 | + }, dbCallbackExecutorService); | ||
269 | + } | ||
433 | 270 | ||
434 | private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { | 271 | private EdgeEventType getEdgeQueueTypeByEntityType(EntityType entityType) { |
435 | switch (entityType) { | 272 | switch (entityType) { |
@@ -446,3 +283,4 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | @@ -446,3 +283,4 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
446 | } | 283 | } |
447 | } | 284 | } |
448 | 285 | ||
286 | + |
@@ -31,11 +31,14 @@ import org.thingsboard.server.dao.device.DeviceService; | @@ -31,11 +31,14 @@ import org.thingsboard.server.dao.device.DeviceService; | ||
31 | import org.thingsboard.server.dao.edge.EdgeService; | 31 | import org.thingsboard.server.dao.edge.EdgeService; |
32 | import org.thingsboard.server.dao.entityview.EntityViewService; | 32 | import org.thingsboard.server.dao.entityview.EntityViewService; |
33 | import org.thingsboard.server.dao.relation.RelationService; | 33 | import org.thingsboard.server.dao.relation.RelationService; |
34 | +import org.thingsboard.server.dao.rule.RuleChainService; | ||
35 | +import org.thingsboard.server.dao.user.UserService; | ||
34 | import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings; | 36 | import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings; |
35 | import org.thingsboard.server.service.edge.rpc.constructor.AlarmUpdateMsgConstructor; | 37 | import org.thingsboard.server.service.edge.rpc.constructor.AlarmUpdateMsgConstructor; |
36 | import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor; | 38 | import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor; |
37 | import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor; | 39 | import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor; |
38 | import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor; | 40 | import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor; |
41 | +import org.thingsboard.server.service.edge.rpc.constructor.EntityDataMsgConstructor; | ||
39 | import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor; | 42 | import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor; |
40 | import org.thingsboard.server.service.edge.rpc.constructor.RelationUpdateMsgConstructor; | 43 | import org.thingsboard.server.service.edge.rpc.constructor.RelationUpdateMsgConstructor; |
41 | import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor; | 44 | import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor; |
@@ -95,6 +98,14 @@ public class EdgeContextComponent { | @@ -95,6 +98,14 @@ public class EdgeContextComponent { | ||
95 | 98 | ||
96 | @Lazy | 99 | @Lazy |
97 | @Autowired | 100 | @Autowired |
101 | + private RuleChainService ruleChainService; | ||
102 | + | ||
103 | + @Lazy | ||
104 | + @Autowired | ||
105 | + private UserService userService; | ||
106 | + | ||
107 | + @Lazy | ||
108 | + @Autowired | ||
98 | private ActorService actorService; | 109 | private ActorService actorService; |
99 | 110 | ||
100 | @Lazy | 111 | @Lazy |
@@ -143,6 +154,10 @@ public class EdgeContextComponent { | @@ -143,6 +154,10 @@ public class EdgeContextComponent { | ||
143 | 154 | ||
144 | @Lazy | 155 | @Lazy |
145 | @Autowired | 156 | @Autowired |
157 | + private EntityDataMsgConstructor entityDataMsgConstructor; | ||
158 | + | ||
159 | + @Lazy | ||
160 | + @Autowired | ||
146 | private EdgeEventStorageSettings edgeEventStorageSettings; | 161 | private EdgeEventStorageSettings edgeEventStorageSettings; |
147 | 162 | ||
148 | @Autowired | 163 | @Autowired |
@@ -19,15 +19,17 @@ import com.datastax.driver.core.utils.UUIDs; | @@ -19,15 +19,17 @@ import com.datastax.driver.core.utils.UUIDs; | ||
19 | import com.fasterxml.jackson.core.JsonProcessingException; | 19 | import com.fasterxml.jackson.core.JsonProcessingException; |
20 | import com.fasterxml.jackson.databind.ObjectMapper; | 20 | import com.fasterxml.jackson.databind.ObjectMapper; |
21 | import com.fasterxml.jackson.databind.node.ObjectNode; | 21 | import com.fasterxml.jackson.databind.node.ObjectNode; |
22 | +import com.google.common.util.concurrent.FutureCallback; | ||
22 | import com.google.common.util.concurrent.Futures; | 23 | import com.google.common.util.concurrent.Futures; |
23 | import com.google.common.util.concurrent.ListenableFuture; | 24 | import com.google.common.util.concurrent.ListenableFuture; |
24 | import com.google.common.util.concurrent.MoreExecutors; | 25 | import com.google.common.util.concurrent.MoreExecutors; |
25 | -import com.google.protobuf.ByteString; | 26 | +import com.google.gson.Gson; |
27 | +import com.google.gson.JsonElement; | ||
28 | +import com.google.gson.JsonObject; | ||
26 | import io.grpc.stub.StreamObserver; | 29 | import io.grpc.stub.StreamObserver; |
27 | import lombok.Data; | 30 | import lombok.Data; |
28 | import lombok.extern.slf4j.Slf4j; | 31 | import lombok.extern.slf4j.Slf4j; |
29 | -import org.apache.commons.codec.binary.Base64; | ||
30 | -import org.thingsboard.server.common.data.Customer; | 32 | +import org.checkerframework.checker.nullness.qual.Nullable; |
31 | import org.thingsboard.server.common.data.Dashboard; | 33 | import org.thingsboard.server.common.data.Dashboard; |
32 | import org.thingsboard.server.common.data.DataConstants; | 34 | import org.thingsboard.server.common.data.DataConstants; |
33 | import org.thingsboard.server.common.data.Device; | 35 | import org.thingsboard.server.common.data.Device; |
@@ -41,12 +43,16 @@ import org.thingsboard.server.common.data.asset.Asset; | @@ -41,12 +43,16 @@ import org.thingsboard.server.common.data.asset.Asset; | ||
41 | import org.thingsboard.server.common.data.audit.ActionType; | 43 | import org.thingsboard.server.common.data.audit.ActionType; |
42 | import org.thingsboard.server.common.data.edge.Edge; | 44 | import org.thingsboard.server.common.data.edge.Edge; |
43 | import org.thingsboard.server.common.data.edge.EdgeEvent; | 45 | import org.thingsboard.server.common.data.edge.EdgeEvent; |
46 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
44 | import org.thingsboard.server.common.data.id.AssetId; | 47 | import org.thingsboard.server.common.data.id.AssetId; |
48 | +import org.thingsboard.server.common.data.id.DashboardId; | ||
45 | import org.thingsboard.server.common.data.id.DeviceId; | 49 | import org.thingsboard.server.common.data.id.DeviceId; |
46 | import org.thingsboard.server.common.data.id.EdgeId; | 50 | import org.thingsboard.server.common.data.id.EdgeId; |
47 | import org.thingsboard.server.common.data.id.EntityId; | 51 | import org.thingsboard.server.common.data.id.EntityId; |
48 | import org.thingsboard.server.common.data.id.EntityViewId; | 52 | import org.thingsboard.server.common.data.id.EntityViewId; |
53 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
49 | import org.thingsboard.server.common.data.id.TenantId; | 54 | import org.thingsboard.server.common.data.id.TenantId; |
55 | +import org.thingsboard.server.common.data.id.UserId; | ||
50 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 56 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
51 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | 57 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
52 | import org.thingsboard.server.common.data.kv.DataType; | 58 | import org.thingsboard.server.common.data.kv.DataType; |
@@ -60,14 +66,13 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | @@ -60,14 +66,13 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | ||
60 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 66 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
61 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; | 67 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
62 | import org.thingsboard.server.common.msg.TbMsg; | 68 | import org.thingsboard.server.common.msg.TbMsg; |
63 | -import org.thingsboard.server.common.msg.TbMsgDataType; | ||
64 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 69 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
65 | -import org.thingsboard.server.common.msg.queue.TbMsgCallback; | 70 | +import org.thingsboard.server.common.msg.session.SessionMsgType; |
71 | +import org.thingsboard.server.common.transport.util.JsonUtils; | ||
66 | import org.thingsboard.server.gen.edge.AlarmUpdateMsg; | 72 | import org.thingsboard.server.gen.edge.AlarmUpdateMsg; |
67 | import org.thingsboard.server.gen.edge.ConnectRequestMsg; | 73 | import org.thingsboard.server.gen.edge.ConnectRequestMsg; |
68 | import org.thingsboard.server.gen.edge.ConnectResponseCode; | 74 | import org.thingsboard.server.gen.edge.ConnectResponseCode; |
69 | import org.thingsboard.server.gen.edge.ConnectResponseMsg; | 75 | import org.thingsboard.server.gen.edge.ConnectResponseMsg; |
70 | -import org.thingsboard.server.gen.edge.CustomerUpdateMsg; | ||
71 | import org.thingsboard.server.gen.edge.DeviceUpdateMsg; | 76 | import org.thingsboard.server.gen.edge.DeviceUpdateMsg; |
72 | import org.thingsboard.server.gen.edge.DownlinkMsg; | 77 | import org.thingsboard.server.gen.edge.DownlinkMsg; |
73 | import org.thingsboard.server.gen.edge.EdgeConfiguration; | 78 | import org.thingsboard.server.gen.edge.EdgeConfiguration; |
@@ -81,7 +86,7 @@ import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg; | @@ -81,7 +86,7 @@ import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg; | ||
81 | import org.thingsboard.server.gen.edge.UpdateMsgType; | 86 | import org.thingsboard.server.gen.edge.UpdateMsgType; |
82 | import org.thingsboard.server.gen.edge.UplinkMsg; | 87 | import org.thingsboard.server.gen.edge.UplinkMsg; |
83 | import org.thingsboard.server.gen.edge.UplinkResponseMsg; | 88 | import org.thingsboard.server.gen.edge.UplinkResponseMsg; |
84 | -import org.thingsboard.server.gen.edge.UserUpdateMsg; | 89 | +import org.thingsboard.server.gen.transport.TransportProtos; |
85 | import org.thingsboard.server.service.edge.EdgeContextComponent; | 90 | import org.thingsboard.server.service.edge.EdgeContextComponent; |
86 | 91 | ||
87 | import java.io.Closeable; | 92 | import java.io.Closeable; |
@@ -103,6 +108,8 @@ public final class EdgeGrpcSession implements Closeable { | @@ -103,6 +108,8 @@ public final class EdgeGrpcSession implements Closeable { | ||
103 | 108 | ||
104 | private static final ReentrantLock deviceCreationLock = new ReentrantLock(); | 109 | private static final ReentrantLock deviceCreationLock = new ReentrantLock(); |
105 | 110 | ||
111 | + private final Gson gson = new Gson(); | ||
112 | + | ||
106 | private static final String QUEUE_START_TS_ATTR_KEY = "queueStartTs"; | 113 | private static final String QUEUE_START_TS_ATTR_KEY = "queueStartTs"; |
107 | 114 | ||
108 | private final UUID sessionId; | 115 | private final UUID sessionId; |
@@ -182,9 +189,9 @@ public final class EdgeGrpcSession implements Closeable { | @@ -182,9 +189,9 @@ public final class EdgeGrpcSession implements Closeable { | ||
182 | processTelemetryMessage(edgeEvent); | 189 | processTelemetryMessage(edgeEvent); |
183 | } else { | 190 | } else { |
184 | processEntityCRUDMessage(edgeEvent, msgType); | 191 | processEntityCRUDMessage(edgeEvent, msgType); |
185 | - } | ||
186 | - if (ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) { | ||
187 | - pushEntityAttributesToEdge(edgeEvent); | 192 | + if (ENTITY_CREATED_RPC_MESSAGE.equals(msgType)) { |
193 | + pushEntityAttributesToEdge(edgeEvent); | ||
194 | + } | ||
188 | } | 195 | } |
189 | } catch (Exception e) { | 196 | } catch (Exception e) { |
190 | log.error("Exception during processing records from queue", e); | 197 | log.error("Exception during processing records from queue", e); |
@@ -213,63 +220,66 @@ public final class EdgeGrpcSession implements Closeable { | @@ -213,63 +220,66 @@ public final class EdgeGrpcSession implements Closeable { | ||
213 | } | 220 | } |
214 | } | 221 | } |
215 | 222 | ||
223 | + private ListenableFuture<Long> getQueueStartTs() { | ||
224 | + ListenableFuture<Optional<AttributeKvEntry>> future = | ||
225 | + ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, QUEUE_START_TS_ATTR_KEY); | ||
226 | + return Futures.transform(future, attributeKvEntryOpt -> { | ||
227 | + if (attributeKvEntryOpt != null && attributeKvEntryOpt.isPresent()) { | ||
228 | + AttributeKvEntry attributeKvEntry = attributeKvEntryOpt.get(); | ||
229 | + return attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L; | ||
230 | + } else { | ||
231 | + return 0L; | ||
232 | + } | ||
233 | + }, MoreExecutors.directExecutor()); | ||
234 | + } | ||
235 | + | ||
236 | + private void updateQueueStartTs(Long newStartTs) { | ||
237 | + newStartTs = ++newStartTs; // increments ts by 1 - next edge event search starts from current offset + 1 | ||
238 | + List<AttributeKvEntry> attributes = Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(QUEUE_START_TS_ATTR_KEY, newStartTs), System.currentTimeMillis())); | ||
239 | + ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); | ||
240 | + } | ||
241 | + | ||
216 | private void pushEntityAttributesToEdge(EdgeEvent edgeEvent) throws IOException { | 242 | private void pushEntityAttributesToEdge(EdgeEvent edgeEvent) throws IOException { |
217 | EntityId entityId = null; | 243 | EntityId entityId = null; |
218 | - String entityName = null; | ||
219 | switch (edgeEvent.getEdgeEventType()) { | 244 | switch (edgeEvent.getEdgeEventType()) { |
220 | case EDGE: | 245 | case EDGE: |
221 | - Edge edge = objectMapper.readValue(entry.getData(), Edge.class); | ||
222 | entityId = edge.getId(); | 246 | entityId = edge.getId(); |
223 | - entityName = edge.getName(); | ||
224 | break; | 247 | break; |
225 | case DEVICE: | 248 | case DEVICE: |
226 | - Device device = objectMapper.readValue(entry.getData(), Device.class); | ||
227 | - entityId = device.getId(); | ||
228 | - entityName = device.getName(); | 249 | + entityId = new DeviceId(edgeEvent.getEntityId()); |
229 | break; | 250 | break; |
230 | case ASSET: | 251 | case ASSET: |
231 | - Asset asset = objectMapper.readValue(entry.getData(), Asset.class); | ||
232 | - entityId = asset.getId(); | ||
233 | - entityName = asset.getName(); | 252 | + entityId = new AssetId(edgeEvent.getEntityId()); |
234 | break; | 253 | break; |
235 | case ENTITY_VIEW: | 254 | case ENTITY_VIEW: |
236 | - EntityView entityView = objectMapper.readValue(entry.getData(), EntityView.class); | ||
237 | - entityId = entityView.getId(); | ||
238 | - entityName = entityView.getName(); | 255 | + entityId = new EntityViewId(edgeEvent.getEntityId()); |
239 | break; | 256 | break; |
240 | case DASHBOARD: | 257 | case DASHBOARD: |
241 | - Dashboard dashboard = objectMapper.readValue(entry.getData(), Dashboard.class); | ||
242 | - entityId = dashboard.getId(); | ||
243 | - entityName = dashboard.getName(); | 258 | + entityId = new DashboardId(edgeEvent.getEntityId()); |
244 | break; | 259 | break; |
245 | } | 260 | } |
246 | if (entityId != null) { | 261 | if (entityId != null) { |
247 | final EntityId finalEntityId = entityId; | 262 | final EntityId finalEntityId = entityId; |
248 | - final String finalEntityName = entityName; | ||
249 | ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.SERVER_SCOPE); | 263 | ListenableFuture<List<AttributeKvEntry>> ssAttrFuture = ctx.getAttributesService().findAll(edge.getTenantId(), entityId, DataConstants.SERVER_SCOPE); |
250 | Futures.transform(ssAttrFuture, ssAttributes -> { | 264 | Futures.transform(ssAttrFuture, ssAttributes -> { |
251 | if (ssAttributes != null && !ssAttributes.isEmpty()) { | 265 | if (ssAttributes != null && !ssAttributes.isEmpty()) { |
252 | try { | 266 | try { |
253 | - TbMsgMetaData metaData = new TbMsgMetaData(); | ||
254 | ObjectNode entityNode = objectMapper.createObjectNode(); | 267 | ObjectNode entityNode = objectMapper.createObjectNode(); |
255 | - metaData.putValue("scope", DataConstants.SERVER_SCOPE); | ||
256 | for (AttributeKvEntry attr : ssAttributes) { | 268 | for (AttributeKvEntry attr : ssAttributes) { |
257 | - if (attr.getDataType() == DataType.BOOLEAN) { | 269 | + if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) { |
258 | entityNode.put(attr.getKey(), attr.getBooleanValue().get()); | 270 | entityNode.put(attr.getKey(), attr.getBooleanValue().get()); |
259 | - } else if (attr.getDataType() == DataType.DOUBLE) { | 271 | + } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) { |
260 | entityNode.put(attr.getKey(), attr.getDoubleValue().get()); | 272 | entityNode.put(attr.getKey(), attr.getDoubleValue().get()); |
261 | - } else if (attr.getDataType() == DataType.LONG) { | 273 | + } else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) { |
262 | entityNode.put(attr.getKey(), attr.getLongValue().get()); | 274 | entityNode.put(attr.getKey(), attr.getLongValue().get()); |
263 | } else { | 275 | } else { |
264 | entityNode.put(attr.getKey(), attr.getValueAsString()); | 276 | entityNode.put(attr.getKey(), attr.getValueAsString()); |
265 | } | 277 | } |
266 | } | 278 | } |
267 | - TbMsg tbMsg = TbMsg.newMsg(DataConstants.ATTRIBUTES_UPDATED, finalEntityId, metaData, TbMsgDataType.JSON | ||
268 | - , objectMapper.writeValueAsString(entityNode)); | ||
269 | - log.debug("Sending donwlink entity data msg, entityName [{}], tbMsg [{}]", finalEntityName, tbMsg); | 279 | + log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", finalEntityId, entityNode); |
280 | + DownlinkMsg value = constructEntityDataProtoMsg(finalEntityId, ActionType.ATTRIBUTES_UPDATED, JsonUtils.parse(objectMapper.writeValueAsString(entityNode))); | ||
270 | outputStream.onNext(ResponseMsg.newBuilder() | 281 | outputStream.onNext(ResponseMsg.newBuilder() |
271 | - .setDownlinkMsg(constructEntityDataProtoMsg(finalEntityName, finalEntityId, tbMsg)) | ||
272 | - .build()); | 282 | + .setDownlinkMsg(value).build()); |
273 | } catch (Exception e) { | 283 | } catch (Exception e) { |
274 | log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e); | 284 | log.error("[{}] Failed to send attribute updates to the edge", edge.getName(), e); |
275 | } | 285 | } |
@@ -283,188 +293,276 @@ public final class EdgeGrpcSession implements Closeable { | @@ -283,188 +293,276 @@ public final class EdgeGrpcSession implements Closeable { | ||
283 | 293 | ||
284 | private void processTelemetryMessage(EdgeEvent edgeEvent) throws IOException { | 294 | private void processTelemetryMessage(EdgeEvent edgeEvent) throws IOException { |
285 | log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent); | 295 | log.trace("Executing processTelemetryMessage, edgeEvent [{}]", edgeEvent); |
286 | - TbMsg tbMsg = TbMsg.fromBytes(Base64.decodeBase64(entry.getData()), TbMsgCallback.EMPTY); | ||
287 | - String entityName = null; | ||
288 | EntityId entityId = null; | 296 | EntityId entityId = null; |
289 | switch (edgeEvent.getEdgeEventType()) { | 297 | switch (edgeEvent.getEdgeEventType()) { |
290 | case DEVICE: | 298 | case DEVICE: |
291 | - Device device = ctx.getDeviceService().findDeviceById(edge.getTenantId(), new DeviceId(tbMsg.getOriginator().getId())); | ||
292 | - entityName = device.getName(); | ||
293 | - entityId = device.getId(); | 299 | + entityId = new DeviceId(edgeEvent.getEntityId()); |
294 | break; | 300 | break; |
295 | case ASSET: | 301 | case ASSET: |
296 | - Asset asset = ctx.getAssetService().findAssetById(edge.getTenantId(), new AssetId(tbMsg.getOriginator().getId())); | ||
297 | - entityName = asset.getName(); | ||
298 | - entityId = asset.getId(); | 302 | + entityId = new AssetId(edgeEvent.getEntityId()); |
299 | break; | 303 | break; |
300 | case ENTITY_VIEW: | 304 | case ENTITY_VIEW: |
301 | - EntityView entityView = ctx.getEntityViewService().findEntityViewById(edge.getTenantId(), new EntityViewId(tbMsg.getOriginator().getId())); | ||
302 | - entityName = entityView.getName(); | ||
303 | - entityId = entityView.getId(); | 305 | + entityId = new EntityViewId(edgeEvent.getEntityId()); |
304 | break; | 306 | break; |
305 | 307 | ||
306 | } | 308 | } |
307 | - if (entityName != null && entityId != null) { | ||
308 | - log.debug("Sending downlink entity data msg, entityName [{}], tbMsg [{}]", entityName, tbMsg); | ||
309 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
310 | - .setDownlinkMsg(constructEntityDataProtoMsg(entityName, entityId, tbMsg)) | ||
311 | - .build()); | 309 | + if (entityId != null) { |
310 | + log.debug("Sending telemetry data msg, entityId [{}], body [{}]", edgeEvent.getEntityId(), edgeEvent.getEntityBody()); | ||
311 | + DownlinkMsg downlinkMsg; | ||
312 | + try { | ||
313 | + ActionType actionType = ActionType.valueOf(edgeEvent.getEdgeEventAction()); | ||
314 | + downlinkMsg = constructEntityDataProtoMsg(entityId, actionType, JsonUtils.parse(objectMapper.writeValueAsString(edgeEvent.getEntityBody()))); | ||
315 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
316 | + .setDownlinkMsg(downlinkMsg) | ||
317 | + .build()); | ||
318 | + } catch (Exception e) { | ||
319 | + log.warn("Can't send telemetry data msg, entityId [{}], body [{}]", edgeEvent.getEntityId(), edgeEvent.getEntityBody(), e); | ||
320 | + } | ||
321 | + | ||
312 | } | 322 | } |
313 | } | 323 | } |
314 | 324 | ||
315 | - private void processEntityCRUDMessage(EdgeEvent edgeEvent, UpdateMsgType msgType) throws java.io.IOException { | 325 | + private void processEntityCRUDMessage(EdgeEvent edgeEvent, UpdateMsgType msgType) { |
316 | log.trace("Executing processEntityCRUDMessage, edgeEvent [{}], msgType [{}]", edgeEvent, msgType); | 326 | log.trace("Executing processEntityCRUDMessage, edgeEvent [{}], msgType [{}]", edgeEvent, msgType); |
317 | switch (edgeEvent.getEdgeEventType()) { | 327 | switch (edgeEvent.getEdgeEventType()) { |
318 | case EDGE: | 328 | case EDGE: |
319 | - Edge edge = objectMapper.readValue(entry.getData(), Edge.class); | ||
320 | - onEdgeUpdated(msgType, edge); | 329 | + // TODO: voba - add edge update logic |
321 | break; | 330 | break; |
322 | case DEVICE: | 331 | case DEVICE: |
323 | - Device device = objectMapper.readValue(entry.getData(), Device.class); | ||
324 | - onDeviceUpdated(msgType, device); | 332 | + processDeviceCRUD(edgeEvent, msgType); |
325 | break; | 333 | break; |
326 | case ASSET: | 334 | case ASSET: |
327 | - Asset asset = objectMapper.readValue(entry.getData(), Asset.class); | ||
328 | - onAssetUpdated(msgType, asset); | 335 | + processAssetCRUD(edgeEvent, msgType); |
329 | break; | 336 | break; |
330 | case ENTITY_VIEW: | 337 | case ENTITY_VIEW: |
331 | - EntityView entityView = objectMapper.readValue(entry.getData(), EntityView.class); | ||
332 | - onEntityViewUpdated(msgType, entityView); | 338 | + processEntityViewCRUD(edgeEvent, msgType); |
333 | break; | 339 | break; |
334 | case DASHBOARD: | 340 | case DASHBOARD: |
335 | - Dashboard dashboard = objectMapper.readValue(entry.getData(), Dashboard.class); | ||
336 | - onDashboardUpdated(msgType, dashboard); | 341 | + processDashboardCRUD(edgeEvent, msgType); |
337 | break; | 342 | break; |
338 | case RULE_CHAIN: | 343 | case RULE_CHAIN: |
339 | - RuleChain ruleChain = objectMapper.readValue(entry.getData(), RuleChain.class); | ||
340 | - onRuleChainUpdated(msgType, ruleChain); | 344 | + processRuleChainCRUD(edgeEvent, msgType); |
341 | break; | 345 | break; |
342 | case RULE_CHAIN_METADATA: | 346 | case RULE_CHAIN_METADATA: |
343 | - RuleChainMetaData ruleChainMetaData = objectMapper.readValue(entry.getData(), RuleChainMetaData.class); | ||
344 | - onRuleChainMetadataUpdated(msgType, ruleChainMetaData); | 347 | + processRuleChainMetadataCRUD(edgeEvent, msgType); |
345 | break; | 348 | break; |
346 | case ALARM: | 349 | case ALARM: |
347 | - Alarm alarm = objectMapper.readValue(entry.getData(), Alarm.class); | ||
348 | - onAlarmUpdated(msgType, alarm); | 350 | + processAlarmCRUD(edgeEvent, msgType); |
349 | break; | 351 | break; |
350 | case USER: | 352 | case USER: |
351 | - User user = objectMapper.readValue(entry.getData(), User.class); | ||
352 | - onUserUpdated(msgType, user); | 353 | + processUserCRUD(edgeEvent, msgType); |
353 | break; | 354 | break; |
354 | case RELATION: | 355 | case RELATION: |
355 | - EntityRelation entityRelation = objectMapper.readValue(entry.getData(), EntityRelation.class); | ||
356 | - onEntityRelationUpdated(msgType, entityRelation); | 356 | + processRelationCRUD(edgeEvent, msgType); |
357 | break; | 357 | break; |
358 | } | 358 | } |
359 | } | 359 | } |
360 | 360 | ||
361 | - private void updateQueueStartTs(Long newStartTs) { | ||
362 | - newStartTs = ++newStartTs; // increments ts by 1 - next edge event search starts from current offset + 1 | ||
363 | - List<AttributeKvEntry> attributes = Collections.singletonList(new BaseAttributeKvEntry(new LongDataEntry(QUEUE_START_TS_ATTR_KEY, newStartTs), System.currentTimeMillis())); | ||
364 | - ctx.getAttributesService().save(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, attributes); | ||
365 | - } | ||
366 | - | ||
367 | - private ListenableFuture<Long> getQueueStartTs() { | ||
368 | - ListenableFuture<Optional<AttributeKvEntry>> future = | ||
369 | - ctx.getAttributesService().find(edge.getTenantId(), edge.getId(), DataConstants.SERVER_SCOPE, QUEUE_START_TS_ATTR_KEY); | ||
370 | - return Futures.transform(future, attributeKvEntryOpt -> { | ||
371 | - if (attributeKvEntryOpt != null && attributeKvEntryOpt.isPresent()) { | ||
372 | - AttributeKvEntry attributeKvEntry = attributeKvEntryOpt.get(); | ||
373 | - return attributeKvEntry.getLongValue().isPresent() ? attributeKvEntry.getLongValue().get() : 0L; | ||
374 | - } else { | ||
375 | - return 0L; | ||
376 | - } | ||
377 | - }, MoreExecutors.directExecutor()); | ||
378 | - } | 361 | + private void processDeviceCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { |
362 | + DeviceId deviceId = new DeviceId(edgeEvent.getEntityId()); | ||
363 | + ListenableFuture<Device> deviceFuture = ctx.getDeviceService().findDeviceByIdAsync(edgeEvent.getTenantId(), deviceId); | ||
364 | + Futures.addCallback(deviceFuture, | ||
365 | + new FutureCallback<Device>() { | ||
366 | + @Override | ||
367 | + public void onSuccess(@Nullable Device device) { | ||
368 | + if (device != null) { | ||
369 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
370 | + .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device)) | ||
371 | + .build(); | ||
372 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
373 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
374 | + .build()); | ||
375 | + } | ||
376 | + } | ||
379 | 377 | ||
380 | - private void onEdgeUpdated(UpdateMsgType msgType, Edge edge) { | ||
381 | - // TODO: voba add configuration update to edge | ||
382 | - this.edge = edge; | ||
383 | - } | 378 | + @Override |
379 | + public void onFailure(Throwable t) { | ||
380 | + log.warn("Can't processDeviceCRUD, edgeEvent [{}]", edgeEvent, t); | ||
381 | + } | ||
382 | + }, ctx.getDbCallbackExecutor()); | ||
383 | + } | ||
384 | + | ||
385 | + private void processAssetCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { | ||
386 | + AssetId assetId = new AssetId(edgeEvent.getEntityId()); | ||
387 | + ListenableFuture<Asset> assetFuture = ctx.getAssetService().findAssetByIdAsync(edgeEvent.getTenantId(), assetId); | ||
388 | + Futures.addCallback(assetFuture, | ||
389 | + new FutureCallback<Asset>() { | ||
390 | + @Override | ||
391 | + public void onSuccess(@Nullable Asset asset) { | ||
392 | + if (asset != null) { | ||
393 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
394 | + .setAssetUpdateMsg(ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset)) | ||
395 | + .build(); | ||
396 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
397 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
398 | + .build()); | ||
399 | + } | ||
400 | + } | ||
384 | 401 | ||
385 | - private void onDeviceUpdated(UpdateMsgType msgType, Device device) { | ||
386 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
387 | - .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device)) | ||
388 | - .build(); | ||
389 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
390 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
391 | - .build()); | ||
392 | - } | 402 | + @Override |
403 | + public void onFailure(Throwable t) { | ||
404 | + log.warn("Can't processAssetCRUD, edgeEvent [{}]", edgeEvent, t); | ||
405 | + } | ||
406 | + }, ctx.getDbCallbackExecutor()); | ||
407 | + } | ||
408 | + | ||
409 | + private void processEntityViewCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { | ||
410 | + EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId()); | ||
411 | + ListenableFuture<EntityView> entityViewFuture = ctx.getEntityViewService().findEntityViewByIdAsync(edgeEvent.getTenantId(), entityViewId); | ||
412 | + Futures.addCallback(entityViewFuture, | ||
413 | + new FutureCallback<EntityView>() { | ||
414 | + @Override | ||
415 | + public void onSuccess(@Nullable EntityView entityView) { | ||
416 | + if (entityView != null) { | ||
417 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
418 | + .setEntityViewUpdateMsg(ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView)) | ||
419 | + .build(); | ||
420 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
421 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
422 | + .build()); | ||
423 | + } | ||
424 | + } | ||
393 | 425 | ||
394 | - private void onAssetUpdated(UpdateMsgType msgType, Asset asset) { | ||
395 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
396 | - .setAssetUpdateMsg(ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset)) | ||
397 | - .build(); | ||
398 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
399 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
400 | - .build()); | ||
401 | - } | 426 | + @Override |
427 | + public void onFailure(Throwable t) { | ||
428 | + log.warn("Can't processEntityViewCRUD, edgeEvent [{}]", edgeEvent, t); | ||
429 | + } | ||
430 | + }, ctx.getDbCallbackExecutor()); | ||
431 | + } | ||
432 | + | ||
433 | + private void processDashboardCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { | ||
434 | + DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId()); | ||
435 | + ListenableFuture<Dashboard> dashboardFuture = ctx.getDashboardService().findDashboardByIdAsync(edgeEvent.getTenantId(), dashboardId); | ||
436 | + Futures.addCallback(dashboardFuture, | ||
437 | + new FutureCallback<Dashboard>() { | ||
438 | + @Override | ||
439 | + public void onSuccess(@Nullable Dashboard dashboard) { | ||
440 | + if (dashboard != null) { | ||
441 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
442 | + .setDashboardUpdateMsg(ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard)) | ||
443 | + .build(); | ||
444 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
445 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
446 | + .build()); | ||
447 | + } | ||
448 | + } | ||
402 | 449 | ||
403 | - private void onEntityViewUpdated(UpdateMsgType msgType, EntityView entityView) { | ||
404 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
405 | - .setEntityViewUpdateMsg(ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView)) | ||
406 | - .build(); | ||
407 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
408 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
409 | - .build()); | ||
410 | - } | 450 | + @Override |
451 | + public void onFailure(Throwable t) { | ||
452 | + log.warn("Can't processDashboardCRUD, edgeEvent [{}]", edgeEvent, t); | ||
453 | + } | ||
454 | + }, ctx.getDbCallbackExecutor()); | ||
455 | + } | ||
456 | + | ||
457 | + private void processRuleChainCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { | ||
458 | + RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId()); | ||
459 | + ListenableFuture<RuleChain> ruleChainFuture = ctx.getRuleChainService().findRuleChainByIdAsync(edgeEvent.getTenantId(), ruleChainId); | ||
460 | + Futures.addCallback(ruleChainFuture, | ||
461 | + new FutureCallback<RuleChain>() { | ||
462 | + @Override | ||
463 | + public void onSuccess(@Nullable RuleChain ruleChain) { | ||
464 | + if (ruleChain != null) { | ||
465 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
466 | + .setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain)) | ||
467 | + .build(); | ||
468 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
469 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
470 | + .build()); | ||
471 | + } | ||
472 | + } | ||
411 | 473 | ||
412 | - private void onRuleChainUpdated(UpdateMsgType msgType, RuleChain ruleChain) { | ||
413 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
414 | - .setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain)) | ||
415 | - .build(); | ||
416 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
417 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
418 | - .build()); | ||
419 | - } | 474 | + @Override |
475 | + public void onFailure(Throwable t) { | ||
476 | + log.warn("Can't processRuleChainCRUD, edgeEvent [{}]", edgeEvent, t); | ||
477 | + } | ||
478 | + }, ctx.getDbCallbackExecutor()); | ||
479 | + } | ||
480 | + | ||
481 | + private void processRuleChainMetadataCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { | ||
482 | + RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId()); | ||
483 | + ListenableFuture<RuleChain> ruleChainFuture = ctx.getRuleChainService().findRuleChainByIdAsync(edgeEvent.getTenantId(), ruleChainId); | ||
484 | + Futures.addCallback(ruleChainFuture, | ||
485 | + new FutureCallback<RuleChain>() { | ||
486 | + @Override | ||
487 | + public void onSuccess(@Nullable RuleChain ruleChain) { | ||
488 | + if (ruleChain != null) { | ||
489 | + RuleChainMetaData ruleChainMetaData = ctx.getRuleChainService().loadRuleChainMetaData(edgeEvent.getTenantId(), ruleChainId); | ||
490 | + RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = | ||
491 | + ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData); | ||
492 | + if (ruleChainMetadataUpdateMsg != null) { | ||
493 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
494 | + .setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg) | ||
495 | + .build(); | ||
496 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
497 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
498 | + .build()); | ||
499 | + } | ||
500 | + } | ||
501 | + } | ||
420 | 502 | ||
421 | - private void onRuleChainMetadataUpdated(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) { | ||
422 | - RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = | ||
423 | - ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData); | ||
424 | - if (ruleChainMetadataUpdateMsg != null) { | ||
425 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
426 | - .setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg) | ||
427 | - .build(); | ||
428 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
429 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
430 | - .build()); | ||
431 | - } | ||
432 | - } | 503 | + @Override |
504 | + public void onFailure(Throwable t) { | ||
505 | + log.warn("Can't processRuleChainMetadataCRUD, edgeEvent [{}]", edgeEvent, t); | ||
506 | + } | ||
507 | + }, ctx.getDbCallbackExecutor()); | ||
508 | + } | ||
509 | + | ||
510 | + private void processUserCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { | ||
511 | + UserId userId = new UserId(edgeEvent.getEntityId()); | ||
512 | + ListenableFuture<User> userFuture = ctx.getUserService().findUserByIdAsync(edgeEvent.getTenantId(), userId); | ||
513 | + Futures.addCallback(userFuture, | ||
514 | + new FutureCallback<User>() { | ||
515 | + @Override | ||
516 | + public void onSuccess(@Nullable User user) { | ||
517 | + if (user != null) { | ||
518 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
519 | + .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user)) | ||
520 | + .build(); | ||
521 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
522 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
523 | + .build()); | ||
524 | + } | ||
525 | + } | ||
433 | 526 | ||
434 | - private void onDashboardUpdated(UpdateMsgType msgType, Dashboard dashboard) { | ||
435 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
436 | - .setDashboardUpdateMsg(ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard)) | ||
437 | - .build(); | ||
438 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
439 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
440 | - .build()); | 527 | + @Override |
528 | + public void onFailure(Throwable t) { | ||
529 | + log.warn("Can't processUserCRUD, edgeEvent [{}]", edgeEvent, t); | ||
530 | + } | ||
531 | + }, ctx.getDbCallbackExecutor()); | ||
441 | } | 532 | } |
442 | 533 | ||
443 | - private void onAlarmUpdated(UpdateMsgType msgType, Alarm alarm) { | 534 | + private void processRelationCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { |
535 | + EntityRelation entityRelation = objectMapper.convertValue(edgeEvent.getEntityBody(), EntityRelation.class); | ||
444 | EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | 536 | EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() |
445 | - .setAlarmUpdateMsg(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm)) | 537 | + .setRelationUpdateMsg(ctx.getRelationUpdateMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation)) |
446 | .build(); | 538 | .build(); |
447 | outputStream.onNext(ResponseMsg.newBuilder() | 539 | outputStream.onNext(ResponseMsg.newBuilder() |
448 | .setEntityUpdateMsg(entityUpdateMsg) | 540 | .setEntityUpdateMsg(entityUpdateMsg) |
449 | .build()); | 541 | .build()); |
450 | } | 542 | } |
451 | 543 | ||
452 | - private void onUserUpdated(UpdateMsgType msgType, User user) { | ||
453 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
454 | - .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user)) | ||
455 | - .build(); | ||
456 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
457 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
458 | - .build()); | ||
459 | - } | 544 | + private void processAlarmCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) { |
545 | + AlarmId alarmId = new AlarmId(edgeEvent.getEntityId()); | ||
546 | + ListenableFuture<Alarm> alarmFuture = ctx.getAlarmService().findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId); | ||
547 | + Futures.addCallback(alarmFuture, | ||
548 | + new FutureCallback<Alarm>() { | ||
549 | + @Override | ||
550 | + public void onSuccess(@Nullable Alarm alarm) { | ||
551 | + if (alarm != null) { | ||
552 | + EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
553 | + .setAlarmUpdateMsg(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm)) | ||
554 | + .build(); | ||
555 | + outputStream.onNext(ResponseMsg.newBuilder() | ||
556 | + .setEntityUpdateMsg(entityUpdateMsg) | ||
557 | + .build()); | ||
558 | + } | ||
559 | + } | ||
460 | 560 | ||
461 | - private void onEntityRelationUpdated(UpdateMsgType msgType, EntityRelation entityRelation) { | ||
462 | - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() | ||
463 | - .setRelationUpdateMsg(ctx.getRelationUpdateMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation)) | ||
464 | - .build(); | ||
465 | - outputStream.onNext(ResponseMsg.newBuilder() | ||
466 | - .setEntityUpdateMsg(entityUpdateMsg) | ||
467 | - .build()); | 561 | + @Override |
562 | + public void onFailure(Throwable t) { | ||
563 | + log.warn("Can't processAlarmCRUD, edgeEvent [{}]", edgeEvent, t); | ||
564 | + } | ||
565 | + }, ctx.getDbCallbackExecutor()); | ||
468 | } | 566 | } |
469 | 567 | ||
470 | private UpdateMsgType getResponseMsgType(ActionType actionType) { | 568 | private UpdateMsgType getResponseMsgType(ActionType actionType) { |
@@ -490,29 +588,10 @@ public final class EdgeGrpcSession implements Closeable { | @@ -490,29 +588,10 @@ public final class EdgeGrpcSession implements Closeable { | ||
490 | } | 588 | } |
491 | } | 589 | } |
492 | 590 | ||
493 | - private DownlinkMsg constructEntityDataProtoMsg(String entityName, EntityId entityId, TbMsg tbMsg) { | ||
494 | - EntityDataProto entityData = EntityDataProto.newBuilder() | ||
495 | - .setEntityName(entityName) | ||
496 | - .setTbMsg(ByteString.copyFrom(TbMsg.toByteArray(tbMsg))) | ||
497 | - .setEntityIdMSB(entityId.getId().getMostSignificantBits()) | ||
498 | - .setEntityIdLSB(entityId.getId().getLeastSignificantBits()) | ||
499 | - .build(); | ||
500 | - | 591 | + private DownlinkMsg constructEntityDataProtoMsg(EntityId entityId, ActionType actionType, JsonElement entityData) { |
592 | + EntityDataProto entityDataProto = ctx.getEntityDataMsgConstructor().constructEntityDataMsg(entityId, actionType, entityData); | ||
501 | DownlinkMsg.Builder builder = DownlinkMsg.newBuilder() | 593 | DownlinkMsg.Builder builder = DownlinkMsg.newBuilder() |
502 | - .addAllEntityData(Collections.singletonList(entityData)); | ||
503 | - | ||
504 | - return builder.build(); | ||
505 | - } | ||
506 | - | ||
507 | - private CustomerUpdateMsg constructCustomerUpdatedMsg(UpdateMsgType msgType, Customer customer) { | ||
508 | - CustomerUpdateMsg.Builder builder = CustomerUpdateMsg.newBuilder() | ||
509 | - .setMsgType(msgType); | ||
510 | - return builder.build(); | ||
511 | - } | ||
512 | - | ||
513 | - private UserUpdateMsg constructUserUpdatedMsg(UpdateMsgType msgType, User user) { | ||
514 | - UserUpdateMsg.Builder builder = UserUpdateMsg.newBuilder() | ||
515 | - .setMsgType(msgType); | 594 | + .addAllEntityData(Collections.singletonList(entityDataProto)); |
516 | return builder.build(); | 595 | return builder.build(); |
517 | } | 596 | } |
518 | 597 | ||
@@ -520,20 +599,21 @@ public final class EdgeGrpcSession implements Closeable { | @@ -520,20 +599,21 @@ public final class EdgeGrpcSession implements Closeable { | ||
520 | try { | 599 | try { |
521 | if (uplinkMsg.getEntityDataList() != null && !uplinkMsg.getEntityDataList().isEmpty()) { | 600 | if (uplinkMsg.getEntityDataList() != null && !uplinkMsg.getEntityDataList().isEmpty()) { |
522 | for (EntityDataProto entityData : uplinkMsg.getEntityDataList()) { | 601 | for (EntityDataProto entityData : uplinkMsg.getEntityDataList()) { |
523 | - TbMsg tbMsg = null; | ||
524 | - TbMsg originalTbMsg = TbMsg.fromBytes(entityData.getTbMsg().toByteArray(), TbMsgCallback.EMPTY); | ||
525 | - if (originalTbMsg.getOriginator().getEntityType() == EntityType.DEVICE) { | ||
526 | - String deviceName = entityData.getEntityName(); | ||
527 | - Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName); | ||
528 | - if (device != null) { | ||
529 | - tbMsg = TbMsg.newMsg(originalTbMsg.getType(), device.getId(), originalTbMsg.getMetaData().copy(), | ||
530 | - originalTbMsg.getDataType(), originalTbMsg.getData()); | ||
531 | - } | ||
532 | - } else { | ||
533 | - tbMsg = originalTbMsg; | ||
534 | - } | ||
535 | - if (tbMsg != null) { | ||
536 | - ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, null); | 602 | + EntityId entityId = constructEntityId(entityData); |
603 | + if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg()) && entityId != null) { | ||
604 | + ListenableFuture<TbMsgMetaData> metaDataFuture = constructBaseMsgMetadata(entityId); | ||
605 | + Futures.transform(metaDataFuture, metaData -> { | ||
606 | + if (metaData != null) { | ||
607 | + metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE); | ||
608 | + if (entityData.hasPostAttributesMsg()) { | ||
609 | + processPostAttributes(entityId, entityData.getPostAttributesMsg(), metaData); | ||
610 | + } | ||
611 | + if (entityData.hasPostTelemetryMsg()) { | ||
612 | + processPostTelemetry(entityId, entityData.getPostTelemetryMsg(), metaData); | ||
613 | + } | ||
614 | + } | ||
615 | + return null; | ||
616 | + }, ctx.getDbCallbackExecutor()); | ||
537 | } | 617 | } |
538 | } | 618 | } |
539 | } | 619 | } |
@@ -559,6 +639,78 @@ public final class EdgeGrpcSession implements Closeable { | @@ -559,6 +639,78 @@ public final class EdgeGrpcSession implements Closeable { | ||
559 | return UplinkResponseMsg.newBuilder().setSuccess(true).build(); | 639 | return UplinkResponseMsg.newBuilder().setSuccess(true).build(); |
560 | } | 640 | } |
561 | 641 | ||
642 | + private ListenableFuture<TbMsgMetaData> constructBaseMsgMetadata(EntityId entityId) { | ||
643 | + switch (entityId.getEntityType()) { | ||
644 | + case DEVICE: | ||
645 | + ListenableFuture<Device> deviceFuture = ctx.getDeviceService().findDeviceByIdAsync(edge.getTenantId(), new DeviceId(entityId.getId())); | ||
646 | + return Futures.transform(deviceFuture, device -> { | ||
647 | + TbMsgMetaData metaData = new TbMsgMetaData(); | ||
648 | + if (device != null) { | ||
649 | + metaData.putValue("deviceName", device.getName()); | ||
650 | + metaData.putValue("deviceType", device.getType()); | ||
651 | + } | ||
652 | + return metaData; | ||
653 | + }, ctx.getDbCallbackExecutor()); | ||
654 | + case ASSET: | ||
655 | + ListenableFuture<Asset> assetFuture = ctx.getAssetService().findAssetByIdAsync(edge.getTenantId(), new AssetId(entityId.getId())); | ||
656 | + return Futures.transform(assetFuture, asset -> { | ||
657 | + TbMsgMetaData metaData = new TbMsgMetaData(); | ||
658 | + if (asset != null) { | ||
659 | + metaData.putValue("assetName", asset.getName()); | ||
660 | + metaData.putValue("assetType", asset.getType()); | ||
661 | + } | ||
662 | + return metaData; | ||
663 | + }, ctx.getDbCallbackExecutor()); | ||
664 | + case ENTITY_VIEW: | ||
665 | + ListenableFuture<EntityView> entityViewFuture = ctx.getEntityViewService().findEntityViewByIdAsync(edge.getTenantId(), new EntityViewId(entityId.getId())); | ||
666 | + return Futures.transform(entityViewFuture, entityView -> { | ||
667 | + TbMsgMetaData metaData = new TbMsgMetaData(); | ||
668 | + if (entityView != null) { | ||
669 | + metaData.putValue("entityViewName", entityView.getName()); | ||
670 | + metaData.putValue("entityViewType", entityView.getType()); | ||
671 | + } | ||
672 | + return metaData; | ||
673 | + }, ctx.getDbCallbackExecutor()); | ||
674 | + default: | ||
675 | + log.debug("Constructing empty metadata for entityId [{}]", entityId); | ||
676 | + return Futures.immediateFuture(new TbMsgMetaData()); | ||
677 | + } | ||
678 | + } | ||
679 | + | ||
680 | + private EntityId constructEntityId(EntityDataProto entityData) { | ||
681 | + EntityType entityType = EntityType.valueOf(entityData.getEntityType()); | ||
682 | + switch (entityType) { | ||
683 | + case DEVICE: | ||
684 | + return new DeviceId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); | ||
685 | + case ASSET: | ||
686 | + return new AssetId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); | ||
687 | + case ENTITY_VIEW: | ||
688 | + return new EntityViewId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); | ||
689 | + case DASHBOARD: | ||
690 | + return new DashboardId(new UUID(entityData.getEntityIdMSB(), entityData.getEntityIdLSB())); | ||
691 | + default: | ||
692 | + log.warn("Unsupported entity type [{}] during construct of entity id. EntityDataProto [{}]", entityData.getEntityType(), entityData); | ||
693 | + return null; | ||
694 | + } | ||
695 | + } | ||
696 | + | ||
697 | + private void processPostTelemetry(EntityId entityId, TransportProtos.PostTelemetryMsg msg, TbMsgMetaData metaData) { | ||
698 | + for (TransportProtos.TsKvListProto tsKv : msg.getTsKvListList()) { | ||
699 | + JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); | ||
700 | + metaData.putValue("ts", tsKv.getTs() + ""); | ||
701 | + TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_TELEMETRY_REQUEST.name(), entityId, metaData, gson.toJson(json)); | ||
702 | + // TODO: voba - verify that null callback is OK | ||
703 | + ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, null); | ||
704 | + } | ||
705 | + } | ||
706 | + | ||
707 | + private void processPostAttributes(EntityId entityId, TransportProtos.PostAttributeMsg msg, TbMsgMetaData metaData) { | ||
708 | + JsonObject json = JsonUtils.getJsonObject(msg.getKvList()); | ||
709 | + TbMsg tbMsg = TbMsg.newMsg(SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), entityId, metaData, gson.toJson(json)); | ||
710 | + // TODO: voba - verify that null callback is OK | ||
711 | + ctx.getTbClusterService().pushMsgToRuleEngine(edge.getTenantId(), tbMsg.getOriginator(), tbMsg, null); | ||
712 | + } | ||
713 | + | ||
562 | private void onDeviceUpdate(DeviceUpdateMsg deviceUpdateMsg) { | 714 | private void onDeviceUpdate(DeviceUpdateMsg deviceUpdateMsg) { |
563 | log.info("onDeviceUpdate {}", deviceUpdateMsg); | 715 | log.info("onDeviceUpdate {}", deviceUpdateMsg); |
564 | DeviceId edgeDeviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); | 716 | DeviceId edgeDeviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); |
@@ -759,7 +911,7 @@ public final class EdgeGrpcSession implements Closeable { | @@ -759,7 +911,7 @@ public final class EdgeGrpcSession implements Closeable { | ||
759 | .setTenantIdLSB(edge.getTenantId().getId().getLeastSignificantBits()) | 911 | .setTenantIdLSB(edge.getTenantId().getId().getLeastSignificantBits()) |
760 | .setName(edge.getName()) | 912 | .setName(edge.getName()) |
761 | .setRoutingKey(edge.getRoutingKey()) | 913 | .setRoutingKey(edge.getRoutingKey()) |
762 | - .setType(edge.getType().toString()) | 914 | + .setType(edge.getType()) |
763 | .build(); | 915 | .build(); |
764 | } | 916 | } |
765 | 917 |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.server.service.edge.rpc.constructor; | ||
17 | + | ||
18 | +import com.google.gson.JsonElement; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.springframework.stereotype.Component; | ||
21 | +import org.thingsboard.server.common.data.audit.ActionType; | ||
22 | +import org.thingsboard.server.common.data.id.EntityId; | ||
23 | +import org.thingsboard.server.common.transport.adaptor.JsonConverter; | ||
24 | +import org.thingsboard.server.gen.edge.EntityDataProto; | ||
25 | + | ||
26 | +@Component | ||
27 | +@Slf4j | ||
28 | +public class EntityDataMsgConstructor { | ||
29 | + | ||
30 | + public EntityDataProto constructEntityDataMsg(EntityId entityId, ActionType actionType, JsonElement entityData) { | ||
31 | + EntityDataProto.Builder builder = EntityDataProto.newBuilder() | ||
32 | + .setEntityIdMSB(entityId.getId().getMostSignificantBits()) | ||
33 | + .setEntityIdLSB(entityId.getId().getLeastSignificantBits()) | ||
34 | + .setEntityType(entityId.getEntityType().name()); | ||
35 | + switch (actionType) { | ||
36 | + case TIMESERIES_UPDATED: | ||
37 | + try { | ||
38 | + builder.setPostTelemetryMsg(JsonConverter.convertToTelemetryProto(entityData)); | ||
39 | + } catch (Exception e) { | ||
40 | + log.warn("Can't convert to telemetry proto, entityData [{}]", entityData, e); | ||
41 | + } | ||
42 | + break; | ||
43 | + case ATTRIBUTES_UPDATED: | ||
44 | + try { | ||
45 | + builder.setPostAttributesMsg(JsonConverter.convertToAttributesProto(entityData)); | ||
46 | + } catch (Exception e) { | ||
47 | + log.warn("Can't convert to attributes proto, entityData [{}]", entityData, e); | ||
48 | + } | ||
49 | + break; | ||
50 | + // TODO: voba - add support for attribute delete | ||
51 | + // case ATTRIBUTES_DELETED: | ||
52 | + } | ||
53 | + return builder.build(); | ||
54 | + } | ||
55 | + | ||
56 | +} |
@@ -65,4 +65,7 @@ public class DataConstants { | @@ -65,4 +65,7 @@ public class DataConstants { | ||
65 | public static final String DEFAULT_SECRET_KEY = ""; | 65 | public static final String DEFAULT_SECRET_KEY = ""; |
66 | public static final String SECRET_KEY_FIELD_NAME = "secretKey"; | 66 | public static final String SECRET_KEY_FIELD_NAME = "secretKey"; |
67 | public static final String DURATION_MS_FIELD_NAME = "durationMs"; | 67 | public static final String DURATION_MS_FIELD_NAME = "durationMs"; |
68 | + | ||
69 | + public static final String EDGE_MSG_SOURCE = "edge"; | ||
70 | + public static final String MSG_SOURCE_KEY = "source"; | ||
68 | } | 71 | } |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.common.data.id; | 16 | package org.thingsboard.server.common.data.id; |
17 | 17 | ||
18 | import org.thingsboard.server.common.data.EntityType; | 18 | import org.thingsboard.server.common.data.EntityType; |
19 | +import org.thingsboard.server.common.data.edge.EdgeEventType; | ||
19 | 20 | ||
20 | import java.util.UUID; | 21 | import java.util.UUID; |
21 | 22 | ||
@@ -68,4 +69,28 @@ public class EntityIdFactory { | @@ -68,4 +69,28 @@ public class EntityIdFactory { | ||
68 | throw new IllegalArgumentException("EntityType " + type + " is not supported!"); | 69 | throw new IllegalArgumentException("EntityType " + type + " is not supported!"); |
69 | } | 70 | } |
70 | 71 | ||
72 | + public static EntityId getByEdgeEventTypeAndUuid(EdgeEventType edgeEventType, UUID uuid) { | ||
73 | + switch (edgeEventType) { | ||
74 | + case CUSTOMER: | ||
75 | + return new CustomerId(uuid); | ||
76 | + case USER: | ||
77 | + return new UserId(uuid); | ||
78 | + case DASHBOARD: | ||
79 | + return new DashboardId(uuid); | ||
80 | + case DEVICE: | ||
81 | + return new DeviceId(uuid); | ||
82 | + case ASSET: | ||
83 | + return new AssetId(uuid); | ||
84 | + case ALARM: | ||
85 | + return new AlarmId(uuid); | ||
86 | + case RULE_CHAIN: | ||
87 | + return new RuleChainId(uuid); | ||
88 | + case ENTITY_VIEW: | ||
89 | + return new EntityViewId(uuid); | ||
90 | + case EDGE: | ||
91 | + return new EdgeId(uuid); | ||
92 | + } | ||
93 | + throw new IllegalArgumentException("EdgeEventType " + edgeEventType + " is not supported!"); | ||
94 | + } | ||
95 | + | ||
71 | } | 96 | } |
@@ -100,9 +100,9 @@ enum UpdateMsgType { | @@ -100,9 +100,9 @@ enum UpdateMsgType { | ||
100 | } | 100 | } |
101 | 101 | ||
102 | message EntityDataProto { | 102 | message EntityDataProto { |
103 | - string entityName = 1; | ||
104 | - int64 entityIdMSB = 2; | ||
105 | - int64 entityIdLSB = 3; | 103 | + int64 entityIdMSB = 1; |
104 | + int64 entityIdLSB = 2; | ||
105 | + string entityType = 3; | ||
106 | transport.PostTelemetryMsg postTelemetryMsg = 4; | 106 | transport.PostTelemetryMsg postTelemetryMsg = 4; |
107 | transport.PostAttributeMsg postAttributesMsg = 5; | 107 | transport.PostAttributeMsg postAttributesMsg = 5; |
108 | // transport.ToDeviceRpcRequestMsg ??? | 108 | // transport.ToDeviceRpcRequestMsg ??? |
@@ -52,6 +52,8 @@ public class BaseEdgeEventService implements EdgeEventService { | @@ -52,6 +52,8 @@ public class BaseEdgeEventService implements EdgeEventService { | ||
52 | return EdgeEventType.DASHBOARD; | 52 | return EdgeEventType.DASHBOARD; |
53 | case USER: | 53 | case USER: |
54 | return EdgeEventType.USER; | 54 | return EdgeEventType.USER; |
55 | + case ALARM: | ||
56 | + return EdgeEventType.ALARM; | ||
55 | default: | 57 | default: |
56 | log.warn("Failed to push notification to edge service. Unsupported entity type [{}]", entityType); | 58 | log.warn("Failed to push notification to edge service. Unsupported entity type [{}]", entityType); |
57 | return null; | 59 | return null; |
@@ -70,34 +70,23 @@ public class TbMsgPushToEdgeNode implements TbNode { | @@ -70,34 +70,23 @@ public class TbMsgPushToEdgeNode implements TbNode { | ||
70 | 70 | ||
71 | @Override | 71 | @Override |
72 | public void onMsg(TbContext ctx, TbMsg msg) { | 72 | public void onMsg(TbContext ctx, TbMsg msg) { |
73 | - if (EntityType.DEVICE.equals(msg.getOriginator().getEntityType()) || | ||
74 | - EntityType.DEVICE.equals(msg.getOriginator().getEntityType()) || | ||
75 | - EntityType.DEVICE.equals(msg.getOriginator().getEntityType()) || | ||
76 | - EntityType.DEVICE.equals(msg.getOriginator().getEntityType())) { | ||
77 | - if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msg.getType()) || | ||
78 | - SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType()) || | ||
79 | - DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType()) || | ||
80 | - DataConstants.ATTRIBUTES_DELETED.equals(msg.getType())) { | 73 | + if (DataConstants.EDGE_MSG_SOURCE.equalsIgnoreCase(msg.getMetaData().getValue(DataConstants.MSG_SOURCE_KEY))) { |
74 | + log.debug("Ignoring msg from the cloud, msg [{}]", msg); | ||
75 | + return; | ||
76 | + } | ||
77 | + if (isSupportedOriginator(msg.getOriginator().getEntityType())) { | ||
78 | + if (isSupportedMsgType(msg.getType())) { | ||
81 | ListenableFuture<EdgeId> getEdgeIdFuture = getEdgeIdByOriginatorId(ctx, ctx.getTenantId(), msg.getOriginator()); | 79 | ListenableFuture<EdgeId> getEdgeIdFuture = getEdgeIdByOriginatorId(ctx, ctx.getTenantId(), msg.getOriginator()); |
82 | Futures.transform(getEdgeIdFuture, edgeId -> { | 80 | Futures.transform(getEdgeIdFuture, edgeId -> { |
83 | EdgeEventType edgeEventTypeByEntityType = ctx.getEdgeEventService().getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType()); | 81 | EdgeEventType edgeEventTypeByEntityType = ctx.getEdgeEventService().getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType()); |
84 | if (edgeEventTypeByEntityType == null) { | 82 | if (edgeEventTypeByEntityType == null) { |
85 | log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType()); | 83 | log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType()); |
86 | - ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '"+ msg.getOriginator().getEntityType() + "'")); | ||
87 | - } | ||
88 | - ActionType actionType; | ||
89 | - if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msg.getType())) { | ||
90 | - actionType = ActionType.TIMESERIES_UPDATED; | ||
91 | - } else if (SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msg.getType()) || | ||
92 | - DataConstants.ATTRIBUTES_UPDATED.equals(msg.getType())) { | ||
93 | - actionType = ActionType.ATTRIBUTES_UPDATED; | ||
94 | - } else { | ||
95 | - actionType = ActionType.ATTRIBUTES_DELETED; | 84 | + ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'")); |
96 | } | 85 | } |
97 | EdgeEvent edgeEvent = new EdgeEvent(); | 86 | EdgeEvent edgeEvent = new EdgeEvent(); |
98 | edgeEvent.setTenantId(ctx.getTenantId()); | 87 | edgeEvent.setTenantId(ctx.getTenantId()); |
99 | edgeEvent.setEdgeId(edgeId); | 88 | edgeEvent.setEdgeId(edgeId); |
100 | - edgeEvent.setEdgeEventAction(actionType.name()); | 89 | + edgeEvent.setEdgeEventAction(getActionTypeByMsgType(msg.getType()).name()); |
101 | edgeEvent.setEntityId(msg.getOriginator().getId()); | 90 | edgeEvent.setEntityId(msg.getOriginator().getId()); |
102 | edgeEvent.setEdgeEventType(edgeEventTypeByEntityType); | 91 | edgeEvent.setEdgeEventType(edgeEventTypeByEntityType); |
103 | edgeEvent.setEntityBody(json.valueToTree(msg.getData())); | 92 | edgeEvent.setEntityBody(json.valueToTree(msg.getData())); |
@@ -126,6 +115,42 @@ public class TbMsgPushToEdgeNode implements TbNode { | @@ -126,6 +115,42 @@ public class TbMsgPushToEdgeNode implements TbNode { | ||
126 | } | 115 | } |
127 | } | 116 | } |
128 | 117 | ||
118 | + private ActionType getActionTypeByMsgType(String msgType) { | ||
119 | + ActionType actionType; | ||
120 | + if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType)) { | ||
121 | + actionType = ActionType.TIMESERIES_UPDATED; | ||
122 | + } else if (SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msgType) | ||
123 | + || DataConstants.ATTRIBUTES_UPDATED.equals(msgType)) { | ||
124 | + actionType = ActionType.ATTRIBUTES_UPDATED; | ||
125 | + } else { | ||
126 | + actionType = ActionType.ATTRIBUTES_DELETED; | ||
127 | + } | ||
128 | + return actionType; | ||
129 | + } | ||
130 | + | ||
131 | + private boolean isSupportedOriginator(EntityType entityType) { | ||
132 | + switch (entityType) { | ||
133 | + case DEVICE: | ||
134 | + case ASSET: | ||
135 | + case ENTITY_VIEW: | ||
136 | + case DASHBOARD: | ||
137 | + return true; | ||
138 | + default: | ||
139 | + return false; | ||
140 | + } | ||
141 | + } | ||
142 | + | ||
143 | + private boolean isSupportedMsgType(String msgType) { | ||
144 | + if (SessionMsgType.POST_TELEMETRY_REQUEST.name().equals(msgType) | ||
145 | + || SessionMsgType.POST_ATTRIBUTES_REQUEST.name().equals(msgType) | ||
146 | + || DataConstants.ATTRIBUTES_UPDATED.equals(msgType) | ||
147 | + || DataConstants.ATTRIBUTES_DELETED.equals(msgType)) { | ||
148 | + return true; | ||
149 | + } else { | ||
150 | + return false; | ||
151 | + } | ||
152 | + } | ||
153 | + | ||
129 | private ListenableFuture<EdgeId> getEdgeIdByOriginatorId(TbContext ctx, TenantId tenantId, EntityId originatorId) { | 154 | private ListenableFuture<EdgeId> getEdgeIdByOriginatorId(TbContext ctx, TenantId tenantId, EntityId originatorId) { |
130 | ListenableFuture<List<EntityRelation>> future = ctx.getRelationService().findByToAndTypeAsync(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); | 155 | ListenableFuture<List<EntityRelation>> future = ctx.getRelationService().findByToAndTypeAsync(tenantId, originatorId, EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); |
131 | return Futures.transform(future, relations -> { | 156 | return Futures.transform(future, relations -> { |
@@ -37,7 +37,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider | @@ -37,7 +37,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider | ||
37 | } | 37 | } |
38 | }) | 38 | }) |
39 | .state('home.ruleChains.core', { | 39 | .state('home.ruleChains.core', { |
40 | - url: '/ruleChains/system', | 40 | + url: '/ruleChains/core', |
41 | params: {'topIndex': 0}, | 41 | params: {'topIndex': 0}, |
42 | module: 'private', | 42 | module: 'private', |
43 | auth: ['SYS_ADMIN', 'TENANT_ADMIN'], | 43 | auth: ['SYS_ADMIN', 'TENANT_ADMIN'], |