Commit 0b4ec2b9b30c25ea930c9fa8b6f7a195e2573964
Committed by
GitHub
Merge pull request #748 from thingsboard/develop/1.5-queue
Queue Put and Ack
Showing
37 changed files
with
464 additions
and
203 deletions
... | ... | @@ -49,6 +49,7 @@ import org.thingsboard.server.dao.customer.CustomerService; |
49 | 49 | import org.thingsboard.server.dao.device.DeviceService; |
50 | 50 | import org.thingsboard.server.dao.event.EventService; |
51 | 51 | import org.thingsboard.server.dao.plugin.PluginService; |
52 | +import org.thingsboard.server.dao.queue.MsgQueue; | |
52 | 53 | import org.thingsboard.server.dao.relation.RelationService; |
53 | 54 | import org.thingsboard.server.dao.rule.RuleChainService; |
54 | 55 | import org.thingsboard.server.dao.rule.RuleService; |
... | ... | @@ -187,6 +188,10 @@ public class ActorSystemContext { |
187 | 188 | @Getter |
188 | 189 | private MailService mailService; |
189 | 190 | |
191 | + @Autowired | |
192 | + @Getter | |
193 | + private MsgQueue msgQueue; | |
194 | + | |
190 | 195 | @Value("${actors.session.sync.timeout}") |
191 | 196 | @Getter |
192 | 197 | private long syncSessionTimeout; | ... | ... |
... | ... | @@ -204,9 +204,13 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
204 | 204 | void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { |
205 | 205 | PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); |
206 | 206 | if (data != null && data.isReplyOnQueueAck()) { |
207 | - logger.debug("[{}] Queue put [{}] ack detected!", deviceId, msg.getId()); | |
208 | - ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId()); | |
209 | - sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | |
207 | + int remainingAcks = data.getAckMsgCount() - 1; | |
208 | + data.setAckMsgCount(remainingAcks); | |
209 | + logger.debug("[{}] Queue put [{}] ack detected. Remaining acks: {}!", deviceId, msg.getId(), remainingAcks); | |
210 | + if (remainingAcks == 0) { | |
211 | + ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId()); | |
212 | + sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | |
213 | + } | |
210 | 214 | } |
211 | 215 | } |
212 | 216 | |
... | ... | @@ -320,8 +324,10 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
320 | 324 | kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); |
321 | 325 | } |
322 | 326 | |
323 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json)); | |
324 | - pushToRuleEngineWithTimeout(context, tbMsg, src, request); | |
327 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | |
328 | + PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | |
329 | + SessionMsgType.POST_ATTRIBUTES_REQUEST, request.getRequestId(), true, 1); | |
330 | + pushToRuleEngineWithTimeout(context, tbMsg, msgData); | |
325 | 331 | } |
326 | 332 | |
327 | 333 | private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) { |
... | ... | @@ -329,10 +335,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
329 | 335 | |
330 | 336 | Map<Long, List<KvEntry>> tsData = request.getData(); |
331 | 337 | |
332 | - JsonArray json = new JsonArray(); | |
338 | + PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | |
339 | + SessionMsgType.POST_TELEMETRY_REQUEST, request.getRequestId(), true, tsData.size()); | |
340 | + | |
333 | 341 | for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) { |
334 | - JsonObject ts = new JsonObject(); | |
335 | - ts.addProperty("ts", entry.getKey()); | |
342 | + JsonObject json = new JsonObject(); | |
343 | + json.addProperty("ts", entry.getKey()); | |
336 | 344 | JsonObject values = new JsonObject(); |
337 | 345 | for (KvEntry kv : entry.getValue()) { |
338 | 346 | kv.getBooleanValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); |
... | ... | @@ -340,12 +348,10 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
340 | 348 | kv.getDoubleValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); |
341 | 349 | kv.getStrValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); |
342 | 350 | } |
343 | - ts.add("values", values); | |
344 | - json.add(ts); | |
351 | + json.add("values", values); | |
352 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | |
353 | + pushToRuleEngineWithTimeout(context, tbMsg, msgData); | |
345 | 354 | } |
346 | - | |
347 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json)); | |
348 | - pushToRuleEngineWithTimeout(context, tbMsg, src, request); | |
349 | 355 | } |
350 | 356 | |
351 | 357 | private void handleClientSideRPCRequest(ActorContext context, DeviceToDeviceActorMsg src) { |
... | ... | @@ -357,8 +363,9 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
357 | 363 | |
358 | 364 | TbMsgMetaData requestMetaData = defaultMetaData.copy(); |
359 | 365 | requestMetaData.putValue("requestId", Integer.toString(request.getRequestId())); |
360 | - TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json)); | |
361 | - pushToRuleEngineWithTimeout(context, tbMsg, src, request); | |
366 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | |
367 | + PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), SessionMsgType.TO_SERVER_RPC_REQUEST, request.getRequestId(), false, 1); | |
368 | + pushToRuleEngineWithTimeout(context, tbMsg, msgData); | |
362 | 369 | |
363 | 370 | scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout()); |
364 | 371 | toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(src.getSessionId(), src.getSessionType(), src.getServerAddress())); |
... | ... | @@ -380,19 +387,15 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
380 | 387 | } |
381 | 388 | } |
382 | 389 | |
383 | - private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg) { | |
384 | - pushToRuleEngineWithTimeout(context, tbMsg, src, fromDeviceRequestMsg, true); | |
385 | - } | |
386 | - | |
387 | - private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg, boolean replyOnAck) { | |
388 | - SessionMsgType sessionMsgType = fromDeviceRequestMsg.getMsgType(); | |
389 | - int requestId = fromDeviceRequestMsg.getRequestId(); | |
390 | + private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, PendingSessionMsgData pendingMsgData) { | |
391 | + SessionMsgType sessionMsgType = pendingMsgData.getSessionMsgType(); | |
392 | + int requestId = pendingMsgData.getRequestId(); | |
390 | 393 | if (systemContext.isQueuePersistenceEnabled()) { |
391 | - pendingMsgs.put(tbMsg.getId(), new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), sessionMsgType, requestId, replyOnAck)); | |
394 | + pendingMsgs.put(tbMsg.getId(), pendingMsgData); | |
392 | 395 | scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout()); |
393 | 396 | } else { |
394 | - ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), src.getSessionId()); | |
395 | - sendMsgToSessionActor(response, src.getServerAddress()); | |
397 | + ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), pendingMsgData.getSessionId()); | |
398 | + sendMsgToSessionActor(response, pendingMsgData.getServerAddress()); | |
396 | 399 | } |
397 | 400 | context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); |
398 | 401 | } | ... | ... |
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | +import lombok.AllArgsConstructor; | |
18 | 19 | import lombok.Data; |
19 | 20 | import org.thingsboard.server.common.data.id.SessionId; |
20 | 21 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
... | ... | @@ -26,6 +27,7 @@ import java.util.Optional; |
26 | 27 | * Created by ashvayka on 17.04.18. |
27 | 28 | */ |
28 | 29 | @Data |
30 | +@AllArgsConstructor | |
29 | 31 | public final class PendingSessionMsgData { |
30 | 32 | |
31 | 33 | private final SessionId sessionId; |
... | ... | @@ -33,5 +35,6 @@ public final class PendingSessionMsgData { |
33 | 35 | private final SessionMsgType sessionMsgType; |
34 | 36 | private final int requestId; |
35 | 37 | private final boolean replyOnQueueAck; |
38 | + private int ackMsgCount; | |
36 | 39 | |
37 | 40 | } | ... | ... |
... | ... | @@ -53,7 +53,6 @@ import java.util.function.Consumer; |
53 | 53 | */ |
54 | 54 | class DefaultTbContext implements TbContext { |
55 | 55 | |
56 | - private static final Function<? super List<Void>, ? extends Void> LIST_VOID_FUNCTION = v -> null; | |
57 | 56 | private final ActorSystemContext mainCtx; |
58 | 57 | private final RuleNodeCtx nodeCtx; |
59 | 58 | |
... | ... | @@ -120,7 +119,7 @@ class DefaultTbContext implements TbContext { |
120 | 119 | |
121 | 120 | @Override |
122 | 121 | public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { |
123 | - return new TbMsg(UUIDs.timeBased(), type, originator, metaData, data); | |
122 | + return new TbMsg(UUIDs.timeBased(), type, originator, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), 0L); | |
124 | 123 | } |
125 | 124 | |
126 | 125 | @Override |
... | ... | @@ -239,7 +238,6 @@ class DefaultTbContext implements TbContext { |
239 | 238 | .build()); |
240 | 239 | }); |
241 | 240 | } |
242 | - | |
243 | 241 | }; |
244 | 242 | } |
245 | 243 | } | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import akka.actor.ActorContext; |
19 | 19 | import akka.actor.ActorRef; |
20 | 20 | import akka.actor.Props; |
21 | 21 | import akka.event.LoggingAdapter; |
22 | +import com.datastax.driver.core.utils.UUIDs; | |
22 | 23 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 24 | import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; |
24 | 25 | import org.thingsboard.server.actors.device.RuleEngineQueuePutAckMsg; |
... | ... | @@ -41,6 +42,7 @@ import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
41 | 42 | import org.thingsboard.server.dao.rule.RuleChainService; |
42 | 43 | |
43 | 44 | import java.util.ArrayList; |
45 | +import java.util.Collections; | |
44 | 46 | import java.util.HashMap; |
45 | 47 | import java.util.List; |
46 | 48 | import java.util.Map; |
... | ... | @@ -52,6 +54,7 @@ import java.util.stream.Collectors; |
52 | 54 | */ |
53 | 55 | public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { |
54 | 56 | |
57 | + private static final long DEFAULT_CLUSTER_PARTITION = 0L; | |
55 | 58 | private final ActorRef parent; |
56 | 59 | private final ActorRef self; |
57 | 60 | private final Map<RuleNodeId, RuleNodeCtx> nodeActors; |
... | ... | @@ -83,6 +86,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
83 | 86 | nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); |
84 | 87 | } |
85 | 88 | initRoutes(ruleChain, ruleNodeList); |
89 | + //TODO: read all messages from queues of the actors and push then to the corresponding node actors; | |
86 | 90 | started = true; |
87 | 91 | } else { |
88 | 92 | onUpdate(context); |
... | ... | @@ -142,15 +146,19 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
142 | 146 | // Populating the routes map; |
143 | 147 | for (RuleNode ruleNode : ruleNodeList) { |
144 | 148 | List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId()); |
145 | - for (EntityRelation relation : relations) { | |
146 | - if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { | |
147 | - RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId())); | |
148 | - if (ruleNodeCtx == null) { | |
149 | - throw new IllegalArgumentException("Rule Node [" + relation.getFrom() + "] has invalid relation to Rule node [" + relation.getTo() + "]"); | |
149 | + if (relations.size() == 0) { | |
150 | + nodeRoutes.put(ruleNode.getId(), Collections.emptyList()); | |
151 | + } else { | |
152 | + for (EntityRelation relation : relations) { | |
153 | + if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { | |
154 | + RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId())); | |
155 | + if (ruleNodeCtx == null) { | |
156 | + throw new IllegalArgumentException("Rule Node [" + relation.getFrom() + "] has invalid relation to Rule node [" + relation.getTo() + "]"); | |
157 | + } | |
150 | 158 | } |
159 | + nodeRoutes.computeIfAbsent(ruleNode.getId(), k -> new ArrayList<>()) | |
160 | + .add(new RuleNodeRelation(ruleNode.getId(), relation.getTo(), relation.getType())); | |
151 | 161 | } |
152 | - nodeRoutes.computeIfAbsent(ruleNode.getId(), k -> new ArrayList<>()) | |
153 | - .add(new RuleNodeRelation(ruleNode.getId(), relation.getTo(), relation.getType())); | |
154 | 162 | } |
155 | 163 | } |
156 | 164 | |
... | ... | @@ -161,45 +169,62 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
161 | 169 | |
162 | 170 | void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) { |
163 | 171 | checkActive(); |
164 | - TbMsg tbMsg = envelope.getTbMsg(); | |
165 | - //TODO: push to queue and act on ack in async way | |
166 | - pushMsgToNode(firstNode, tbMsg); | |
172 | + putToQueue(enrichWithRuleChainId(envelope.getTbMsg()), msg -> pushMsgToNode(firstNode, msg)); | |
167 | 173 | } |
168 | 174 | |
169 | - public void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) { | |
175 | + void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) { | |
170 | 176 | checkActive(); |
171 | - TbMsg tbMsg = envelope.getTbMsg(); | |
172 | - //TODO: push to queue and act on ack in async way | |
173 | - pushMsgToNode(firstNode, tbMsg); | |
174 | - envelope.getCallbackRef().tell(new RuleEngineQueuePutAckMsg(tbMsg.getId()), self); | |
177 | + putToQueue(enrichWithRuleChainId(envelope.getTbMsg()), msg -> { | |
178 | + pushMsgToNode(firstNode, msg); | |
179 | + envelope.getCallbackRef().tell(new RuleEngineQueuePutAckMsg(msg.getId()), self); | |
180 | + }); | |
175 | 181 | } |
176 | 182 | |
177 | 183 | void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { |
178 | 184 | checkActive(); |
179 | 185 | RuleNodeId originator = envelope.getOriginator(); |
180 | 186 | String targetRelationType = envelope.getRelationType(); |
181 | - List<RuleNodeRelation> relations = nodeRoutes.get(originator); | |
182 | - if (relations == null) { | |
183 | - return; | |
184 | - } | |
185 | - boolean copy = relations.size() > 1; | |
186 | - for (RuleNodeRelation relation : relations) { | |
187 | - TbMsg msg = envelope.getMsg(); | |
188 | - if (copy) { | |
189 | - msg = msg.copy(); | |
187 | + List<RuleNodeRelation> relations = nodeRoutes.get(originator).stream() | |
188 | + .filter(r -> targetRelationType == null || targetRelationType.equalsIgnoreCase(r.getType())) | |
189 | + .collect(Collectors.toList()); | |
190 | + | |
191 | + TbMsg msg = envelope.getMsg(); | |
192 | + int relationsCount = relations.size(); | |
193 | + if (relationsCount == 0) { | |
194 | + queue.ack(msg, msg.getRuleNodeId().getId(), msg.getClusterPartition()); | |
195 | + } else if (relationsCount == 1) { | |
196 | + for (RuleNodeRelation relation : relations) { | |
197 | + pushToTarget(msg, relation.getOut()); | |
190 | 198 | } |
191 | - if (targetRelationType == null || targetRelationType.equalsIgnoreCase(relation.getType())) { | |
192 | - switch (relation.getOut().getEntityType()) { | |
199 | + } else { | |
200 | + for (RuleNodeRelation relation : relations) { | |
201 | + EntityId target = relation.getOut(); | |
202 | + switch (target.getEntityType()) { | |
193 | 203 | case RULE_NODE: |
194 | - RuleNodeId targetRuleNodeId = new RuleNodeId(relation.getOut().getId()); | |
195 | - RuleNodeCtx targetRuleNode = nodeActors.get(targetRuleNodeId); | |
196 | - pushMsgToNode(targetRuleNode, msg); | |
204 | + RuleNodeId targetId = new RuleNodeId(target.getId()); | |
205 | + RuleNodeCtx targetNodeCtx = nodeActors.get(targetId); | |
206 | + TbMsg copy = msg.copy(UUIDs.timeBased(), entityId, targetId, DEFAULT_CLUSTER_PARTITION); | |
207 | + putToQueue(copy, queuedMsg -> pushMsgToNode(targetNodeCtx, queuedMsg)); | |
197 | 208 | break; |
198 | 209 | case RULE_CHAIN: |
199 | -// TODO: implement | |
210 | + parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, true), self); | |
200 | 211 | break; |
201 | 212 | } |
202 | 213 | } |
214 | + //TODO: Ideally this should happen in async way when all targets confirm that the copied messages are successfully written to corresponding target queues. | |
215 | + EntityId ackId = msg.getRuleNodeId() != null ? msg.getRuleNodeId() : msg.getRuleChainId(); | |
216 | + queue.ack(msg, ackId.getId(), msg.getClusterPartition()); | |
217 | + } | |
218 | + } | |
219 | + | |
220 | + private void pushToTarget(TbMsg msg, EntityId target) { | |
221 | + switch (target.getEntityType()) { | |
222 | + case RULE_NODE: | |
223 | + pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg); | |
224 | + break; | |
225 | + case RULE_CHAIN: | |
226 | + parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, false), self); | |
227 | + break; | |
203 | 228 | } |
204 | 229 | } |
205 | 230 | |
... | ... | @@ -208,4 +233,9 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
208 | 233 | nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self); |
209 | 234 | } |
210 | 235 | } |
236 | + | |
237 | + private TbMsg enrichWithRuleChainId(TbMsg tbMsg) { | |
238 | + // We don't put firstNodeId because it may change over time; | |
239 | + return new TbMsg(tbMsg.getId(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData(), tbMsg.getData(), entityId, null, 0L); | |
240 | + } | |
211 | 241 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleChainMsg.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2018 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.actors.ruleChain; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.rule.engine.api.TbContext; | |
20 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
21 | +import org.thingsboard.server.common.msg.MsgType; | |
22 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
23 | +import org.thingsboard.server.common.msg.TbMsg; | |
24 | + | |
25 | +/** | |
26 | + * Created by ashvayka on 19.03.18. | |
27 | + */ | |
28 | +@Data | |
29 | +final class RuleChainToRuleChainMsg implements TbActorMsg { | |
30 | + | |
31 | + private final RuleChainId target; | |
32 | + private final RuleChainId source; | |
33 | + private final TbMsg msg; | |
34 | + private final boolean enqueue; | |
35 | + | |
36 | + @Override | |
37 | + public MsgType getMsgType() { | |
38 | + return MsgType.RULE_CHAIN_TO_RULE_CHAIN_MSG; | |
39 | + } | |
40 | +} | ... | ... |
... | ... | @@ -17,22 +17,32 @@ package org.thingsboard.server.actors.shared; |
17 | 17 | |
18 | 18 | import akka.actor.ActorContext; |
19 | 19 | import akka.event.LoggingAdapter; |
20 | +import com.google.common.util.concurrent.FutureCallback; | |
21 | +import com.google.common.util.concurrent.Futures; | |
20 | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | 23 | import org.thingsboard.server.actors.stats.StatsPersistTick; |
24 | +import org.thingsboard.server.common.data.id.EntityId; | |
22 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
23 | 26 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
27 | +import org.thingsboard.server.common.msg.TbMsg; | |
24 | 28 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
29 | +import org.thingsboard.server.dao.queue.MsgQueue; | |
25 | 30 | |
26 | -public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgProcessor { | |
31 | +import javax.annotation.Nullable; | |
32 | +import java.util.function.Consumer; | |
33 | + | |
34 | +public abstract class ComponentMsgProcessor<T extends EntityId> extends AbstractContextAwareMsgProcessor { | |
27 | 35 | |
28 | 36 | protected final TenantId tenantId; |
29 | 37 | protected final T entityId; |
38 | + protected final MsgQueue queue; | |
30 | 39 | protected ComponentLifecycleState state; |
31 | 40 | |
32 | 41 | protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) { |
33 | 42 | super(systemContext, logger); |
34 | 43 | this.tenantId = tenantId; |
35 | 44 | this.entityId = id; |
45 | + this.queue = systemContext.getMsgQueue(); | |
36 | 46 | } |
37 | 47 | |
38 | 48 | public abstract void start(ActorContext context) throws Exception; |
... | ... | @@ -75,4 +85,19 @@ public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgPr |
75 | 85 | throw new IllegalStateException("Rule chain is not active!"); |
76 | 86 | } |
77 | 87 | } |
88 | + | |
89 | + protected void putToQueue(final TbMsg tbMsg, final Consumer<TbMsg> onSuccess) { | |
90 | + EntityId entityId = tbMsg.getRuleNodeId() != null ? tbMsg.getRuleNodeId() : tbMsg.getRuleChainId(); | |
91 | + Futures.addCallback(queue.put(tbMsg, entityId.getId(), 0), new FutureCallback<Void>() { | |
92 | + @Override | |
93 | + public void onSuccess(@Nullable Void result) { | |
94 | + onSuccess.accept(tbMsg); | |
95 | + } | |
96 | + | |
97 | + @Override | |
98 | + public void onFailure(Throwable t) { | |
99 | + logger.debug("Failed to push message [{}] to queue due to [{}]", tbMsg, t); | |
100 | + } | |
101 | + }); | |
102 | + } | |
78 | 103 | } | ... | ... |
... | ... | @@ -237,7 +237,7 @@ public class RuleChainController extends BaseController { |
237 | 237 | ScriptEngine engine = null; |
238 | 238 | try { |
239 | 239 | engine = new NashornJsEngine(script, functionName, argNames); |
240 | - TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data); | |
240 | + TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data, null, null, 0L); | |
241 | 241 | switch (scriptType) { |
242 | 242 | case "update": |
243 | 243 | output = msgToOutput(engine.executeUpdate(inMsg)); | ... | ... |
... | ... | @@ -118,7 +118,7 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn |
118 | 118 | String newData = data != null ? data : msg.getData(); |
119 | 119 | TbMsgMetaData newMetadata = metadata != null ? new TbMsgMetaData(metadata) : msg.getMetaData(); |
120 | 120 | String newMessageType = !StringUtils.isEmpty(messageType) ? messageType : msg.getType(); |
121 | - return new TbMsg(msg.getId(), newMessageType, msg.getOriginator(), newMetadata, newData); | |
121 | + return new TbMsg(msg.getId(), newMessageType, msg.getOriginator(), newMetadata, newData, msg.getRuleChainId(), msg.getRuleNodeId(), msg.getClusterPartition()); | |
122 | 122 | } catch (Throwable th) { |
123 | 123 | th.printStackTrace(); |
124 | 124 | throw new RuntimeException("Failed to unbind message data from javascript result", th); | ... | ... |
... | ... | @@ -36,7 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. |
36 | 36 | |
37 | 37 | public abstract class BaseComponentDescriptorControllerTest extends AbstractControllerTest { |
38 | 38 | |
39 | - private static final int AMOUNT_OF_DEFAULT_FILTER_NODES = 3; | |
39 | + private static final int AMOUNT_OF_DEFAULT_FILTER_NODES = 4; | |
40 | 40 | private Tenant savedTenant; |
41 | 41 | private User tenantAdmin; |
42 | 42 | |
... | ... | @@ -87,7 +87,7 @@ public abstract class BaseComponentDescriptorControllerTest extends AbstractCont |
87 | 87 | }); |
88 | 88 | |
89 | 89 | Assert.assertNotNull(descriptors); |
90 | - Assert.assertEquals(AMOUNT_OF_DEFAULT_FILTER_NODES, descriptors.size()); | |
90 | + Assert.assertTrue(descriptors.size() >= AMOUNT_OF_DEFAULT_FILTER_NODES); | |
91 | 91 | |
92 | 92 | for (ComponentType type : ComponentType.values()) { |
93 | 93 | doGet("/api/components/" + type).andExpect(status().isOk()); | ... | ... |
... | ... | @@ -80,7 +80,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
80 | 80 | } |
81 | 81 | } |
82 | 82 | |
83 | - @Ignore | |
84 | 83 | @Test |
85 | 84 | public void testServerMqttOneWayRpc() throws Exception { |
86 | 85 | Device device = new Device(); |
... | ... | @@ -107,7 +106,6 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
107 | 106 | Assert.assertTrue(StringUtils.isEmpty(result)); |
108 | 107 | } |
109 | 108 | |
110 | - @Ignore | |
111 | 109 | @Test |
112 | 110 | public void testServerMqttOneWayRpcDeviceOffline() throws Exception { |
113 | 111 | Device device = new Device(); | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.mqtt.rpc.sql; |
17 | 17 | |
18 | -import org.thingsboard.server.dao.service.DaoNoSqlTest; | |
19 | 18 | import org.thingsboard.server.dao.service.DaoSqlTest; |
20 | 19 | import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcIntegrationTest; |
21 | 20 | ... | ... |
... | ... | @@ -150,7 +150,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
150 | 150 | "CUSTOM", |
151 | 151 | device.getId(), |
152 | 152 | new TbMsgMetaData(), |
153 | - "{}"); | |
153 | + "{}", null, null, 0L); | |
154 | 154 | actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg)); |
155 | 155 | |
156 | 156 | Thread.sleep(3000); | ... | ... |
... | ... | @@ -138,7 +138,8 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac |
138 | 138 | "CUSTOM", |
139 | 139 | device.getId(), |
140 | 140 | new TbMsgMetaData(), |
141 | - "{}"); | |
141 | + "{}", | |
142 | + null, null, 0L); | |
142 | 143 | actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg)); |
143 | 144 | |
144 | 145 | Thread.sleep(3000); | ... | ... |
... | ... | @@ -42,7 +42,7 @@ public class NashornJsEngineTest { |
42 | 42 | metaData.putValue("humidity", "99"); |
43 | 43 | String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; |
44 | 44 | |
45 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
45 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | |
46 | 46 | |
47 | 47 | TbMsg actual = scriptEngine.executeUpdate(msg); |
48 | 48 | assertEquals("70", actual.getMetaData().getValue("temp")); |
... | ... | @@ -57,7 +57,7 @@ public class NashornJsEngineTest { |
57 | 57 | metaData.putValue("humidity", "99"); |
58 | 58 | String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; |
59 | 59 | |
60 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
60 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | |
61 | 61 | |
62 | 62 | TbMsg actual = scriptEngine.executeUpdate(msg); |
63 | 63 | assertEquals("94", actual.getMetaData().getValue("newAttr")); |
... | ... | @@ -72,7 +72,7 @@ public class NashornJsEngineTest { |
72 | 72 | metaData.putValue("humidity", "99"); |
73 | 73 | String rawJson = "{\"name\":\"Vit\",\"passed\": 5,\"bigObj\":{\"prop\":42}}"; |
74 | 74 | |
75 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
75 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | |
76 | 76 | |
77 | 77 | TbMsg actual = scriptEngine.executeUpdate(msg); |
78 | 78 | |
... | ... | @@ -89,7 +89,7 @@ public class NashornJsEngineTest { |
89 | 89 | metaData.putValue("humidity", "99"); |
90 | 90 | String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; |
91 | 91 | |
92 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
92 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | |
93 | 93 | assertFalse(scriptEngine.executeFilter(msg)); |
94 | 94 | } |
95 | 95 | |
... | ... | @@ -102,7 +102,7 @@ public class NashornJsEngineTest { |
102 | 102 | metaData.putValue("humidity", "99"); |
103 | 103 | String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; |
104 | 104 | |
105 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
105 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | |
106 | 106 | assertTrue(scriptEngine.executeFilter(msg)); |
107 | 107 | } |
108 | 108 | |
... | ... | @@ -122,7 +122,7 @@ public class NashornJsEngineTest { |
122 | 122 | metaData.putValue("humidity", "99"); |
123 | 123 | String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; |
124 | 124 | |
125 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
125 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | |
126 | 126 | Set<String> actual = scriptEngine.executeSwitch(msg); |
127 | 127 | assertEquals(Sets.newHashSet("one"), actual); |
128 | 128 | } |
... | ... | @@ -143,7 +143,7 @@ public class NashornJsEngineTest { |
143 | 143 | metaData.putValue("humidity", "99"); |
144 | 144 | String rawJson = "{\"name\": \"Vit\", \"passed\": 5, \"bigObj\": {\"prop\":42}}"; |
145 | 145 | |
146 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
146 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, null, null, 0L); | |
147 | 147 | Set<String> actual = scriptEngine.executeSwitch(msg); |
148 | 148 | assertEquals(Sets.newHashSet("one", "three"), actual); |
149 | 149 | } | ... | ... |
... | ... | @@ -48,6 +48,11 @@ public enum MsgType { |
48 | 48 | RULE_CHAIN_TO_RULE_MSG, |
49 | 49 | |
50 | 50 | /** |
51 | + * Message that is sent by RuleChainActor to other RuleChainActor with command to process TbMsg. | |
52 | + */ | |
53 | + RULE_CHAIN_TO_RULE_CHAIN_MSG, | |
54 | + | |
55 | + /** | |
51 | 56 | * Message that is sent by RuleActor to RuleChainActor with command to process TbMsg by next nodes in chain. |
52 | 57 | */ |
53 | 58 | RULE_TO_RULE_CHAIN_TELL_NEXT_MSG, | ... | ... |
... | ... | @@ -15,12 +15,13 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.msg; |
17 | 17 | |
18 | -import com.google.protobuf.ByteString; | |
19 | 18 | import com.google.protobuf.InvalidProtocolBufferException; |
20 | 19 | import lombok.AllArgsConstructor; |
21 | 20 | import lombok.Data; |
22 | 21 | import org.thingsboard.server.common.data.id.EntityId; |
23 | 22 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
23 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
24 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
24 | 25 | import org.thingsboard.server.common.msg.gen.MsgProtos; |
25 | 26 | |
26 | 27 | import java.io.Serializable; |
... | ... | @@ -41,22 +42,40 @@ public final class TbMsg implements Serializable { |
41 | 42 | private final TbMsgDataType dataType; |
42 | 43 | private final String data; |
43 | 44 | |
44 | - public TbMsg(UUID id, String type, EntityId originator, TbMsgMetaData metaData, String data) { | |
45 | + //The following fields are not persisted to DB, because they can always be recovered from the context; | |
46 | + private final RuleChainId ruleChainId; | |
47 | + private final RuleNodeId ruleNodeId; | |
48 | + private final long clusterPartition; | |
49 | + | |
50 | + public TbMsg(UUID id, String type, EntityId originator, TbMsgMetaData metaData, String data, | |
51 | + RuleChainId ruleChainId, RuleNodeId ruleNodeId, long clusterPartition) { | |
45 | 52 | this.id = id; |
46 | 53 | this.type = type; |
47 | 54 | this.originator = originator; |
48 | 55 | this.metaData = metaData; |
49 | - this.dataType = TbMsgDataType.JSON; | |
50 | 56 | this.data = data; |
57 | + this.dataType = TbMsgDataType.JSON; | |
58 | + this.ruleChainId = ruleChainId; | |
59 | + this.ruleNodeId = ruleNodeId; | |
60 | + this.clusterPartition = clusterPartition; | |
51 | 61 | } |
52 | 62 | |
53 | 63 | public static ByteBuffer toBytes(TbMsg msg) { |
54 | 64 | MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder(); |
55 | 65 | builder.setId(msg.getId().toString()); |
56 | 66 | builder.setType(msg.getType()); |
57 | - if (msg.getOriginator() != null) { | |
58 | - builder.setEntityType(msg.getOriginator().getEntityType().name()); | |
59 | - builder.setEntityId(msg.getOriginator().getId().toString()); | |
67 | + builder.setEntityType(msg.getOriginator().getEntityType().name()); | |
68 | + builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits()); | |
69 | + builder.setEntityIdLSB(msg.getOriginator().getId().getLeastSignificantBits()); | |
70 | + | |
71 | + if (msg.getRuleChainId() != null) { | |
72 | + builder.setRuleChainIdMSB(msg.getRuleChainId().getId().getMostSignificantBits()); | |
73 | + builder.setRuleChainIdLSB(msg.getRuleChainId().getId().getLeastSignificantBits()); | |
74 | + } | |
75 | + | |
76 | + if (msg.getRuleNodeId() != null) { | |
77 | + builder.setRuleNodeIdMSB(msg.getRuleNodeId().getId().getMostSignificantBits()); | |
78 | + builder.setRuleNodeIdLSB(msg.getRuleNodeId().getId().getLeastSignificantBits()); | |
60 | 79 | } |
61 | 80 | |
62 | 81 | if (msg.getMetaData() != null) { |
... | ... | @@ -73,15 +92,18 @@ public final class TbMsg implements Serializable { |
73 | 92 | try { |
74 | 93 | MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array()); |
75 | 94 | TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); |
76 | - EntityId entityId = EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()); | |
95 | + EntityId entityId = EntityIdFactory.getByTypeAndUuid(proto.getEntityType(), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB())); | |
96 | + RuleChainId ruleChainId = new RuleChainId(new UUID(proto.getRuleChainIdMSB(), proto.getRuleChainIdLSB())); | |
97 | + RuleNodeId ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleChainIdLSB())); | |
77 | 98 | TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; |
78 | - return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, dataType, proto.getData()); | |
99 | + return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, proto.getClusterPartition()); | |
79 | 100 | } catch (InvalidProtocolBufferException e) { |
80 | 101 | throw new IllegalStateException("Could not parse protobuf for TbMsg", e); |
81 | 102 | } |
82 | 103 | } |
83 | 104 | |
84 | - public TbMsg copy() { | |
85 | - return new TbMsg(id, type, originator, metaData.copy(), dataType, data); | |
105 | + public TbMsg copy(UUID newId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, long clusterPartition) { | |
106 | + return new TbMsg(newId, type, originator, metaData, dataType, data, ruleChainId, ruleNodeId, clusterPartition); | |
86 | 107 | } |
108 | + | |
87 | 109 | } | ... | ... |
... | ... | @@ -27,10 +27,19 @@ message TbMsgProto { |
27 | 27 | string id = 1; |
28 | 28 | string type = 2; |
29 | 29 | string entityType = 3; |
30 | - string entityId = 4; | |
30 | + int64 entityIdMSB = 4; | |
31 | + int64 entityIdLSB = 5; | |
31 | 32 | |
32 | - TbMsgMetaDataProto metaData = 5; | |
33 | + int64 ruleChainIdMSB = 6; | |
34 | + int64 ruleChainIdLSB = 7; | |
35 | + | |
36 | + int64 ruleNodeIdMSB = 8; | |
37 | + int64 ruleNodeIdLSB = 9; | |
38 | + int64 clusterPartition = 10; | |
39 | + | |
40 | + TbMsgMetaDataProto metaData = 11; | |
41 | + | |
42 | + int32 dataType = 12; | |
43 | + string data = 13; | |
33 | 44 | |
34 | - int32 dataType = 6; | |
35 | - string data = 7; | |
36 | 45 | } |
\ No newline at end of file | ... | ... |
dao/src/main/java/org/thingsboard/server/dao/queue/MsgQueue.java
renamed from
dao/src/main/java/org/thingsboard/server/dao/queue/MsqQueue.java
... | ... | @@ -27,10 +27,9 @@ import lombok.extern.slf4j.Slf4j; |
27 | 27 | import org.springframework.beans.factory.annotation.Autowired; |
28 | 28 | import org.springframework.boot.CommandLineRunner; |
29 | 29 | import org.springframework.boot.SpringApplication; |
30 | -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | |
31 | -import org.springframework.boot.autoconfigure.SpringBootApplication; | |
32 | 30 | import org.springframework.context.annotation.Bean; |
33 | -import org.springframework.context.annotation.ComponentScan; | |
31 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
32 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
34 | 33 | import org.thingsboard.server.common.msg.TbMsg; |
35 | 34 | import org.thingsboard.server.common.msg.TbMsgDataType; |
36 | 35 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
... | ... | @@ -61,11 +60,11 @@ public class QueueBenchmark implements CommandLineRunner { |
61 | 60 | } |
62 | 61 | |
63 | 62 | @Autowired |
64 | - private MsqQueue msqQueue; | |
63 | + private MsgQueue msgQueue; | |
65 | 64 | |
66 | 65 | @Override |
67 | 66 | public void run(String... strings) throws Exception { |
68 | - System.out.println("It works + " + msqQueue); | |
67 | + System.out.println("It works + " + msgQueue); | |
69 | 68 | |
70 | 69 | |
71 | 70 | long start = System.currentTimeMillis(); |
... | ... | @@ -81,8 +80,8 @@ public class QueueBenchmark implements CommandLineRunner { |
81 | 80 | try { |
82 | 81 | TbMsg msg = randomMsg(); |
83 | 82 | UUID nodeId = UUIDs.timeBased(); |
84 | - ListenableFuture<Void> put = msqQueue.put(msg, nodeId, 100L); | |
85 | -// ListenableFuture<Void> put = msqQueue.ack(msg, nodeId, 100L); | |
83 | + ListenableFuture<Void> put = msgQueue.put(msg, nodeId, 100L); | |
84 | +// ListenableFuture<Void> put = msgQueue.ack(msg, nodeId, 100L); | |
86 | 85 | Futures.addCallback(put, new FutureCallback<Void>() { |
87 | 86 | @Override |
88 | 87 | public void onSuccess(@Nullable Void result) { |
... | ... | @@ -126,7 +125,7 @@ public class QueueBenchmark implements CommandLineRunner { |
126 | 125 | TbMsgMetaData metaData = new TbMsgMetaData(); |
127 | 126 | metaData.putValue("key", "value"); |
128 | 127 | String dataStr = "someContent"; |
129 | - return new TbMsg(UUIDs.timeBased(), "type", null, metaData, TbMsgDataType.JSON, dataStr); | |
128 | + return new TbMsg(UUIDs.timeBased(), "type", null, metaData, TbMsgDataType.JSON, dataStr, new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L); | |
130 | 129 | } |
131 | 130 | |
132 | 131 | @Bean | ... | ... |
dao/src/main/java/org/thingsboard/server/dao/service/queue/cassandra/CassandraMsgQueue.java
renamed from
dao/src/main/java/org/thingsboard/server/dao/service/queue/cassandra/CassandraMsqQueue.java
... | ... | @@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j; |
22 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 23 | import org.springframework.stereotype.Component; |
24 | 24 | import org.thingsboard.server.common.msg.TbMsg; |
25 | -import org.thingsboard.server.dao.queue.MsqQueue; | |
25 | +import org.thingsboard.server.dao.queue.MsgQueue; | |
26 | 26 | import org.thingsboard.server.dao.service.queue.cassandra.repository.AckRepository; |
27 | 27 | import org.thingsboard.server.dao.service.queue.cassandra.repository.MsgRepository; |
28 | 28 | import org.thingsboard.server.dao.util.NoSqlDao; |
... | ... | @@ -33,7 +33,7 @@ import java.util.UUID; |
33 | 33 | @Component |
34 | 34 | @Slf4j |
35 | 35 | @NoSqlDao |
36 | -public class CassandraMsqQueue implements MsqQueue { | |
36 | +public class CassandraMsgQueue implements MsgQueue { | |
37 | 37 | |
38 | 38 | @Autowired |
39 | 39 | private MsgRepository msgRepository; | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 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.dao.sql.queue; | |
17 | + | |
18 | +import com.google.common.util.concurrent.Futures; | |
19 | +import com.google.common.util.concurrent.ListenableFuture; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.springframework.stereotype.Component; | |
22 | +import org.thingsboard.server.common.msg.TbMsg; | |
23 | +import org.thingsboard.server.dao.queue.MsgQueue; | |
24 | +import org.thingsboard.server.dao.util.SqlDao; | |
25 | + | |
26 | +import java.util.Collections; | |
27 | +import java.util.UUID; | |
28 | + | |
29 | +/** | |
30 | + * Created by ashvayka on 27.04.18. | |
31 | + */ | |
32 | +@Component | |
33 | +@Slf4j | |
34 | +@SqlDao | |
35 | +public class DummySqlMsgQueue implements MsgQueue { | |
36 | + @Override | |
37 | + public ListenableFuture<Void> put(TbMsg msg, UUID nodeId, long clusterPartition) { | |
38 | + return Futures.immediateFuture(null); | |
39 | + } | |
40 | + | |
41 | + @Override | |
42 | + public ListenableFuture<Void> ack(TbMsg msg, UUID nodeId, long clusterPartition) { | |
43 | + return Futures.immediateFuture(null); | |
44 | + } | |
45 | + | |
46 | + @Override | |
47 | + public Iterable<TbMsg> findUnprocessed(UUID nodeId, long clusterPartition) { | |
48 | + return Collections.emptyList(); | |
49 | + } | |
50 | +} | ... | ... |
... | ... | @@ -33,8 +33,8 @@ public class UnprocessedMsgFilterTest { |
33 | 33 | public void acknowledgedMsgsAreFilteredOut() { |
34 | 34 | UUID id1 = UUID.randomUUID(); |
35 | 35 | UUID id2 = UUID.randomUUID(); |
36 | - TbMsg msg1 = new TbMsg(id1, "T", null, null, null, null); | |
37 | - TbMsg msg2 = new TbMsg(id2, "T", null, null, null, null); | |
36 | + TbMsg msg1 = new TbMsg(id1, "T", null, null, null, null, null, null, 0L); | |
37 | + TbMsg msg2 = new TbMsg(id2, "T", null, null, null, null, null, null, 0L); | |
38 | 38 | List<TbMsg> msgs = Lists.newArrayList(msg1, msg2); |
39 | 39 | List<MsgAck> acks = Lists.newArrayList(new MsgAck(id2, UUID.randomUUID(), 1L, 1L)); |
40 | 40 | Collection<TbMsg> actual = msgFilter.filter(msgs, acks); | ... | ... |
... | ... | @@ -23,6 +23,8 @@ import org.junit.Before; |
23 | 23 | import org.junit.Test; |
24 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 25 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
27 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
26 | 28 | import org.thingsboard.server.common.msg.TbMsg; |
27 | 29 | import org.thingsboard.server.common.msg.TbMsgDataType; |
28 | 30 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
... | ... | @@ -45,7 +47,8 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest { |
45 | 47 | |
46 | 48 | @Test |
47 | 49 | public void msgCanBeSavedAndRead() throws ExecutionException, InterruptedException { |
48 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000"); | |
50 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000", | |
51 | + new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L); | |
49 | 52 | UUID nodeId = UUIDs.timeBased(); |
50 | 53 | ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 1L, 1L, 1L); |
51 | 54 | future.get(); |
... | ... | @@ -55,7 +58,8 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest { |
55 | 58 | |
56 | 59 | @Test |
57 | 60 | public void expiredMsgsAreNotReturned() throws ExecutionException, InterruptedException { |
58 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000"); | |
61 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, "0000", | |
62 | + new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L); | |
59 | 63 | UUID nodeId = UUIDs.timeBased(); |
60 | 64 | ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 2L, 2L, 2L); |
61 | 65 | future.get(); |
... | ... | @@ -68,7 +72,8 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest { |
68 | 72 | TbMsgMetaData metaData = new TbMsgMetaData(); |
69 | 73 | metaData.putValue("key", "value"); |
70 | 74 | String dataStr = "someContent"; |
71 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), metaData, TbMsgDataType.JSON, dataStr); | |
75 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), metaData, TbMsgDataType.JSON, dataStr, | |
76 | + new RuleChainId(UUIDs.timeBased()), new RuleNodeId(UUIDs.timeBased()), 0L); | |
72 | 77 | UUID nodeId = UUIDs.timeBased(); |
73 | 78 | ListenableFuture<Void> future = msgRepository.save(msg, nodeId, 1L, 1L, 1L); |
74 | 79 | future.get(); | ... | ... |
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAlarmNode.java
... | ... | @@ -91,11 +91,11 @@ public class TbAlarmNode implements TbNode { |
91 | 91 | if (alarmResult.alarm == null) { |
92 | 92 | ctx.tellNext(msg, "False"); |
93 | 93 | } else if (alarmResult.isCreated) { |
94 | - ctx.tellNext(toAlarmMsg(alarmResult, msg), "Created"); | |
94 | + ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), "Created"); | |
95 | 95 | } else if (alarmResult.isUpdated) { |
96 | - ctx.tellNext(toAlarmMsg(alarmResult, msg), "Updated"); | |
96 | + ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), "Updated"); | |
97 | 97 | } else if (alarmResult.isCleared) { |
98 | - ctx.tellNext(toAlarmMsg(alarmResult, msg), "Cleared"); | |
98 | + ctx.tellNext(toAlarmMsg(ctx, alarmResult, msg), "Cleared"); | |
99 | 99 | } |
100 | 100 | }, |
101 | 101 | t -> ctx.tellError(msg, t)); |
... | ... | @@ -176,7 +176,7 @@ public class TbAlarmNode implements TbNode { |
176 | 176 | return ctx.getJsExecutor().executeAsync(() -> buildDetailsJsEngine.executeJson(msg)); |
177 | 177 | } |
178 | 178 | |
179 | - private TbMsg toAlarmMsg(AlarmResult alarmResult, TbMsg originalMsg) { | |
179 | + private TbMsg toAlarmMsg(TbContext ctx, AlarmResult alarmResult, TbMsg originalMsg) { | |
180 | 180 | JsonNode jsonNodes = mapper.valueToTree(alarmResult.alarm); |
181 | 181 | String data = jsonNodes.toString(); |
182 | 182 | TbMsgMetaData metaData = originalMsg.getMetaData().copy(); |
... | ... | @@ -187,7 +187,7 @@ public class TbAlarmNode implements TbNode { |
187 | 187 | } else if (alarmResult.isCleared) { |
188 | 188 | metaData.putValue(IS_CLEARED_ALARM, Boolean.TRUE.toString()); |
189 | 189 | } |
190 | - return new TbMsg(UUIDs.timeBased(), "ALARM", originalMsg.getOriginator(), metaData, data); | |
190 | + return ctx.newMsg("ALARM", originalMsg.getOriginator(), metaData, data); | |
191 | 191 | } |
192 | 192 | |
193 | 193 | ... | ... |
... | ... | @@ -78,18 +78,18 @@ public class TbMsgGeneratorNode implements TbNode { |
78 | 78 | } |
79 | 79 | |
80 | 80 | private void sentTickMsg(TbContext ctx) { |
81 | - TbMsg tickMsg = new TbMsg(UUIDs.timeBased(), TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), ""); | |
81 | + TbMsg tickMsg = ctx.newMsg(TB_MSG_GENERATOR_NODE_MSG, ctx.getSelfId(), new TbMsgMetaData(), ""); | |
82 | 82 | nextTickId = tickMsg.getId(); |
83 | 83 | ctx.tellSelf(tickMsg, delay); |
84 | 84 | } |
85 | 85 | |
86 | - protected ListenableFuture<TbMsg> generate(TbContext ctx) { | |
86 | + private ListenableFuture<TbMsg> generate(TbContext ctx) { | |
87 | 87 | return ctx.getJsExecutor().executeAsync(() -> { |
88 | 88 | if (prevMsg == null) { |
89 | - prevMsg = new TbMsg(UUIDs.timeBased(), "", originatorId, new TbMsgMetaData(), "{}"); | |
89 | + prevMsg = ctx.newMsg( "", originatorId, new TbMsgMetaData(), "{}"); | |
90 | 90 | } |
91 | 91 | TbMsg generated = jsEngine.executeGenerate(prevMsg); |
92 | - prevMsg = new TbMsg(UUIDs.timeBased(), generated.getType(), originatorId, generated.getMetaData(), generated.getData()); | |
92 | + prevMsg = ctx.newMsg(generated.getType(), originatorId, generated.getMetaData(), generated.getData()); | |
93 | 93 | return prevMsg; |
94 | 94 | }); |
95 | 95 | } | ... | ... |
... | ... | @@ -76,7 +76,7 @@ public class TbMsgToEmailNode implements TbNode { |
76 | 76 | public void onMsg(TbContext ctx, TbMsg msg) { |
77 | 77 | try { |
78 | 78 | EmailPojo email = convert(msg); |
79 | - TbMsg emailMsg = buildEmailMsg(msg, email); | |
79 | + TbMsg emailMsg = buildEmailMsg(ctx, msg, email); | |
80 | 80 | ctx.tellNext(emailMsg); |
81 | 81 | } catch (Exception ex) { |
82 | 82 | log.warn("Can not convert message to email " + ex.getMessage()); |
... | ... | @@ -84,9 +84,9 @@ public class TbMsgToEmailNode implements TbNode { |
84 | 84 | } |
85 | 85 | } |
86 | 86 | |
87 | - private TbMsg buildEmailMsg(TbMsg msg, EmailPojo email) throws JsonProcessingException { | |
87 | + private TbMsg buildEmailMsg(TbContext ctx, TbMsg msg, EmailPojo email) throws JsonProcessingException { | |
88 | 88 | String emailJson = MAPPER.writeValueAsString(email); |
89 | - return new TbMsg(UUIDs.timeBased(), SEND_EMAIL_TYPE, msg.getOriginator(), msg.getMetaData().copy(), emailJson); | |
89 | + return ctx.newMsg(SEND_EMAIL_TYPE, msg.getOriginator(), msg.getMetaData().copy(), emailJson); | |
90 | 90 | } |
91 | 91 | |
92 | 92 | private EmailPojo convert(TbMsg msg) throws IOException { | ... | ... |
... | ... | @@ -63,8 +63,6 @@ public class TbSendEmailNode implements TbNode { |
63 | 63 | } catch (Exception ex) { |
64 | 64 | ctx.tellError(msg, ex); |
65 | 65 | } |
66 | - | |
67 | - | |
68 | 66 | } |
69 | 67 | |
70 | 68 | private EmailPojo getEmail(TbMsg msg) throws IOException { |
... | ... | @@ -84,6 +82,5 @@ public class TbSendEmailNode implements TbNode { |
84 | 82 | |
85 | 83 | @Override |
86 | 84 | public void destroy() { |
87 | - | |
88 | 85 | } |
89 | 86 | } | ... | ... |
... | ... | @@ -60,7 +60,7 @@ public class TbChangeOriginatorNode extends TbAbstractTransformNode { |
60 | 60 | @Override |
61 | 61 | protected ListenableFuture<TbMsg> transform(TbContext ctx, TbMsg msg) { |
62 | 62 | ListenableFuture<? extends EntityId> newOriginator = getNewOriginator(ctx, msg.getOriginator()); |
63 | - return Futures.transform(newOriginator, (Function<EntityId, TbMsg>) n -> new TbMsg(msg.getId(), msg.getType(), n, msg.getMetaData(), msg.getData())); | |
63 | + return Futures.transform(newOriginator, (Function<EntityId, TbMsg>) n -> ctx.newMsg(msg.getType(), n, msg.getMetaData(), msg.getData())); | |
64 | 64 | } |
65 | 65 | |
66 | 66 | private ListenableFuture<? extends EntityId> getNewOriginator(TbContext ctx, EntityId original) { | ... | ... |
... | ... | @@ -35,6 +35,8 @@ import org.thingsboard.rule.engine.api.*; |
35 | 35 | import org.thingsboard.server.common.data.alarm.Alarm; |
36 | 36 | import org.thingsboard.server.common.data.id.DeviceId; |
37 | 37 | import org.thingsboard.server.common.data.id.EntityId; |
38 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
39 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
38 | 40 | import org.thingsboard.server.common.data.id.TenantId; |
39 | 41 | import org.thingsboard.server.common.msg.TbMsg; |
40 | 42 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
... | ... | @@ -73,6 +75,9 @@ public class TbAlarmNodeTest { |
73 | 75 | @Mock |
74 | 76 | private ScriptEngine detailsJs; |
75 | 77 | |
78 | + private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
79 | + private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
80 | + | |
76 | 81 | private ListeningExecutor dbExecutor; |
77 | 82 | |
78 | 83 | private EntityId originator = new DeviceId(UUIDs.timeBased()); |
... | ... | @@ -103,7 +108,7 @@ public class TbAlarmNodeTest { |
103 | 108 | public void newAlarmCanBeCreated() throws ScriptException, IOException { |
104 | 109 | initWithScript(); |
105 | 110 | metaData.putValue("key", "value"); |
106 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); | |
111 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
107 | 112 | |
108 | 113 | when(createJs.executeFilter(msg)).thenReturn(true); |
109 | 114 | when(detailsJs.executeJson(msg)).thenReturn(null); |
... | ... | @@ -113,17 +118,21 @@ public class TbAlarmNodeTest { |
113 | 118 | |
114 | 119 | node.onMsg(ctx, msg); |
115 | 120 | |
116 | - ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); | |
117 | - verify(ctx).tellNext(captor.capture(), eq("Created")); | |
118 | - TbMsg actualMsg = captor.getValue(); | |
121 | + verify(ctx).tellNext(any(), eq("Created")); | |
122 | + | |
123 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | |
124 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | |
125 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | |
126 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | |
127 | + verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | |
119 | 128 | |
120 | - assertEquals("ALARM", actualMsg.getType()); | |
121 | - assertEquals(originator, actualMsg.getOriginator()); | |
122 | - assertEquals("value", actualMsg.getMetaData().getValue("key")); | |
123 | - assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_NEW_ALARM)); | |
124 | - assertNotSame(metaData, actualMsg.getMetaData()); | |
129 | + assertEquals("ALARM", typeCaptor.getValue()); | |
130 | + assertEquals(originator, originatorCaptor.getValue()); | |
131 | + assertEquals("value", metadataCaptor.getValue().getValue("key")); | |
132 | + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM)); | |
133 | + assertNotSame(metaData, metadataCaptor.getValue()); | |
125 | 134 | |
126 | - Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class); | |
135 | + Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); | |
127 | 136 | Alarm expectedAlarm = Alarm.builder() |
128 | 137 | .tenantId(tenantId) |
129 | 138 | .originator(originator) |
... | ... | @@ -143,7 +152,7 @@ public class TbAlarmNodeTest { |
143 | 152 | public void shouldCreateScriptThrowsException() throws ScriptException { |
144 | 153 | initWithScript(); |
145 | 154 | metaData.putValue("key", "value"); |
146 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); | |
155 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
147 | 156 | |
148 | 157 | when(createJs.executeFilter(msg)).thenThrow(new NotImplementedException("message")); |
149 | 158 | |
... | ... | @@ -165,7 +174,7 @@ public class TbAlarmNodeTest { |
165 | 174 | public void buildDetailsThrowsException() throws ScriptException, IOException { |
166 | 175 | initWithScript(); |
167 | 176 | metaData.putValue("key", "value"); |
168 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); | |
177 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
169 | 178 | |
170 | 179 | when(createJs.executeFilter(msg)).thenReturn(true); |
171 | 180 | when(detailsJs.executeJson(msg)).thenThrow(new NotImplementedException("message")); |
... | ... | @@ -191,7 +200,7 @@ public class TbAlarmNodeTest { |
191 | 200 | public void ifAlarmClearedCreateNew() throws ScriptException, IOException { |
192 | 201 | initWithScript(); |
193 | 202 | metaData.putValue("key", "value"); |
194 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); | |
203 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
195 | 204 | |
196 | 205 | Alarm clearedAlarm = Alarm.builder().status(CLEARED_ACK).build(); |
197 | 206 | |
... | ... | @@ -203,17 +212,22 @@ public class TbAlarmNodeTest { |
203 | 212 | |
204 | 213 | node.onMsg(ctx, msg); |
205 | 214 | |
206 | - ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); | |
207 | - verify(ctx).tellNext(captor.capture(), eq("Created")); | |
208 | - TbMsg actualMsg = captor.getValue(); | |
215 | + verify(ctx).tellNext(any(), eq("Created")); | |
216 | + | |
217 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | |
218 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | |
219 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | |
220 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | |
221 | + verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | |
209 | 222 | |
210 | - assertEquals("ALARM", actualMsg.getType()); | |
211 | - assertEquals(originator, actualMsg.getOriginator()); | |
212 | - assertEquals("value", actualMsg.getMetaData().getValue("key")); | |
213 | - assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_NEW_ALARM)); | |
214 | - assertNotSame(metaData, actualMsg.getMetaData()); | |
223 | + assertEquals("ALARM", typeCaptor.getValue()); | |
224 | + assertEquals(originator, originatorCaptor.getValue()); | |
225 | + assertEquals("value", metadataCaptor.getValue().getValue("key")); | |
226 | + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_NEW_ALARM)); | |
227 | + assertNotSame(metaData, metadataCaptor.getValue()); | |
215 | 228 | |
216 | - Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class); | |
229 | + | |
230 | + Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); | |
217 | 231 | Alarm expectedAlarm = Alarm.builder() |
218 | 232 | .tenantId(tenantId) |
219 | 233 | .originator(originator) |
... | ... | @@ -233,7 +247,7 @@ public class TbAlarmNodeTest { |
233 | 247 | public void alarmCanBeUpdated() throws ScriptException, IOException { |
234 | 248 | initWithScript(); |
235 | 249 | metaData.putValue("key", "value"); |
236 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); | |
250 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
237 | 251 | |
238 | 252 | long oldEndDate = System.currentTimeMillis(); |
239 | 253 | Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build(); |
... | ... | @@ -247,17 +261,21 @@ public class TbAlarmNodeTest { |
247 | 261 | |
248 | 262 | node.onMsg(ctx, msg); |
249 | 263 | |
250 | - ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); | |
251 | - verify(ctx).tellNext(captor.capture(), eq("Updated")); | |
252 | - TbMsg actualMsg = captor.getValue(); | |
264 | + verify(ctx).tellNext(any(), eq("Updated")); | |
265 | + | |
266 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | |
267 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | |
268 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | |
269 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | |
270 | + verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | |
253 | 271 | |
254 | - assertEquals("ALARM", actualMsg.getType()); | |
255 | - assertEquals(originator, actualMsg.getOriginator()); | |
256 | - assertEquals("value", actualMsg.getMetaData().getValue("key")); | |
257 | - assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_EXISTING_ALARM)); | |
258 | - assertNotSame(metaData, actualMsg.getMetaData()); | |
272 | + assertEquals("ALARM", typeCaptor.getValue()); | |
273 | + assertEquals(originator, originatorCaptor.getValue()); | |
274 | + assertEquals("value", metadataCaptor.getValue().getValue("key")); | |
275 | + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_EXISTING_ALARM)); | |
276 | + assertNotSame(metaData, metadataCaptor.getValue()); | |
259 | 277 | |
260 | - Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class); | |
278 | + Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); | |
261 | 279 | assertTrue(activeAlarm.getEndTs() > oldEndDate); |
262 | 280 | Alarm expectedAlarm = Alarm.builder() |
263 | 281 | .tenantId(tenantId) |
... | ... | @@ -279,7 +297,7 @@ public class TbAlarmNodeTest { |
279 | 297 | public void alarmCanBeCleared() throws ScriptException, IOException { |
280 | 298 | initWithScript(); |
281 | 299 | metaData.putValue("key", "value"); |
282 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); | |
300 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
283 | 301 | |
284 | 302 | long oldEndDate = System.currentTimeMillis(); |
285 | 303 | Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build(); |
... | ... | @@ -293,17 +311,21 @@ public class TbAlarmNodeTest { |
293 | 311 | |
294 | 312 | node.onMsg(ctx, msg); |
295 | 313 | |
296 | - ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); | |
297 | - verify(ctx).tellNext(captor.capture(), eq("Cleared")); | |
298 | - TbMsg actualMsg = captor.getValue(); | |
314 | + verify(ctx).tellNext(any(), eq("Cleared")); | |
315 | + | |
316 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | |
317 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | |
318 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | |
319 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | |
320 | + verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | |
299 | 321 | |
300 | - assertEquals("ALARM", actualMsg.getType()); | |
301 | - assertEquals(originator, actualMsg.getOriginator()); | |
302 | - assertEquals("value", actualMsg.getMetaData().getValue("key")); | |
303 | - assertEquals(Boolean.TRUE.toString(), actualMsg.getMetaData().getValue(IS_CLEARED_ALARM)); | |
304 | - assertNotSame(metaData, actualMsg.getMetaData()); | |
322 | + assertEquals("ALARM", typeCaptor.getValue()); | |
323 | + assertEquals(originator, originatorCaptor.getValue()); | |
324 | + assertEquals("value", metadataCaptor.getValue().getValue("key")); | |
325 | + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_CLEARED_ALARM)); | |
326 | + assertNotSame(metaData, metadataCaptor.getValue()); | |
305 | 327 | |
306 | - Alarm actualAlarm = new ObjectMapper().readValue(actualMsg.getData().getBytes(), Alarm.class); | |
328 | + Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); | |
307 | 329 | Alarm expectedAlarm = Alarm.builder() |
308 | 330 | .tenantId(tenantId) |
309 | 331 | .originator(originator) | ... | ... |
... | ... | @@ -27,6 +27,8 @@ import org.mockito.Mock; |
27 | 27 | import org.mockito.runners.MockitoJUnitRunner; |
28 | 28 | import org.mockito.stubbing.Answer; |
29 | 29 | import org.thingsboard.rule.engine.api.*; |
30 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
31 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
30 | 32 | import org.thingsboard.server.common.msg.TbMsg; |
31 | 33 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
32 | 34 | |
... | ... | @@ -48,10 +50,13 @@ public class TbJsFilterNodeTest { |
48 | 50 | @Mock |
49 | 51 | private ScriptEngine scriptEngine; |
50 | 52 | |
53 | + private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
54 | + private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
55 | + | |
51 | 56 | @Test |
52 | 57 | public void falseEvaluationDoNotSendMsg() throws TbNodeException, ScriptException { |
53 | 58 | initWithScript(); |
54 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, new TbMsgMetaData(), "{}"); | |
59 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
55 | 60 | mockJsExecutor(); |
56 | 61 | when(scriptEngine.executeFilter(msg)).thenReturn(false); |
57 | 62 | |
... | ... | @@ -64,7 +69,7 @@ public class TbJsFilterNodeTest { |
64 | 69 | public void exceptionInJsThrowsException() throws TbNodeException, ScriptException { |
65 | 70 | initWithScript(); |
66 | 71 | TbMsgMetaData metaData = new TbMsgMetaData(); |
67 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}"); | |
72 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}", ruleChainId, ruleNodeId, 0L); | |
68 | 73 | mockJsExecutor(); |
69 | 74 | when(scriptEngine.executeFilter(msg)).thenThrow(new ScriptException("error")); |
70 | 75 | |
... | ... | @@ -77,7 +82,7 @@ public class TbJsFilterNodeTest { |
77 | 82 | public void metadataConditionCanBeTrue() throws TbNodeException, ScriptException { |
78 | 83 | initWithScript(); |
79 | 84 | TbMsgMetaData metaData = new TbMsgMetaData(); |
80 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}"); | |
85 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{}", ruleChainId, ruleNodeId, 0L); | |
81 | 86 | mockJsExecutor(); |
82 | 87 | when(scriptEngine.executeFilter(msg)).thenReturn(true); |
83 | 88 | ... | ... |
... | ... | @@ -28,6 +28,8 @@ import org.mockito.Mock; |
28 | 28 | import org.mockito.runners.MockitoJUnitRunner; |
29 | 29 | import org.mockito.stubbing.Answer; |
30 | 30 | import org.thingsboard.rule.engine.api.*; |
31 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
32 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
31 | 33 | import org.thingsboard.server.common.msg.TbMsg; |
32 | 34 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
33 | 35 | |
... | ... | @@ -51,6 +53,9 @@ public class TbJsSwitchNodeTest { |
51 | 53 | @Mock |
52 | 54 | private ScriptEngine scriptEngine; |
53 | 55 | |
56 | + private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
57 | + private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
58 | + | |
54 | 59 | @Test |
55 | 60 | public void multipleRoutesAreAllowed() throws TbNodeException, ScriptException { |
56 | 61 | initWithScript(); |
... | ... | @@ -59,7 +64,7 @@ public class TbJsSwitchNodeTest { |
59 | 64 | metaData.putValue("humidity", "99"); |
60 | 65 | String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; |
61 | 66 | |
62 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
67 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
63 | 68 | mockJsExecutor(); |
64 | 69 | when(scriptEngine.executeSwitch(msg)).thenReturn(Sets.newHashSet("one", "three")); |
65 | 70 | ... | ... |
... | ... | @@ -27,6 +27,8 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
27 | 27 | import org.thingsboard.rule.engine.api.TbNodeException; |
28 | 28 | import org.thingsboard.server.common.data.id.DeviceId; |
29 | 29 | import org.thingsboard.server.common.data.id.EntityId; |
30 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
31 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
30 | 32 | import org.thingsboard.server.common.msg.TbMsg; |
31 | 33 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
32 | 34 | |
... | ... | @@ -34,7 +36,9 @@ import java.io.IOException; |
34 | 36 | |
35 | 37 | import static org.junit.Assert.assertEquals; |
36 | 38 | import static org.junit.Assert.assertNotSame; |
39 | +import static org.mockito.Matchers.any; | |
37 | 40 | import static org.mockito.Mockito.verify; |
41 | +import static org.mockito.Mockito.when; | |
38 | 42 | |
39 | 43 | @RunWith(MockitoJUnitRunner.class) |
40 | 44 | public class TbMsgToEmailNodeTest { |
... | ... | @@ -48,26 +52,31 @@ public class TbMsgToEmailNodeTest { |
48 | 52 | private TbMsgMetaData metaData = new TbMsgMetaData(); |
49 | 53 | private String rawJson = "{\"name\": \"temp\", \"passed\": 5 , \"complex\": {\"val\":12, \"count\":100}}"; |
50 | 54 | |
55 | + private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
56 | + private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
57 | + | |
51 | 58 | @Test |
52 | 59 | public void msgCanBeConverted() throws IOException { |
53 | 60 | initWithScript(); |
54 | 61 | metaData.putValue("username", "oreo"); |
55 | 62 | metaData.putValue("userEmail", "user@email.io"); |
56 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson); | |
63 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", originator, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
57 | 64 | |
58 | 65 | emailNode.onMsg(ctx, msg); |
59 | 66 | |
60 | - ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); | |
61 | - verify(ctx).tellNext(captor.capture()); | |
62 | - TbMsg actualMsg = captor.getValue(); | |
67 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | |
68 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | |
69 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | |
70 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | |
71 | + verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | |
63 | 72 | |
64 | - assertEquals("SEND_EMAIL", actualMsg.getType()); | |
65 | - assertEquals(originator, actualMsg.getOriginator()); | |
66 | - assertEquals("oreo", actualMsg.getMetaData().getValue("username")); | |
67 | - assertNotSame(metaData, actualMsg.getMetaData()); | |
68 | 73 | |
74 | + assertEquals("SEND_EMAIL", typeCaptor.getValue()); | |
75 | + assertEquals(originator, originatorCaptor.getValue()); | |
76 | + assertEquals("oreo", metadataCaptor.getValue().getValue("username")); | |
77 | + assertNotSame(metaData, metadataCaptor.getValue()); | |
69 | 78 | |
70 | - EmailPojo actual = new ObjectMapper().readValue(actualMsg.getData().getBytes(), EmailPojo.class); | |
79 | + EmailPojo actual = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), EmailPojo.class); | |
71 | 80 | |
72 | 81 | EmailPojo expected = new EmailPojo.EmailPojoBuilder() |
73 | 82 | .from("test@mail.org") | ... | ... |
... | ... | @@ -34,6 +34,8 @@ import org.thingsboard.server.common.data.asset.Asset; |
34 | 34 | import org.thingsboard.server.common.data.id.AssetId; |
35 | 35 | import org.thingsboard.server.common.data.id.CustomerId; |
36 | 36 | import org.thingsboard.server.common.data.id.DeviceId; |
37 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
38 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
37 | 39 | import org.thingsboard.server.common.data.id.UserId; |
38 | 40 | import org.thingsboard.server.common.data.kv.*; |
39 | 41 | import org.thingsboard.server.common.msg.TbMsg; |
... | ... | @@ -77,6 +79,9 @@ public class TbGetCustomerAttributeNodeTest { |
77 | 79 | |
78 | 80 | private TbMsg msg; |
79 | 81 | |
82 | + private RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
83 | + private RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
84 | + | |
80 | 85 | @Before |
81 | 86 | public void init() throws TbNodeException { |
82 | 87 | TbGetEntityAttrNodeConfiguration config = new TbGetEntityAttrNodeConfiguration(); |
... | ... | @@ -98,7 +103,8 @@ public class TbGetCustomerAttributeNodeTest { |
98 | 103 | User user = new User(); |
99 | 104 | user.setCustomerId(customerId); |
100 | 105 | |
101 | - msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}"); | |
106 | + | |
107 | + msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
102 | 108 | |
103 | 109 | when(ctx.getUserService()).thenReturn(userService); |
104 | 110 | when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user)); |
... | ... | @@ -123,7 +129,7 @@ public class TbGetCustomerAttributeNodeTest { |
123 | 129 | User user = new User(); |
124 | 130 | user.setCustomerId(customerId); |
125 | 131 | |
126 | - msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}"); | |
132 | + msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
127 | 133 | |
128 | 134 | when(ctx.getUserService()).thenReturn(userService); |
129 | 135 | when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user)); |
... | ... | @@ -148,7 +154,7 @@ public class TbGetCustomerAttributeNodeTest { |
148 | 154 | User user = new User(); |
149 | 155 | user.setCustomerId(customerId); |
150 | 156 | |
151 | - msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}"); | |
157 | + msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
152 | 158 | |
153 | 159 | when(ctx.getUserService()).thenReturn(userService); |
154 | 160 | when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(null)); |
... | ... | @@ -166,7 +172,7 @@ public class TbGetCustomerAttributeNodeTest { |
166 | 172 | @Test |
167 | 173 | public void customerAttributeAddedInMetadata() { |
168 | 174 | CustomerId customerId = new CustomerId(UUIDs.timeBased()); |
169 | - msg = new TbMsg(UUIDs.timeBased(), "CUSTOMER", customerId, new TbMsgMetaData(), "{}"); | |
175 | + msg = new TbMsg(UUIDs.timeBased(), "CUSTOMER", customerId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
170 | 176 | entityAttributeFetched(customerId); |
171 | 177 | } |
172 | 178 | |
... | ... | @@ -177,7 +183,7 @@ public class TbGetCustomerAttributeNodeTest { |
177 | 183 | User user = new User(); |
178 | 184 | user.setCustomerId(customerId); |
179 | 185 | |
180 | - msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}"); | |
186 | + msg = new TbMsg(UUIDs.timeBased(), "USER", userId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
181 | 187 | |
182 | 188 | when(ctx.getUserService()).thenReturn(userService); |
183 | 189 | when(userService.findUserByIdAsync(userId)).thenReturn(Futures.immediateFuture(user)); |
... | ... | @@ -192,7 +198,7 @@ public class TbGetCustomerAttributeNodeTest { |
192 | 198 | Asset asset = new Asset(); |
193 | 199 | asset.setCustomerId(customerId); |
194 | 200 | |
195 | - msg = new TbMsg(UUIDs.timeBased(), "USER", assetId, new TbMsgMetaData(), "{}"); | |
201 | + msg = new TbMsg(UUIDs.timeBased(), "USER", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
196 | 202 | |
197 | 203 | when(ctx.getAssetService()).thenReturn(assetService); |
198 | 204 | when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset)); |
... | ... | @@ -207,7 +213,7 @@ public class TbGetCustomerAttributeNodeTest { |
207 | 213 | Device device = new Device(); |
208 | 214 | device.setCustomerId(customerId); |
209 | 215 | |
210 | - msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}"); | |
216 | + msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
211 | 217 | |
212 | 218 | when(ctx.getDeviceService()).thenReturn(deviceService); |
213 | 219 | when(deviceService.findDeviceByIdAsync(deviceId)).thenReturn(Futures.immediateFuture(device)); |
... | ... | @@ -234,7 +240,7 @@ public class TbGetCustomerAttributeNodeTest { |
234 | 240 | Device device = new Device(); |
235 | 241 | device.setCustomerId(customerId); |
236 | 242 | |
237 | - msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}"); | |
243 | + msg = new TbMsg(UUIDs.timeBased(), "USER", deviceId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
238 | 244 | |
239 | 245 | when(ctx.getDeviceService()).thenReturn(deviceService); |
240 | 246 | when(deviceService.findDeviceByIdAsync(deviceId)).thenReturn(Futures.immediateFuture(device)); | ... | ... |
... | ... | @@ -29,6 +29,9 @@ import org.thingsboard.rule.engine.api.TbNodeException; |
29 | 29 | import org.thingsboard.server.common.data.asset.Asset; |
30 | 30 | import org.thingsboard.server.common.data.id.AssetId; |
31 | 31 | import org.thingsboard.server.common.data.id.CustomerId; |
32 | +import org.thingsboard.server.common.data.id.EntityId; | |
33 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
34 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
32 | 35 | import org.thingsboard.server.common.msg.TbMsg; |
33 | 36 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
34 | 37 | import org.thingsboard.server.dao.asset.AssetService; |
... | ... | @@ -57,17 +60,23 @@ public class TbChangeOriginatorNodeTest { |
57 | 60 | Asset asset = new Asset(); |
58 | 61 | asset.setCustomerId(customerId); |
59 | 62 | |
60 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}"); | |
63 | + RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
64 | + RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
65 | + | |
66 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
61 | 67 | |
62 | 68 | when(ctx.getAssetService()).thenReturn(assetService); |
63 | 69 | when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset)); |
64 | 70 | |
65 | 71 | node.onMsg(ctx, msg); |
66 | - ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); | |
67 | - verify(ctx).tellNext(captor.capture()); | |
68 | - TbMsg actualMsg = captor.getValue(); | |
69 | - assertEquals(customerId, actualMsg.getOriginator()); | |
70 | - assertEquals(msg.getId(), actualMsg.getId()); | |
72 | + | |
73 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | |
74 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | |
75 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | |
76 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | |
77 | + verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | |
78 | + | |
79 | + assertEquals(customerId, originatorCaptor.getValue()); | |
71 | 80 | } |
72 | 81 | |
73 | 82 | @Test |
... | ... | @@ -78,17 +87,22 @@ public class TbChangeOriginatorNodeTest { |
78 | 87 | Asset asset = new Asset(); |
79 | 88 | asset.setCustomerId(customerId); |
80 | 89 | |
81 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}"); | |
90 | + RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
91 | + RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
92 | + | |
93 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
82 | 94 | |
83 | 95 | when(ctx.getAssetService()).thenReturn(assetService); |
84 | 96 | when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFuture(asset)); |
85 | 97 | |
86 | 98 | node.onMsg(ctx, msg); |
87 | - ArgumentCaptor<TbMsg> captor = ArgumentCaptor.forClass(TbMsg.class); | |
88 | - verify(ctx).spawn(captor.capture()); | |
89 | - TbMsg actualMsg = captor.getValue(); | |
90 | - assertEquals(customerId, actualMsg.getOriginator()); | |
91 | - assertEquals(msg.getId(), actualMsg.getId()); | |
99 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | |
100 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | |
101 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | |
102 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | |
103 | + verify(ctx).newMsg(typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | |
104 | + | |
105 | + assertEquals(customerId, originatorCaptor.getValue()); | |
92 | 106 | } |
93 | 107 | |
94 | 108 | @Test |
... | ... | @@ -99,7 +113,10 @@ public class TbChangeOriginatorNodeTest { |
99 | 113 | Asset asset = new Asset(); |
100 | 114 | asset.setCustomerId(customerId); |
101 | 115 | |
102 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}"); | |
116 | + RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
117 | + RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
118 | + | |
119 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "ASSET", assetId, new TbMsgMetaData(), "{}", ruleChainId, ruleNodeId, 0L); | |
103 | 120 | |
104 | 121 | when(ctx.getAssetService()).thenReturn(assetService); |
105 | 122 | when(assetService.findAssetByIdAsync(assetId)).thenReturn(Futures.immediateFailedFuture(new IllegalStateException("wrong"))); | ... | ... |
... | ... | @@ -27,6 +27,8 @@ import org.mockito.Mock; |
27 | 27 | import org.mockito.runners.MockitoJUnitRunner; |
28 | 28 | import org.mockito.stubbing.Answer; |
29 | 29 | import org.thingsboard.rule.engine.api.*; |
30 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
31 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
30 | 32 | import org.thingsboard.server.common.msg.TbMsg; |
31 | 33 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
32 | 34 | |
... | ... | @@ -56,8 +58,10 @@ public class TbTransformMsgNodeTest { |
56 | 58 | metaData.putValue("temp", "7"); |
57 | 59 | String rawJson = "{\"passed\": 5}"; |
58 | 60 | |
59 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
60 | - TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}"); | |
61 | + RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
62 | + RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
63 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
64 | + TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}", ruleChainId, ruleNodeId, 0L); | |
61 | 65 | mockJsExecutor(); |
62 | 66 | when(scriptEngine.executeUpdate(msg)).thenReturn(transformedMsg); |
63 | 67 | |
... | ... | @@ -77,8 +81,10 @@ public class TbTransformMsgNodeTest { |
77 | 81 | metaData.putValue("temp", "7"); |
78 | 82 | String rawJson = "{\"passed\": 5"; |
79 | 83 | |
80 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
81 | - TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}"); | |
84 | + RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
85 | + RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
86 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
87 | + TbMsg transformedMsg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, "{new}", ruleChainId, ruleNodeId, 0L); | |
82 | 88 | mockJsExecutor(); |
83 | 89 | when(scriptEngine.executeUpdate(msg)).thenReturn(transformedMsg); |
84 | 90 | |
... | ... | @@ -97,7 +103,9 @@ public class TbTransformMsgNodeTest { |
97 | 103 | metaData.putValue("temp", "7"); |
98 | 104 | String rawJson = "{\"passed\": 5"; |
99 | 105 | |
100 | - TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson); | |
106 | + RuleChainId ruleChainId = new RuleChainId(UUIDs.timeBased()); | |
107 | + RuleNodeId ruleNodeId = new RuleNodeId(UUIDs.timeBased()); | |
108 | + TbMsg msg = new TbMsg(UUIDs.timeBased(), "USER", null, metaData, rawJson, ruleChainId, ruleNodeId, 0L); | |
101 | 109 | mockJsExecutor(); |
102 | 110 | when(scriptEngine.executeUpdate(msg)).thenThrow(new IllegalStateException("error")); |
103 | 111 | ... | ... |