Commit 79c9473554d0a8452361a09c03570966a6af440b

Authored by Volodymyr Babak
2 parents e832759e 5b413a4b

Merge remote-tracking branch 'vbabak/feature/edge' into bug/device_credentials_from_edge

Showing 63 changed files with 418 additions and 336 deletions
... ... @@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
35 35 import org.thingsboard.rule.engine.api.MailService;
36 36 import org.thingsboard.server.common.data.User;
37 37 import org.thingsboard.server.common.data.audit.ActionType;
  38 +import org.thingsboard.server.common.data.edge.EdgeEventType;
38 39 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
39 40 import org.thingsboard.server.common.data.exception.ThingsboardException;
40 41 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -124,6 +125,9 @@ public class AuthController extends BaseController {
124 125 }
125 126 userCredentials.setPassword(passwordEncoder.encode(newPassword));
126 127 userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials);
  128 +
  129 + sendNotificationMsgToEdgeService(getTenantId(), null, userCredentials.getUserId(), EdgeEventType.USER, ActionType.CREDENTIALS_UPDATED);
  130 +
127 131 } catch (Exception e) {
128 132 throw handleException(e);
129 133 }
... ...
... ... @@ -26,12 +26,12 @@ import org.springframework.beans.factory.annotation.Value;
26 26 import org.springframework.security.core.Authentication;
27 27 import org.springframework.security.core.context.SecurityContextHolder;
28 28 import org.springframework.web.bind.annotation.ExceptionHandler;
29   -import org.thingsboard.server.common.data.BaseData;
30 29 import org.thingsboard.server.common.data.Customer;
31 30 import org.thingsboard.server.common.data.Dashboard;
32 31 import org.thingsboard.server.common.data.DashboardInfo;
33 32 import org.thingsboard.server.common.data.DataConstants;
34 33 import org.thingsboard.server.common.data.Device;
  34 +import org.thingsboard.server.common.data.EdgeUtils;
35 35 import org.thingsboard.server.common.data.EntityType;
36 36 import org.thingsboard.server.common.data.EntityView;
37 37 import org.thingsboard.server.common.data.HasName;
... ... @@ -39,14 +39,14 @@ import org.thingsboard.server.common.data.HasTenantId;
39 39 import org.thingsboard.server.common.data.Tenant;
40 40 import org.thingsboard.server.common.data.User;
41 41 import org.thingsboard.server.common.data.alarm.Alarm;
42   -import org.thingsboard.server.common.data.edge.EdgeEventType;
43   -import org.thingsboard.server.common.data.id.AlarmId;
44 42 import org.thingsboard.server.common.data.alarm.AlarmInfo;
45 43 import org.thingsboard.server.common.data.asset.Asset;
46 44 import org.thingsboard.server.common.data.audit.ActionType;
47 45 import org.thingsboard.server.common.data.edge.Edge;
  46 +import org.thingsboard.server.common.data.edge.EdgeEventType;
48 47 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
49 48 import org.thingsboard.server.common.data.exception.ThingsboardException;
  49 +import org.thingsboard.server.common.data.id.AlarmId;
50 50 import org.thingsboard.server.common.data.id.AssetId;
51 51 import org.thingsboard.server.common.data.id.CustomerId;
52 52 import org.thingsboard.server.common.data.id.DashboardId;
... ... @@ -85,7 +85,6 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
85 85 import org.thingsboard.server.dao.device.ClaimDevicesService;
86 86 import org.thingsboard.server.dao.device.DeviceCredentialsService;
87 87 import org.thingsboard.server.dao.device.DeviceService;
88   -import org.thingsboard.server.dao.edge.EdgeEventService;
89 88 import org.thingsboard.server.dao.edge.EdgeService;
90 89 import org.thingsboard.server.dao.entityview.EntityViewService;
91 90 import org.thingsboard.server.dao.exception.DataValidationException;
... ... @@ -113,7 +112,6 @@ import org.thingsboard.server.service.state.DeviceStateService;
113 112 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
114 113
115 114 import javax.mail.MessagingException;
116   -import javax.management.relation.Relation;
117 115 import javax.servlet.http.HttpServletResponse;
118 116 import java.util.List;
119 117 import java.util.Optional;
... ... @@ -209,9 +207,6 @@ public abstract class BaseController {
209 207 @Autowired
210 208 protected EdgeNotificationService edgeNotificationService;
211 209
212   - @Autowired
213   - protected EdgeEventService edgeEventService;
214   -
215 210 @Value("${server.log_controller_error_stack_trace}")
216 211 @Getter
217 212 private boolean logControllerErrorStackTrace;
... ... @@ -735,7 +730,7 @@ public abstract class BaseController {
735 730 }
736 731
737 732 protected void sendNotificationMsgToEdgeService(TenantId tenantId, EntityId entityId, ActionType edgeEventAction) {
738   - EdgeEventType edgeEventType = edgeEventService.getEdgeEventTypeByEntityType(entityId.getEntityType());
  733 + EdgeEventType edgeEventType = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
739 734 if (edgeEventType != null) {
740 735 sendNotificationMsgToEdgeService(tenantId, null, entityId, null, edgeEventType, edgeEventAction);
741 736 }
... ...
... ... @@ -35,17 +35,14 @@ import org.thingsboard.rule.engine.api.MailService;
35 35 import org.thingsboard.server.common.data.EntityType;
36 36 import org.thingsboard.server.common.data.User;
37 37 import org.thingsboard.server.common.data.audit.ActionType;
38   -import org.thingsboard.server.common.data.edge.Edge;
  38 +import org.thingsboard.server.common.data.edge.EdgeEventType;
39 39 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
40 40 import org.thingsboard.server.common.data.exception.ThingsboardException;
41 41 import org.thingsboard.server.common.data.id.CustomerId;
42   -import org.thingsboard.server.common.data.id.EdgeId;
43 42 import org.thingsboard.server.common.data.id.TenantId;
44 43 import org.thingsboard.server.common.data.id.UserId;
45 44 import org.thingsboard.server.common.data.page.TextPageData;
46 45 import org.thingsboard.server.common.data.page.TextPageLink;
47   -import org.thingsboard.server.common.data.page.TimePageData;
48   -import org.thingsboard.server.common.data.page.TimePageLink;
49 46 import org.thingsboard.server.common.data.security.Authority;
50 47 import org.thingsboard.server.common.data.security.UserCredentials;
51 48 import org.thingsboard.server.queue.util.TbCoreComponent;
... ... @@ -60,8 +57,6 @@ import org.thingsboard.server.utils.MiscUtils;
60 57
61 58 import javax.servlet.http.HttpServletRequest;
62 59
63   -import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
64   -
65 60 @RestController
66 61 @TbCoreComponent
67 62 @RequestMapping("/api")
... ... @@ -167,6 +162,8 @@ public class UserController extends BaseController {
167 162 savedUser.getCustomerId(),
168 163 user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
169 164
  165 + sendNotificationMsgToEdgeService(getTenantId(), null, user.getId(), EdgeEventType.USER, user.getId() == null ? ActionType.ADDED : ActionType.UPDATED);
  166 +
170 167 return savedUser;
171 168 } catch (Exception e) {
172 169
... ... @@ -242,6 +239,8 @@ public class UserController extends BaseController {
242 239 user.getCustomerId(),
243 240 ActionType.DELETED, null, strUserId);
244 241
  242 + sendNotificationMsgToEdgeService(getTenantId(), null, user.getId(), EdgeEventType.USER, ActionType.DELETED);
  243 +
245 244 } catch (Exception e) {
246 245 logEntityAction(emptyId(EntityType.USER),
247 246 null,
... ...
... ... @@ -174,6 +174,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
174 174 // TODO: voba - ADDED is not required for CE version ?
175 175 // case ADDED:
176 176 case UPDATED:
  177 + case CREDENTIALS_UPDATED:
177 178 ListenableFuture<List<EdgeId>> edgeIdsFuture = findRelatedEdgeIdsByEntityId(tenantId, entityId);
178 179 Futures.transform(edgeIdsFuture, edgeIds -> {
179 180 if (edgeIds != null && !edgeIds.isEmpty()) {
... ...
... ... @@ -194,11 +194,23 @@ public final class EdgeGrpcSession implements Closeable {
194 194 for (EdgeEvent edgeEvent : pageData.getData()) {
195 195 log.trace("[{}] Processing edge event [{}]", this.sessionId, edgeEvent);
196 196 try {
197   - UpdateMsgType msgType = getResponseMsgType(ActionType.valueOf(edgeEvent.getEdgeEventAction()));
198   - if (msgType == null) {
199   - processTelemetryMessage(edgeEvent);
200   - } else {
201   - processEntityCRUDMessage(edgeEvent, msgType);
  197 + ActionType edgeEventAction = ActionType.valueOf(edgeEvent.getEdgeEventAction());
  198 + switch (edgeEventAction) {
  199 + case UPDATED:
  200 + case ADDED:
  201 + case ASSIGNED_TO_EDGE:
  202 + case DELETED:
  203 + case UNASSIGNED_FROM_EDGE:
  204 + case ALARM_ACK:
  205 + case ALARM_CLEAR:
  206 + case CREDENTIALS_UPDATED:
  207 + processEntityMessage(edgeEvent, edgeEventAction);
  208 + break;
  209 + case ATTRIBUTES_UPDATED:
  210 + case ATTRIBUTES_DELETED:
  211 + case TIMESERIES_UPDATED:
  212 + processTelemetryMessage(edgeEvent);
  213 + break;
202 214 }
203 215 } catch (Exception e) {
204 216 log.error("Exception during processing records from queue", e);
... ... @@ -237,7 +249,7 @@ public final class EdgeGrpcSession implements Closeable {
237 249 } else {
238 250 return 0L;
239 251 }
240   - }, MoreExecutors.directExecutor());
  252 + }, ctx.getDbCallbackExecutor());
241 253 }
242 254
243 255 private void updateQueueStartTs(Long newStartTs) {
... ... @@ -259,7 +271,9 @@ public final class EdgeGrpcSession implements Closeable {
259 271 case ENTITY_VIEW:
260 272 entityId = new EntityViewId(edgeEvent.getEntityId());
261 273 break;
262   -
  274 + case DASHBOARD:
  275 + entityId = new DashboardId(edgeEvent.getEntityId());
  276 + break;
263 277 }
264 278 if (entityId != null) {
265 279 log.debug("Sending telemetry data msg, entityId [{}], body [{}]", edgeEvent.getEntityId(), edgeEvent.getEntityBody());
... ... @@ -277,217 +291,212 @@ public final class EdgeGrpcSession implements Closeable {
277 291 }
278 292 }
279 293
280   - private void processEntityCRUDMessage(EdgeEvent edgeEvent, UpdateMsgType msgType) {
281   - log.trace("Executing processEntityCRUDMessage, edgeEvent [{}], msgType [{}]", edgeEvent, msgType);
  294 + private void processEntityMessage(EdgeEvent edgeEvent, ActionType edgeEventAction) {
  295 + UpdateMsgType msgType = getResponseMsgType(ActionType.valueOf(edgeEvent.getEdgeEventAction()));
  296 + log.trace("Executing processEntityMessage, edgeEvent [{}], edgeEventAction [{}], msgType [{}]", edgeEvent, edgeEventAction, msgType);
282 297 switch (edgeEvent.getEdgeEventType()) {
283 298 case EDGE:
284 299 // TODO: voba - add edge update logic
285 300 break;
286 301 case DEVICE:
287   - processDeviceCRUD(edgeEvent, msgType);
288   - break;
289   - case DEVICE_CREDENTIALS:
290   - processDeviceCredentialsCRUD(edgeEvent, msgType);
  302 + processDevice(edgeEvent, msgType, edgeEventAction);
291 303 break;
292 304 case ASSET:
293   - processAssetCRUD(edgeEvent, msgType);
  305 + processAsset(edgeEvent, msgType, edgeEventAction);
294 306 break;
295 307 case ENTITY_VIEW:
296   - processEntityViewCRUD(edgeEvent, msgType);
  308 + processEntityView(edgeEvent, msgType, edgeEventAction);
297 309 break;
298 310 case DASHBOARD:
299   - processDashboardCRUD(edgeEvent, msgType);
  311 + processDashboard(edgeEvent, msgType, edgeEventAction);
300 312 break;
301 313 case RULE_CHAIN:
302   - processRuleChainCRUD(edgeEvent, msgType);
  314 + processRuleChain(edgeEvent, msgType, edgeEventAction);
303 315 break;
304 316 case RULE_CHAIN_METADATA:
305   - processRuleChainMetadataCRUD(edgeEvent, msgType);
  317 + processRuleChainMetadata(edgeEvent, msgType);
306 318 break;
307 319 case ALARM:
308   - processAlarmCRUD(edgeEvent, msgType);
  320 + processAlarm(edgeEvent, msgType);
309 321 break;
310 322 case USER:
311   - processUserCRUD(edgeEvent, msgType);
312   - break;
313   - case USER_CREDENTIALS:
314   - processUserCredentialsCRUD(edgeEvent, msgType);
  323 + processUser(edgeEvent, msgType, edgeEventAction);
315 324 break;
316 325 case RELATION:
317   - processRelationCRUD(edgeEvent, msgType);
  326 + processRelation(edgeEvent, msgType);
318 327 break;
319 328 }
320 329 }
321 330
322   - private void processDeviceCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  331 + private void processDevice(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeActionType) {
323 332 DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
324   - switch (msgType) {
325   - case ENTITY_CREATED_RPC_MESSAGE:
326   - case ENTITY_UPDATED_RPC_MESSAGE:
327   - case DEVICE_CONFLICT_RPC_MESSAGE:
  333 + EntityUpdateMsg entityUpdateMsg = null;
  334 + switch (edgeActionType) {
  335 + case ADDED:
  336 + case UPDATED:
  337 + case ASSIGNED_TO_EDGE:
328 338 Device device = ctx.getDeviceService().findDeviceById(edgeEvent.getTenantId(), deviceId);
329 339 if (device != null) {
330 340 DeviceUpdateMsg deviceUpdateMsg =
331 341 ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device);
332   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  342 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
333 343 .setDeviceUpdateMsg(deviceUpdateMsg)
334 344 .build();
335   - outputStream.onNext(ResponseMsg.newBuilder()
336   - .setEntityUpdateMsg(entityUpdateMsg)
337   - .build());
338 345 }
339 346 break;
340   - case ENTITY_DELETED_RPC_MESSAGE:
  347 + case DELETED:
  348 + case UNASSIGNED_FROM_EDGE:
341 349 DeviceUpdateMsg deviceUpdateMsg =
342 350 ctx.getDeviceUpdateMsgConstructor().constructDeviceDeleteMsg(deviceId);
343   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  351 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
344 352 .setDeviceUpdateMsg(deviceUpdateMsg)
345 353 .build();
346   - outputStream.onNext(ResponseMsg.newBuilder()
347   - .setEntityUpdateMsg(entityUpdateMsg)
348   - .build());
349   - }
350   - }
351   -
352   - private void processDeviceCredentialsCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
353   - DeviceId deviceId = new DeviceId(edgeEvent.getEntityId());
354   - switch (msgType) {
355   - case ENTITY_CREATED_RPC_MESSAGE:
356   - case ENTITY_UPDATED_RPC_MESSAGE:
  354 + break;
  355 + case CREDENTIALS_UPDATED:
357 356 DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(edge.getTenantId(), deviceId);
358 357 if (deviceCredentials != null) {
359 358 DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg =
360 359 ctx.getDeviceUpdateMsgConstructor().constructDeviceCredentialsUpdatedMsg(deviceCredentials);
361   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  360 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
362 361 .setDeviceCredentialsUpdateMsg(deviceCredentialsUpdateMsg)
363 362 .build();
364   - outputStream.onNext(ResponseMsg.newBuilder()
365   - .setEntityUpdateMsg(entityUpdateMsg)
366   - .build());
367 363 }
368 364 break;
369 365 }
  366 + if (entityUpdateMsg != null) {
  367 + outputStream.onNext(ResponseMsg.newBuilder()
  368 + .setEntityUpdateMsg(entityUpdateMsg)
  369 + .build());
  370 + }
370 371 }
371 372
372   - private void processAssetCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  373 + private void processAsset(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
373 374 AssetId assetId = new AssetId(edgeEvent.getEntityId());
374   - switch (msgType) {
375   - case ENTITY_CREATED_RPC_MESSAGE:
376   - case ENTITY_UPDATED_RPC_MESSAGE:
  375 + EntityUpdateMsg entityUpdateMsg = null;
  376 + switch (edgeEventAction) {
  377 + case ADDED:
  378 + case UPDATED:
  379 + case ASSIGNED_TO_EDGE:
377 380 Asset asset = ctx.getAssetService().findAssetById(edgeEvent.getTenantId(), assetId);
378 381 if (asset != null) {
379 382 AssetUpdateMsg assetUpdateMsg =
380 383 ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset);
381   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  384 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
382 385 .setAssetUpdateMsg(assetUpdateMsg)
383 386 .build();
384   - outputStream.onNext(ResponseMsg.newBuilder()
385   - .setEntityUpdateMsg(entityUpdateMsg)
386   - .build());
387 387 }
388 388 break;
389   - case ENTITY_DELETED_RPC_MESSAGE:
  389 + case DELETED:
  390 + case UNASSIGNED_FROM_EDGE:
390 391 AssetUpdateMsg assetUpdateMsg =
391 392 ctx.getAssetUpdateMsgConstructor().constructAssetDeleteMsg(assetId);
392   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  393 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
393 394 .setAssetUpdateMsg(assetUpdateMsg)
394 395 .build();
395   - outputStream.onNext(ResponseMsg.newBuilder()
396   - .setEntityUpdateMsg(entityUpdateMsg)
397   - .build());
398 396 break;
399 397 }
  398 + if (entityUpdateMsg != null) {
  399 + outputStream.onNext(ResponseMsg.newBuilder()
  400 + .setEntityUpdateMsg(entityUpdateMsg)
  401 + .build());
  402 + }
400 403 }
401 404
402   - private void processEntityViewCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  405 + private void processEntityView(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
403 406 EntityViewId entityViewId = new EntityViewId(edgeEvent.getEntityId());
404   - switch (msgType) {
405   - case ENTITY_CREATED_RPC_MESSAGE:
406   - case ENTITY_UPDATED_RPC_MESSAGE:
  407 + EntityUpdateMsg entityUpdateMsg = null;
  408 + switch (edgeEventAction) {
  409 + case ADDED:
  410 + case UPDATED:
  411 + case ASSIGNED_TO_EDGE:
407 412 EntityView entityView = ctx.getEntityViewService().findEntityViewById(edgeEvent.getTenantId(), entityViewId);
408 413 if (entityView != null) {
409 414 EntityViewUpdateMsg entityViewUpdateMsg =
410 415 ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView);
411   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  416 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
412 417 .setEntityViewUpdateMsg(entityViewUpdateMsg)
413 418 .build();
414   - outputStream.onNext(ResponseMsg.newBuilder()
415   - .setEntityUpdateMsg(entityUpdateMsg)
416   - .build());
417 419 }
418 420 break;
419   - case ENTITY_DELETED_RPC_MESSAGE:
  421 + case DELETED:
  422 + case UNASSIGNED_FROM_EDGE:
420 423 EntityViewUpdateMsg entityViewUpdateMsg =
421 424 ctx.getEntityViewUpdateMsgConstructor().constructEntityViewDeleteMsg(entityViewId);
422   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  425 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
423 426 .setEntityViewUpdateMsg(entityViewUpdateMsg)
424 427 .build();
425   - outputStream.onNext(ResponseMsg.newBuilder()
426   - .setEntityUpdateMsg(entityUpdateMsg)
427   - .build());
428 428 break;
429 429 }
  430 + if (entityUpdateMsg != null) {
  431 + outputStream.onNext(ResponseMsg.newBuilder()
  432 + .setEntityUpdateMsg(entityUpdateMsg)
  433 + .build());
  434 + }
430 435 }
431 436
432   - private void processDashboardCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  437 + private void processDashboard(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
433 438 DashboardId dashboardId = new DashboardId(edgeEvent.getEntityId());
434   - switch (msgType) {
435   - case ENTITY_CREATED_RPC_MESSAGE:
436   - case ENTITY_UPDATED_RPC_MESSAGE:
  439 + EntityUpdateMsg entityUpdateMsg = null;
  440 + switch (edgeEventAction) {
  441 + case ADDED:
  442 + case UPDATED:
  443 + case ASSIGNED_TO_EDGE:
437 444 Dashboard dashboard = ctx.getDashboardService().findDashboardById(edgeEvent.getTenantId(), dashboardId);
438 445 if (dashboard != null) {
439 446 DashboardUpdateMsg dashboardUpdateMsg =
440 447 ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard);
441   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  448 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
442 449 .setDashboardUpdateMsg(dashboardUpdateMsg)
443 450 .build();
444   - outputStream.onNext(ResponseMsg.newBuilder()
445   - .setEntityUpdateMsg(entityUpdateMsg)
446   - .build());
447 451 }
448 452 break;
449   - case ENTITY_DELETED_RPC_MESSAGE:
  453 + case DELETED:
  454 + case UNASSIGNED_FROM_EDGE:
450 455 DashboardUpdateMsg dashboardUpdateMsg =
451 456 ctx.getDashboardUpdateMsgConstructor().constructDashboardDeleteMsg(dashboardId);
452   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  457 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
453 458 .setDashboardUpdateMsg(dashboardUpdateMsg)
454 459 .build();
455   - outputStream.onNext(ResponseMsg.newBuilder()
456   - .setEntityUpdateMsg(entityUpdateMsg)
457   - .build());
458 460 break;
459 461 }
  462 + if (entityUpdateMsg != null) {
  463 + outputStream.onNext(ResponseMsg.newBuilder()
  464 + .setEntityUpdateMsg(entityUpdateMsg)
  465 + .build());
  466 + }
460 467 }
461 468
462   - private void processRuleChainCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  469 + private void processRuleChain(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeEventAction) {
463 470 RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
464   - switch (msgType) {
465   - case ENTITY_CREATED_RPC_MESSAGE:
466   - case ENTITY_UPDATED_RPC_MESSAGE:
  471 + EntityUpdateMsg entityUpdateMsg = null;
  472 + switch (edgeEventAction) {
  473 + case ADDED:
  474 + case UPDATED:
  475 + case ASSIGNED_TO_EDGE:
467 476 RuleChain ruleChain = ctx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
468 477 if (ruleChain != null) {
469 478 RuleChainUpdateMsg ruleChainUpdateMsg =
470 479 ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge.getRootRuleChainId(), msgType, ruleChain);
471   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  480 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
472 481 .setRuleChainUpdateMsg(ruleChainUpdateMsg)
473 482 .build();
474   - outputStream.onNext(ResponseMsg.newBuilder()
475   - .setEntityUpdateMsg(entityUpdateMsg)
476   - .build());
477 483 }
478 484 break;
479   - case ENTITY_DELETED_RPC_MESSAGE:
480   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  485 + case DELETED:
  486 + case UNASSIGNED_FROM_EDGE:
  487 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
481 488 .setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainDeleteMsg(ruleChainId))
482 489 .build();
483   - outputStream.onNext(ResponseMsg.newBuilder()
484   - .setEntityUpdateMsg(entityUpdateMsg)
485   - .build());
486 490 break;
487 491 }
  492 + if (entityUpdateMsg != null) {
  493 + outputStream.onNext(ResponseMsg.newBuilder()
  494 + .setEntityUpdateMsg(entityUpdateMsg)
  495 + .build());
  496 + }
488 497 }
489 498
490   - private void processRuleChainMetadataCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  499 + private void processRuleChainMetadata(EdgeEvent edgeEvent, UpdateMsgType msgType) {
491 500 RuleChainId ruleChainId = new RuleChainId(edgeEvent.getEntityId());
492 501 RuleChain ruleChain = ctx.getRuleChainService().findRuleChainById(edgeEvent.getTenantId(), ruleChainId);
493 502 if (ruleChain != null) {
... ... @@ -505,53 +514,44 @@ public final class EdgeGrpcSession implements Closeable {
505 514 }
506 515 }
507 516
508   - private void processUserCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  517 + private void processUser(EdgeEvent edgeEvent, UpdateMsgType msgType, ActionType edgeActionType) {
509 518 UserId userId = new UserId(edgeEvent.getEntityId());
510   - switch (msgType) {
511   - case ENTITY_CREATED_RPC_MESSAGE:
512   - case ENTITY_UPDATED_RPC_MESSAGE:
  519 + EntityUpdateMsg entityUpdateMsg = null;
  520 + switch (edgeActionType) {
  521 + case ADDED:
  522 + case UPDATED:
  523 + case ASSIGNED_TO_EDGE:
513 524 User user = ctx.getUserService().findUserById(edgeEvent.getTenantId(), userId);
514 525 if (user != null) {
515   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  526 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
516 527 .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserUpdatedMsg(msgType, user))
517 528 .build();
518   - outputStream.onNext(ResponseMsg.newBuilder()
519   - .setEntityUpdateMsg(entityUpdateMsg)
520   - .build());
521 529 }
522 530 break;
523   - case ENTITY_DELETED_RPC_MESSAGE:
524   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  531 + case DELETED:
  532 + case UNASSIGNED_FROM_EDGE:
  533 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
525 534 .setUserUpdateMsg(ctx.getUserUpdateMsgConstructor().constructUserDeleteMsg(userId))
526 535 .build();
527   - outputStream.onNext(ResponseMsg.newBuilder()
528   - .setEntityUpdateMsg(entityUpdateMsg)
529   - .build());
530 536 break;
531   - }
532   - }
533   -
534   - private void processUserCredentialsCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
535   - UserId userId = new UserId(edgeEvent.getEntityId());
536   - switch (msgType) {
537   - case ENTITY_CREATED_RPC_MESSAGE:
538   - case ENTITY_UPDATED_RPC_MESSAGE:
  537 + case CREDENTIALS_UPDATED:
539 538 UserCredentials userCredentialsByUserId = ctx.getUserService().findUserCredentialsByUserId(edge.getTenantId(), userId);
540 539 if (userCredentialsByUserId != null) {
541 540 UserCredentialsUpdateMsg userCredentialsUpdateMsg =
542 541 ctx.getUserUpdateMsgConstructor().constructUserCredentialsUpdatedMsg(userCredentialsByUserId);
543   - EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
  542 + entityUpdateMsg = EntityUpdateMsg.newBuilder()
544 543 .setUserCredentialsUpdateMsg(userCredentialsUpdateMsg)
545 544 .build();
546   - outputStream.onNext(ResponseMsg.newBuilder()
547   - .setEntityUpdateMsg(entityUpdateMsg)
548   - .build());
549 545 }
550   - break;
  546 + }
  547 + if (entityUpdateMsg != null) {
  548 + outputStream.onNext(ResponseMsg.newBuilder()
  549 + .setEntityUpdateMsg(entityUpdateMsg)
  550 + .build());
551 551 }
552 552 }
553 553
554   - private void processRelationCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  554 + private void processRelation(EdgeEvent edgeEvent, UpdateMsgType msgType) {
555 555 EntityRelation entityRelation = mapper.convertValue(edgeEvent.getEntityBody(), EntityRelation.class);
556 556 EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
557 557 .setRelationUpdateMsg(ctx.getRelationUpdateMsgConstructor().constructRelationUpdatedMsg(msgType, entityRelation))
... ... @@ -561,7 +561,7 @@ public final class EdgeGrpcSession implements Closeable {
561 561 .build());
562 562 }
563 563
564   - private void processAlarmCRUD(EdgeEvent edgeEvent, UpdateMsgType msgType) {
  564 + private void processAlarm(EdgeEvent edgeEvent, UpdateMsgType msgType) {
565 565 try {
566 566 AlarmId alarmId = new AlarmId(edgeEvent.getEntityId());
567 567 Alarm alarm = ctx.getAlarmService().findAlarmByIdAsync(edgeEvent.getTenantId(), alarmId).get();
... ... @@ -574,13 +574,14 @@ public final class EdgeGrpcSession implements Closeable {
574 574 .build());
575 575 }
576 576 } catch (Exception e) {
577   - log.error("Can't process alarm CRUD msg [{}] [{}]", edgeEvent, msgType, e);
  577 + log.error("Can't process alarm msg [{}] [{}]", edgeEvent, msgType, e);
578 578 }
579 579 }
580 580
581 581 private UpdateMsgType getResponseMsgType(ActionType actionType) {
582 582 switch (actionType) {
583 583 case UPDATED:
  584 + case CREDENTIALS_UPDATED:
584 585 return UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
585 586 case ADDED:
586 587 case ASSIGNED_TO_EDGE:
... ... @@ -592,10 +593,6 @@ public final class EdgeGrpcSession implements Closeable {
592 593 return UpdateMsgType.ALARM_ACK_RPC_MESSAGE;
593 594 case ALARM_CLEAR:
594 595 return UpdateMsgType.ALARM_CLEAR_RPC_MESSAGE;
595   - case ATTRIBUTES_UPDATED:
596   - case ATTRIBUTES_DELETED:
597   - case TIMESERIES_UPDATED:
598   - return null;
599 596 default:
600 597 throw new RuntimeException("Unsupported actionType [" + actionType + "]");
601 598 }
... ...
... ... @@ -395,7 +395,7 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
395 395 public void processDeviceCredentialsRequestMsg(Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) {
396 396 if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) {
397 397 DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
398   - saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE_CREDENTIALS, ActionType.ADDED, deviceId, null);
  398 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.DEVICE, ActionType.CREDENTIALS_UPDATED, deviceId, null);
399 399 }
400 400 }
401 401
... ... @@ -403,7 +403,7 @@ public class DefaultSyncEdgeService implements SyncEdgeService {
403 403 public void processUserCredentialsRequestMsg(Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) {
404 404 if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) {
405 405 UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
406   - saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER_CREDENTIALS, ActionType.ADDED, userId, null);
  406 + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, ActionType.CREDENTIALS_UPDATED, userId, null);
407 407 }
408 408 }
409 409
... ...
... ... @@ -33,9 +33,9 @@ public class TbCoreConsumerStats {
33 33 private final AtomicInteger claimDeviceCounter = new AtomicInteger(0);
34 34
35 35 private final AtomicInteger deviceStateCounter = new AtomicInteger(0);
36   - private final AtomicInteger edgeNotificationMsgCounter = new AtomicInteger(0);
37 36 private final AtomicInteger subscriptionMsgCounter = new AtomicInteger(0);
38 37 private final AtomicInteger toCoreNotificationsCounter = new AtomicInteger(0);
  38 + private final AtomicInteger edgeNotificationMsgCounter = new AtomicInteger(0);
39 39
40 40 public void log(TransportProtos.TransportToDeviceActorMsg msg) {
41 41 totalCounter.incrementAndGet();
... ...
... ... @@ -26,8 +26,6 @@ import org.thingsboard.server.common.data.page.TimePageLink;
26 26
27 27 public interface EdgeEventService {
28 28
29   - EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType);
30   -
31 29 ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent);
32 30
33 31 TimePageData<EdgeEvent> findEdgeEvents(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.common.data;
17 17
  18 +import org.thingsboard.server.common.data.edge.EdgeEventType;
18 19 import org.thingsboard.server.common.data.id.EdgeId;
19 20
20 21 import java.util.Set;
... ... @@ -24,50 +25,22 @@ public final class EdgeUtils {
24 25 private EdgeUtils() {
25 26 }
26 27
27   - public static boolean isAssignedToEdge(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) {
28   - return assignedEdges != null && assignedEdges.contains(new ShortEdgeInfo(edgeId, null, null));
29   - }
30   -
31   - public static ShortEdgeInfo getAssignedEdgeInfo(Set<ShortEdgeInfo> assignedEdges, EdgeId edgeId) {
32   - if (assignedEdges != null) {
33   - for (ShortEdgeInfo edgeInfo : assignedEdges) {
34   - if (edgeInfo.getEdgeId().equals(edgeId)) {
35   - return edgeInfo;
36   - }
37   - }
38   - }
39   - return null;
40   - }
41   -
42   - public static boolean addAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
43   - if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
44   - return false;
45   - } else {
46   - if (assignedEdges != null) {
47   - assignedEdges.add(edgeInfo);
48   - return true;
49   - } else {
50   - return false;
51   - }
52   - }
53   - }
54   -
55   - public static boolean updateAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
56   - if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
57   - assignedEdges.remove(edgeInfo);
58   - assignedEdges.add(edgeInfo);
59   - return true;
60   - } else {
61   - return false;
62   - }
63   - }
64   -
65   - public static boolean removeAssignedEdge(Set<ShortEdgeInfo> assignedEdges, ShortEdgeInfo edgeInfo) {
66   - if (assignedEdges != null && assignedEdges.contains(edgeInfo)) {
67   - assignedEdges.remove(edgeInfo);
68   - return true;
69   - } else {
70   - return false;
  28 + public static EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
  29 + switch (entityType) {
  30 + case DEVICE:
  31 + return EdgeEventType.DEVICE;
  32 + case ASSET:
  33 + return EdgeEventType.ASSET;
  34 + case ENTITY_VIEW:
  35 + return EdgeEventType.ENTITY_VIEW;
  36 + case DASHBOARD:
  37 + return EdgeEventType.DASHBOARD;
  38 + case USER:
  39 + return EdgeEventType.USER;
  40 + case ALARM:
  41 + return EdgeEventType.ALARM;
  42 + default:
  43 + return null;
71 44 }
72 45 }
73 46 }
... ...
... ... @@ -43,7 +43,8 @@ public enum ActionType {
43 43 LOGOUT(false),
44 44 LOCKOUT(false),
45 45 ASSIGNED_TO_EDGE(false), // log edge name
46   - UNASSIGNED_FROM_EDGE(false); // log edge name
  46 + UNASSIGNED_FROM_EDGE(false), // log edge name
  47 + CREDENTIALS_REQUEST(false); // request credentials from edge
47 48
48 49 private final boolean isRead;
49 50
... ...
... ... @@ -19,14 +19,12 @@ public enum EdgeEventType {
19 19 DASHBOARD,
20 20 ASSET,
21 21 DEVICE,
22   - DEVICE_CREDENTIALS,
23 22 ENTITY_VIEW,
24 23 ALARM,
25 24 RULE_CHAIN,
26 25 RULE_CHAIN_METADATA,
27 26 EDGE,
28 27 USER,
29   - USER_CREDENTIALS,
30 28 CUSTOMER,
31 29 RELATION
32 30 }
... ...
... ... @@ -20,9 +20,7 @@ import lombok.extern.slf4j.Slf4j;
20 20 import org.apache.commons.lang3.StringUtils;
21 21 import org.springframework.beans.factory.annotation.Autowired;
22 22 import org.springframework.stereotype.Service;
23   -import org.thingsboard.server.common.data.EntityType;
24 23 import org.thingsboard.server.common.data.edge.EdgeEvent;
25   -import org.thingsboard.server.common.data.edge.EdgeEventType;
26 24 import org.thingsboard.server.common.data.id.EdgeId;
27 25 import org.thingsboard.server.common.data.id.TenantId;
28 26 import org.thingsboard.server.common.data.page.TimePageData;
... ... @@ -40,27 +38,6 @@ public class BaseEdgeEventService implements EdgeEventService {
40 38 public EdgeEventDao edgeEventDao;
41 39
42 40 @Override
43   - public EdgeEventType getEdgeEventTypeByEntityType(EntityType entityType) {
44   - switch (entityType) {
45   - case DEVICE:
46   - return EdgeEventType.DEVICE;
47   - case ASSET:
48   - return EdgeEventType.ASSET;
49   - case ENTITY_VIEW:
50   - return EdgeEventType.ENTITY_VIEW;
51   - case DASHBOARD:
52   - return EdgeEventType.DASHBOARD;
53   - case USER:
54   - return EdgeEventType.USER;
55   - case ALARM:
56   - return EdgeEventType.ALARM;
57   - default:
58   - log.warn("Failed to push notification to edge service. Unsupported entity type [{}]", entityType);
59   - return null;
60   - }
61   - }
62   -
63   - @Override
64 41 public ListenableFuture<EdgeEvent> saveAsync(EdgeEvent edgeEvent) {
65 42 edgeEventValidator.validate(edgeEvent, EdgeEvent::getTenantId);
66 43 return edgeEventDao.saveAsync(edgeEvent);
... ...
... ... @@ -45,7 +45,8 @@ import org.thingsboard.server.common.data.Tenant;
45 45 import org.thingsboard.server.common.data.UpdateMessage;
46 46 import org.thingsboard.server.common.data.User;
47 47 import org.thingsboard.server.common.data.alarm.Alarm;
48   -import org.thingsboard.server.common.data.id.AlarmId;
  48 +import org.thingsboard.server.common.data.edge.Edge;
  49 +import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
49 50 import org.thingsboard.server.common.data.alarm.AlarmInfo;
50 51 import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
51 52 import org.thingsboard.server.common.data.alarm.AlarmSeverity;
... ... @@ -56,10 +57,12 @@ import org.thingsboard.server.common.data.audit.ActionType;
56 57 import org.thingsboard.server.common.data.audit.AuditLog;
57 58 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
58 59 import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
  60 +import org.thingsboard.server.common.data.id.AlarmId;
59 61 import org.thingsboard.server.common.data.id.AssetId;
60 62 import org.thingsboard.server.common.data.id.CustomerId;
61 63 import org.thingsboard.server.common.data.id.DashboardId;
62 64 import org.thingsboard.server.common.data.id.DeviceId;
  65 +import org.thingsboard.server.common.data.id.EdgeId;
63 66 import org.thingsboard.server.common.data.id.EntityId;
64 67 import org.thingsboard.server.common.data.id.EntityViewId;
65 68 import org.thingsboard.server.common.data.id.RuleChainId;
... ... @@ -1978,6 +1981,190 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
1978 1981 }
1979 1982 }
1980 1983
  1984 + public Edge saveEdge(Edge edge) {
  1985 + return restTemplate.postForEntity(baseURL + "/api/edge", edge, Edge.class).getBody();
  1986 + }
  1987 +
  1988 + public void deleteEdge(EdgeId edgeId) {
  1989 + restTemplate.delete(baseURL + "/api/edge/{edgeId}", edgeId.getId());
  1990 + }
  1991 +
  1992 + public Optional<Edge> getEdgeById(EdgeId edgeId) {
  1993 + try {
  1994 + ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/edge/{edgeId}", Edge.class, edgeId.getId());
  1995 + return Optional.ofNullable(edge.getBody());
  1996 + } catch (HttpClientErrorException exception) {
  1997 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  1998 + return Optional.empty();
  1999 + } else {
  2000 + throw exception;
  2001 + }
  2002 + }
  2003 + }
  2004 +
  2005 + public Optional<Edge> assignEdgeToCustomer(CustomerId customerId, EdgeId edgeId) {
  2006 + try {
  2007 + ResponseEntity<Edge> edge = restTemplate.postForEntity(baseURL + "/api/customer/{customerId}/edge/{edgeId}", null, Edge.class, customerId.getId(), edgeId.getId());
  2008 + return Optional.ofNullable(edge.getBody());
  2009 + } catch (HttpClientErrorException exception) {
  2010 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2011 + return Optional.empty();
  2012 + } else {
  2013 + throw exception;
  2014 + }
  2015 + }
  2016 + }
  2017 +
  2018 + public Optional<Edge> unassignEdgeFromCustomer(EdgeId edgeId) {
  2019 + try {
  2020 + ResponseEntity<Edge> edge = restTemplate.exchange(baseURL + "/api/customer/edge/{edgeId}", HttpMethod.DELETE, HttpEntity.EMPTY, Edge.class, edgeId.getId());
  2021 + return Optional.ofNullable(edge.getBody());
  2022 + } catch (HttpClientErrorException exception) {
  2023 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2024 + return Optional.empty();
  2025 + } else {
  2026 + throw exception;
  2027 + }
  2028 + }
  2029 + }
  2030 +
  2031 + public Optional<Device> assignDeviceToEdge(EdgeId edgeId, DeviceId deviceId) {
  2032 + try {
  2033 + ResponseEntity<Device> device = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/device/{deviceId}", null, Device.class, edgeId.getId(), deviceId.getId());
  2034 + return Optional.ofNullable(device.getBody());
  2035 + } catch (HttpClientErrorException exception) {
  2036 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2037 + return Optional.empty();
  2038 + } else {
  2039 + throw exception;
  2040 + }
  2041 + }
  2042 + }
  2043 +
  2044 + public Optional<Device> unassignDeviceFromEdge(DeviceId deviceId) {
  2045 + try {
  2046 + ResponseEntity<Device> device = restTemplate.exchange(baseURL + "/api/edge/device/{deviceId}", HttpMethod.DELETE, HttpEntity.EMPTY, Device.class, deviceId.getId());
  2047 + return Optional.ofNullable(device.getBody());
  2048 + } catch (HttpClientErrorException exception) {
  2049 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2050 + return Optional.empty();
  2051 + } else {
  2052 + throw exception;
  2053 + }
  2054 + }
  2055 + }
  2056 +
  2057 + public TextPageData<Device> getEdgeDevices(EdgeId edgeId, String deviceType, TextPageLink pageLink) {
  2058 + Map<String, String> params = new HashMap<>();
  2059 + params.put("edgeId", edgeId.getId().toString());
  2060 + params.put("type", deviceType);
  2061 + addPageLinkToParam(params, pageLink);
  2062 + return restTemplate.exchange(
  2063 + baseURL + "/api/edge/{edgeId}/devices?type={type}&" + getUrlParams(pageLink),
  2064 + HttpMethod.GET, HttpEntity.EMPTY,
  2065 + new ParameterizedTypeReference<TextPageData<Device>>() {
  2066 + }, params).getBody();
  2067 + }
  2068 +
  2069 + public Optional<Asset> assignAssetToEdge(EdgeId edgeId, AssetId assetId) {
  2070 + try {
  2071 + ResponseEntity<Asset> asset = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/asset/{assetId}", null, Asset.class, edgeId.getId(), assetId.getId());
  2072 + return Optional.ofNullable(asset.getBody());
  2073 + } catch (HttpClientErrorException exception) {
  2074 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2075 + return Optional.empty();
  2076 + } else {
  2077 + throw exception;
  2078 + }
  2079 + }
  2080 + }
  2081 +
  2082 + public Optional<Asset> unassignAssetFromEdge(AssetId assetId) {
  2083 + try {
  2084 + ResponseEntity<Asset> asset = restTemplate.exchange(baseURL + "/api/edge/asset/{assetId}", HttpMethod.DELETE, HttpEntity.EMPTY, Asset.class, assetId.getId());
  2085 + return Optional.ofNullable(asset.getBody());
  2086 + } catch (HttpClientErrorException exception) {
  2087 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2088 + return Optional.empty();
  2089 + } else {
  2090 + throw exception;
  2091 + }
  2092 + }
  2093 + }
  2094 +
  2095 + public TextPageData<Asset> getEdgeAssets(EdgeId edgeId, String assetType, TextPageLink pageLink) {
  2096 + Map<String, String> params = new HashMap<>();
  2097 + params.put("edgeId", edgeId.getId().toString());
  2098 + params.put("type", assetType);
  2099 + addPageLinkToParam(params, pageLink);
  2100 + return restTemplate.exchange(
  2101 + baseURL + "/api/edge/{edgeId}/assets?type={type}&" + getUrlParams(pageLink),
  2102 + HttpMethod.GET, HttpEntity.EMPTY,
  2103 + new ParameterizedTypeReference<TextPageData<Asset>>() {
  2104 + }, params).getBody();
  2105 + }
  2106 +
  2107 + public TextPageData<Edge> getTenantEdges(String type, TextPageLink pageLink) {
  2108 + Map<String, String> params = new HashMap<>();
  2109 + params.put("type", type);
  2110 + addPageLinkToParam(params, pageLink);
  2111 + return restTemplate.exchange(
  2112 + baseURL + "/api/tenant/edges?type={type}&" + getUrlParams(pageLink),
  2113 + HttpMethod.GET, HttpEntity.EMPTY,
  2114 + new ParameterizedTypeReference<TextPageData<Edge>>() {
  2115 + }, params).getBody();
  2116 + }
  2117 +
  2118 + public Optional<Edge> getTenantEdge(String edgeName) {
  2119 + try {
  2120 + ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/tenant/edges?edgeName={edgeName}", Edge.class, edgeName);
  2121 + return Optional.ofNullable(edge.getBody());
  2122 + } catch (HttpClientErrorException exception) {
  2123 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  2124 + return Optional.empty();
  2125 + } else {
  2126 + throw exception;
  2127 + }
  2128 + }
  2129 + }
  2130 +
  2131 + public TextPageData<Edge> getCustomerEdges(CustomerId customerId, String edgeType, TextPageLink pageLink) {
  2132 + Map<String, String> params = new HashMap<>();
  2133 + params.put("customerId", customerId.getId().toString());
  2134 + params.put("type", edgeType);
  2135 + addPageLinkToParam(params, pageLink);
  2136 + return restTemplate.exchange(
  2137 + baseURL + "/api/customer/{customerId}/edges?type={type}&" + getUrlParams(pageLink),
  2138 + HttpMethod.GET, HttpEntity.EMPTY,
  2139 + new ParameterizedTypeReference<TextPageData<Edge>>() {
  2140 + }, params).getBody();
  2141 + }
  2142 +
  2143 + public List<Edge> getEdgesByIds(List<EdgeId> edgeIds) {
  2144 + return restTemplate.exchange(baseURL + "/api/edges?edgeIds={edgeIds}",
  2145 + HttpMethod.GET,
  2146 + HttpEntity.EMPTY, new ParameterizedTypeReference<List<Edge>>() {
  2147 + }, listIdsToString(edgeIds)).getBody();
  2148 + }
  2149 +
  2150 + public List<Edge> findByQuery(EdgeSearchQuery query) {
  2151 + return restTemplate.exchange(
  2152 + baseURL + "/api/edges",
  2153 + HttpMethod.POST,
  2154 + new HttpEntity<>(query),
  2155 + new ParameterizedTypeReference<List<Edge>>() {
  2156 + }).getBody();
  2157 + }
  2158 +
  2159 + public List<EntitySubtype> getEdgeTypes() {
  2160 + return restTemplate.exchange(
  2161 + baseURL + "/api/edge/types",
  2162 + HttpMethod.GET,
  2163 + HttpEntity.EMPTY,
  2164 + new ParameterizedTypeReference<List<EntitySubtype>>() {
  2165 + }).getBody();
  2166 + }
  2167 +
1981 2168 @Deprecated
1982 2169 public Optional<JsonNode> getAttributes(String accessToken, String clientKeys, String sharedKeys) {
1983 2170 Map<String, String> params = new HashMap<>();
... ...
... ... @@ -58,6 +58,6 @@ public @interface RuleNode {
58 58
59 59 boolean customRelations() default false;
60 60
61   - RuleChainType[] ruleChainTypes() default RuleChainType.CORE;
  61 + RuleChainType[] ruleChainTypes() default {RuleChainType.CORE, RuleChainType.EDGE};
62 62
63 63 }
... ...
... ... @@ -37,9 +37,7 @@ import org.thingsboard.server.common.msg.TbMsg;
37 37 "Will create new Customer if it doesn't exists and 'Create new Customer if not exists' is set to true.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js"},
39 39 configDirective = "tbActionNodeAssignToCustomerConfig",
40   - icon = "add_circle",
41   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
42   -)
  40 + icon = "add_circle")
43 41 public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> {
44 42
45 43 @Override
... ...
... ... @@ -45,9 +45,7 @@ import org.thingsboard.server.common.msg.TbMsg;
45 45 "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js"},
47 47 configDirective = "tbActionNodeClearAlarmConfig",
48   - icon = "notifications_off",
49   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
50   -)
  48 + icon = "notifications_off")
51 49 public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> {
52 50
53 51 @Override
... ...
... ... @@ -57,9 +57,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
57 57 "Changes message originator to related entity view and produces new messages according to count of updated entity views",
58 58 uiResources = {"static/rulenode/rulenode-core-config.js"},
59 59 configDirective = "tbNodeEmptyConfig",
60   - icon = "content_copy",
61   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
62   -)
  60 + icon = "content_copy")
63 61 public class TbCopyAttributesToEntityViewNode implements TbNode {
64 62
65 63 EmptyNodeConfiguration config;
... ...
... ... @@ -51,9 +51,7 @@ import java.util.List;
51 51 "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
52 52 uiResources = {"static/rulenode/rulenode-core-config.js"},
53 53 configDirective = "tbActionNodeCreateAlarmConfig",
54   - icon = "notifications_active",
55   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
56   -)
  54 + icon = "notifications_active")
57 55 public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> {
58 56
59 57 private static ObjectMapper mapper = new ObjectMapper();
... ...
... ... @@ -54,9 +54,7 @@ import java.util.List;
54 54 nodeDetails = "If the relation already exists or successfully created - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
55 55 uiResources = {"static/rulenode/rulenode-core-config.js"},
56 56 configDirective = "tbActionNodeCreateRelationConfig",
57   - icon = "add_circle",
58   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
59   -)
  57 + icon = "add_circle")
60 58 public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> {
61 59
62 60 @Override
... ...
... ... @@ -44,9 +44,7 @@ import java.util.List;
44 44 nodeDetails = "If the relation(s) successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
45 45 uiResources = {"static/rulenode/rulenode-core-config.js"},
46 46 configDirective = "tbActionNodeDeleteRelationConfig",
47   - icon = "remove_circle",
48   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
49   -)
  47 + icon = "remove_circle")
50 48 public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {
51 49
52 50 @Override
... ...
... ... @@ -37,10 +37,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
37 37 "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js"},
39 39 configDirective = "tbActionNodeLogConfig",
40   - icon = "menu",
41   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
42   -)
43   -
  40 + icon = "menu")
44 41 public class TbLogNode implements TbNode {
45 42
46 43 private TbLogNodeConfiguration config;
... ...
... ... @@ -44,9 +44,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
44 44 nodeDetails = "Count incoming messages for specified interval and produces POST_TELEMETRY_REQUEST msg with messages count",
45 45 icon = "functions",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js"},
47   - configDirective = "tbActionNodeMsgCountConfig",
48   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
49   -)
  47 + configDirective = "tbActionNodeMsgCountConfig")
50 48 public class TbMsgCountNode implements TbNode {
51 49
52 50 private static final String TB_MSG_COUNT_NODE_MSG = "TbMsgCountNodeMsg";
... ...
... ... @@ -78,7 +78,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
78 78 " otherwise, the message will be routed via <b>success</b> chain.",
79 79 uiResources = {"static/rulenode/rulenode-core-config.js"},
80 80 configDirective = "tbActionNodeCustomTableConfig",
81   - icon = "file_upload"
  81 + icon = "file_upload",
  82 + ruleChainTypes = RuleChainType.CORE
82 83 )
83 84 public class TbSaveToCustomCassandraTableNode implements TbNode {
84 85
... ...
... ... @@ -21,9 +21,13 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
21 21 import org.thingsboard.rule.engine.api.TbNodeException;
22 22 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
23 23 import org.thingsboard.server.common.data.EntityType;
24   -import org.thingsboard.server.common.data.id.*;
  24 +import org.thingsboard.server.common.data.id.AssetId;
  25 +import org.thingsboard.server.common.data.id.CustomerId;
  26 +import org.thingsboard.server.common.data.id.DashboardId;
  27 +import org.thingsboard.server.common.data.id.DeviceId;
  28 +import org.thingsboard.server.common.data.id.EdgeId;
  29 +import org.thingsboard.server.common.data.id.EntityViewId;
25 30 import org.thingsboard.server.common.data.plugin.ComponentType;
26   -import org.thingsboard.server.common.data.rule.RuleChainType;
27 31 import org.thingsboard.server.common.msg.TbMsg;
28 32
29 33 @RuleNode(
... ... @@ -34,8 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg;
34 38 nodeDetails = "Finds target Entity Customer by Customer name pattern and then unassign Originator Entity from this customer.",
35 39 uiResources = {"static/rulenode/rulenode-core-config.js"},
36 40 configDirective = "tbActionNodeUnAssignToCustomerConfig",
37   - icon = "remove_circle",
38   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  41 + icon = "remove_circle"
39 42 )
40 43 public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> {
41 44
... ...
... ... @@ -46,8 +46,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
46 46 "For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
47 47 uiResources = {"static/rulenode/rulenode-core-config.js"},
48 48 configDirective = "tbActionNodeSnsConfig",
49   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
50   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  49 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
51 50 )
52 51 public class TbSnsNode implements TbNode {
53 52
... ...
... ... @@ -51,8 +51,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
51 51 " For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
52 52 uiResources = {"static/rulenode/rulenode-core-config.js"},
53 53 configDirective = "tbActionNodeSqsConfig",
54   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
55   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  54 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+"
56 55 )
57 56 public class TbSqsNode implements TbNode {
58 57
... ...
... ... @@ -45,8 +45,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
45 45 inEnabled = false,
46 46 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
47 47 configDirective = "tbActionNodeGeneratorConfig",
48   - icon = "repeat",
49   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  48 + icon = "repeat"
50 49 )
51 50
52 51 public class TbMsgGeneratorNode implements TbNode {
... ...
... ... @@ -46,8 +46,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
46 46 nodeDetails = "Delays messages for configurable period. Please note, this node acknowledges the message from the current queue (message will be removed from queue)",
47 47 icon = "pause",
48 48 uiResources = {"static/rulenode/rulenode-core-config.js"},
49   - configDirective = "tbActionNodeMsgDelayConfig",
50   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  49 + configDirective = "tbActionNodeMsgDelayConfig"
51 50 )
52 51
53 52 public class TbMsgDelayNode implements TbNode {
... ...
... ... @@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
29 29 import org.thingsboard.rule.engine.api.TbNodeException;
30 30 import org.thingsboard.rule.engine.api.util.TbNodeUtils;
31 31 import org.thingsboard.server.common.data.DataConstants;
  32 +import org.thingsboard.server.common.data.EdgeUtils;
32 33 import org.thingsboard.server.common.data.EntityType;
33 34 import org.thingsboard.server.common.data.audit.ActionType;
34 35 import org.thingsboard.server.common.data.edge.EdgeEvent;
... ... @@ -39,6 +40,7 @@ import org.thingsboard.server.common.data.id.TenantId;
39 40 import org.thingsboard.server.common.data.plugin.ComponentType;
40 41 import org.thingsboard.server.common.data.relation.EntityRelation;
41 42 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
  43 +import org.thingsboard.server.common.data.rule.RuleChainType;
42 44 import org.thingsboard.server.common.msg.TbMsg;
43 45 import org.thingsboard.server.common.msg.session.SessionMsgType;
44 46
... ... @@ -56,7 +58,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
56 58 nodeDetails = "Pushes messages to edge, if Message Originator assigned to particular edge or is EDGE entity. This node is used only on Cloud instances to push messages from Cloud to Edge. Supports only DEVICE, ENTITY_VIEW, ASSET and EDGE Message Originator(s).",
57 59 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
58 60 configDirective = "tbNodeEmptyConfig",
59   - icon = "cloud_download"
  61 + icon = "cloud_download",
  62 + ruleChainTypes = RuleChainType.CORE
60 63 )
61 64 public class TbMsgPushToEdgeNode implements TbNode {
62 65
... ... @@ -81,7 +84,7 @@ public class TbMsgPushToEdgeNode implements TbNode {
81 84 Futures.addCallback(getEdgeIdFuture, new FutureCallback<EdgeId>() {
82 85 @Override
83 86 public void onSuccess(@Nullable EdgeId edgeId) {
84   - EdgeEventType edgeEventTypeByEntityType = ctx.getEdgeEventService().getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType());
  87 + EdgeEventType edgeEventTypeByEntityType = EdgeUtils.getEdgeEventTypeByEntityType(msg.getOriginator().getEntityType());
85 88 if (edgeEventTypeByEntityType == null) {
86 89 log.debug("Edge event type is null. Entity Type {}", msg.getOriginator().getEntityType());
87 90 ctx.tellFailure(msg, new RuntimeException("Edge event type is null. Entity Type '" + msg.getOriginator().getEntityType() + "'"));
... ...
... ... @@ -40,8 +40,7 @@ import java.util.Map;
40 40 nodeDetails = "If selected checkbox 'Check that all selected keys are present'\" and all keys in message data and metadata are exist - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.\n" +
41 41 "Else if the checkbox is not selected, and at least one of the keys from data or metadata of the message exists - send Message via <b>True</b> chain, otherwise, <b>False</b> chain is used. ",
42 42 uiResources = {"static/rulenode/rulenode-core-config.js"},
43   - configDirective = "tbFilterNodeCheckMessageConfig",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + configDirective = "tbFilterNodeCheckMessageConfig"
45 44 )
46 45 public class TbCheckMessageNode implements TbNode {
47 46
... ...
... ... @@ -52,8 +52,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
52 52 " any relation to the originator of the message by type and direction.",
53 53 nodeDetails = "If at least one relation exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
54 54 uiResources = {"static/rulenode/rulenode-core-config.js"},
55   - configDirective = "tbFilterNodeCheckRelationConfig",
56   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  55 + configDirective = "tbFilterNodeCheckRelationConfig"
57 56 )
58 57 public class TbCheckRelationNode implements TbNode {
59 58
... ...
... ... @@ -37,8 +37,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
37 37 "Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
38 38 "Message type can be accessed via <code>msgType</code> property.",
39 39 uiResources = {"static/rulenode/rulenode-core-config.js"},
40   - configDirective = "tbFilterNodeScriptConfig",
41   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  40 + configDirective = "tbFilterNodeScriptConfig"
42 41 )
43 42
44 43 public class TbJsFilterNode implements TbNode {
... ...
... ... @@ -40,8 +40,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
40 40 "Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
41 41 "Message type can be accessed via <code>msgType</code> property.",
42 42 uiResources = {"static/rulenode/rulenode-core-config.js"},
43   - configDirective = "tbFilterNodeSwitchConfig",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + configDirective = "tbFilterNodeSwitchConfig"
45 44 )
46 45 public class TbJsSwitchNode implements TbNode {
47 46
... ...
... ... @@ -34,8 +34,7 @@ import org.thingsboard.server.common.msg.TbMsg;
34 34 nodeDescription = "Filter incoming messages by Message Type",
35 35 nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
36 36 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
37   - configDirective = "tbFilterNodeMessageTypeConfig",
38   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  37 + configDirective = "tbFilterNodeMessageTypeConfig"
39 38 )
40 39 public class TbMsgTypeFilterNode implements TbNode {
41 40
... ...
... ... @@ -35,8 +35,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
35 35 nodeDescription = "Route incoming messages by Message Type",
36 36 nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.",
37 37 uiResources = {"static/rulenode/rulenode-core-config.js"},
38   - configDirective = "tbNodeEmptyConfig",
39   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  38 + configDirective = "tbNodeEmptyConfig"
40 39 )
41 40 public class TbMsgTypeSwitchNode implements TbNode {
42 41
... ...
... ... @@ -32,8 +32,7 @@ import org.thingsboard.server.common.msg.TbMsg;
32 32 nodeDescription = "Filter incoming messages by message Originator Type",
33 33 nodeDetails = "If Originator Type of incoming message is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
34 34 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
35   - configDirective = "tbFilterNodeOriginatorTypeConfig",
36   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  35 + configDirective = "tbFilterNodeOriginatorTypeConfig"
37 36 )
38 37 public class TbOriginatorTypeFilterNode implements TbNode {
39 38
... ...
... ... @@ -32,8 +32,7 @@ import org.thingsboard.server.common.msg.TbMsg;
32 32 nodeDescription = "Route incoming messages by Message Originator Type",
33 33 nodeDetails = "Routes messages to chain according to the originator type ('Device', 'Asset', etc.).",
34 34 uiResources = {"static/rulenode/rulenode-core-config.js"},
35   - configDirective = "tbNodeEmptyConfig",
36   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  35 + configDirective = "tbNodeEmptyConfig"
37 36 )
38 37 public class TbOriginatorTypeSwitchNode implements TbNode {
39 38
... ...
... ... @@ -50,8 +50,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
50 50 "<b>messageId</b> field can be accessed with <code>metadata.messageId</code>.",
51 51 uiResources = {"static/rulenode/rulenode-core-config.js"},
52 52 configDirective = "tbActionNodePubSubConfig",
53   - iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=",
54   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  53 + iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo="
55 54 )
56 55 public class TbPubSubNode implements TbNode {
57 56
... ...
... ... @@ -52,8 +52,7 @@ import java.util.concurrent.TimeoutException;
52 52 nodeDescription = "Produces incoming messages using GPS based geofencing",
53 53 nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns different events based on configuration parameters",
54 54 uiResources = {"static/rulenode/rulenode-core-config.js"},
55   - configDirective = "tbActionNodeGpsGeofencingConfig",
56   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  55 + configDirective = "tbActionNodeGpsGeofencingConfig"
57 56 )
58 57 public class TbGpsGeofencingActionNode extends AbstractGeofencingNode<TbGpsGeofencingActionNodeConfiguration> {
59 58
... ...
... ... @@ -53,8 +53,7 @@ import java.util.List;
53 53 nodeDescription = "Filter incoming messages by GPS based geofencing",
54 54 nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns 'True' if they are inside configured perimeters, 'False' otherwise.",
55 55 uiResources = {"static/rulenode/rulenode-core-config.js"},
56   - configDirective = "tbFilterNodeGpsGeofencingConfig",
57   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  56 + configDirective = "tbFilterNodeGpsGeofencingConfig"
58 57 )
59 58 public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofencingFilterNodeConfiguration> {
60 59
... ...
... ... @@ -52,8 +52,7 @@ import java.util.Properties;
52 52 " from the Kafka in the Message Metadata. For example <b>partition</b> field can be accessed with <code>metadata.partition</code>.",
53 53 uiResources = {"static/rulenode/rulenode-core-config.js"},
54 54 configDirective = "tbActionNodeKafkaConfig",
55   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==",
56   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  55 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg=="
57 56 )
58 57 public class TbKafkaNode implements TbNode {
59 58
... ...
... ... @@ -41,8 +41,7 @@ import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
41 41 "Set 'SEND_EMAIL' output message type.",
42 42 uiResources = {"static/rulenode/rulenode-core-config.js"},
43 43 configDirective = "tbTransformationNodeToEmailConfig",
44   - icon = "email",
45   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  44 + icon = "email"
46 45 )
47 46 public class TbMsgToEmailNode implements TbNode {
48 47
... ...
... ... @@ -47,8 +47,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
47 47 "with <code>to Email</code> Node using <code>Successful</code> chain.",
48 48 uiResources = {"static/rulenode/rulenode-core-config.js"},
49 49 configDirective = "tbActionNodeSendEmailConfig",
50   - icon = "send",
51   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  50 + icon = "send"
52 51 )
53 52 public class TbSendEmailNode implements TbNode {
54 53
... ...
... ... @@ -41,8 +41,7 @@ import org.thingsboard.server.common.msg.TbMsg;
41 41 "To access those attributes in other nodes this template can be used " +
42 42 "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
43 43 uiResources = {"static/rulenode/rulenode-core-config.js"},
44   - configDirective = "tbEnrichmentNodeOriginatorAttributesConfig",
45   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  44 + configDirective = "tbEnrichmentNodeOriginatorAttributesConfig"
46 45 )
47 46 public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> {
48 47
... ...
... ... @@ -34,8 +34,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
34 34 "To access those attributes in other nodes this template can be used " +
35 35 "<code>metadata.temperature</code>.",
36 36 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
37   - configDirective = "tbEnrichmentNodeCustomerAttributesConfig",
38   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  37 + configDirective = "tbEnrichmentNodeCustomerAttributesConfig"
39 38 )
40 39 public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> {
41 40
... ...
... ... @@ -43,8 +43,7 @@ import org.thingsboard.server.common.msg.TbMsg;
43 43 "<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" +
44 44 "If the originator of the message is not assigned to Customer, or originator type is not supported - Message will be forwarded to <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.",
45 45 uiResources = {"static/rulenode/rulenode-core-config.js"},
46   - configDirective = "tbEnrichmentNodeEntityDetailsConfig",
47   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  46 + configDirective = "tbEnrichmentNodeEntityDetailsConfig"
48 47 )
49 48 public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration> {
50 49
... ...
... ... @@ -39,8 +39,7 @@ import org.thingsboard.server.common.msg.TbMsg;
39 39 "To access those attributes in other nodes this template can be used " +
40 40 "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42   - configDirective = "tbEnrichmentNodeDeviceAttributesConfig",
43   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  42 + configDirective = "tbEnrichmentNodeDeviceAttributesConfig"
44 43 )
45 44 public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> {
46 45
... ...
... ... @@ -44,8 +44,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
44 44 nodeDescription = "Add Message Originator fields values into Message Metadata",
45 45 nodeDetails = "Will fetch fields values specified in mapping. If specified field is not part of originator fields it will be ignored.",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js"},
47   - configDirective = "tbEnrichmentNodeOriginatorFieldsConfig",
48   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  47 + configDirective = "tbEnrichmentNodeOriginatorFieldsConfig"
49 48 )
50 49 public class TbGetOriginatorFieldsNode implements TbNode {
51 50
... ...
... ... @@ -36,8 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
36 36 "To access those attributes in other nodes this template can be used " +
37 37 "<code>metadata.temperature</code>.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
39   - configDirective = "tbEnrichmentNodeRelatedAttributesConfig",
40   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  39 + configDirective = "tbEnrichmentNodeRelatedAttributesConfig"
41 40 )
42 41
43 42 public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {
... ...
... ... @@ -67,8 +67,7 @@ import static org.thingsboard.server.common.data.kv.Aggregation.NONE;
67 67 "Also, the rule node allows you to select telemetry sampling order: <b>ASC</b> or <b>DESC</b>. </br>" +
68 68 "<b>Note</b>: The maximum size of the fetched array is 1000 records.\n ",
69 69 uiResources = {"static/rulenode/rulenode-core-config.js"},
70   - configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase",
71   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  70 + configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase"
72 71 )
73 72 public class TbGetTelemetryNode implements TbNode {
74 73
... ...
... ... @@ -36,8 +36,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
36 36 "To access those attributes in other nodes this template can be used " +
37 37 "<code>metadata.temperature</code>.",
38 38 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
39   - configDirective = "tbEnrichmentNodeTenantAttributesConfig",
40   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  39 + configDirective = "tbEnrichmentNodeTenantAttributesConfig"
41 40 )
42 41 public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> {
43 42
... ...
... ... @@ -38,8 +38,7 @@ import org.thingsboard.server.common.msg.TbMsg;
38 38 "<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" +
39 39 "If the originator of the message is not assigned to Tenant, or originator type is not supported - Message will be forwarded to <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.",
40 40 uiResources = {"static/rulenode/rulenode-core-config.js"},
41   - configDirective = "tbEnrichmentNodeEntityDetailsConfig",
42   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  41 + configDirective = "tbEnrichmentNodeEntityDetailsConfig"
43 42 )
44 43 public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetTenantDetailsNodeConfiguration> {
45 44
... ...
... ... @@ -50,8 +50,7 @@ import java.util.concurrent.TimeoutException;
50 50 nodeDetails = "Will publish message payload to the MQTT broker with QoS <b>AT_LEAST_ONCE</b>.",
51 51 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
52 52 configDirective = "tbActionNodeMqttConfig",
53   - icon = "call_split",
54   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  53 + icon = "call_split"
55 54 )
56 55 public class TbMqttNode implements TbNode {
57 56
... ...
... ... @@ -40,8 +40,7 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
40 40 nodeDetails = "Will publish message payload to RabbitMQ queue.",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42 42 configDirective = "tbActionNodeRabbitMqConfig",
43   - iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4="
45 44 )
46 45 public class TbRabbitMqNode implements TbNode {
47 46
... ...
... ... @@ -42,8 +42,7 @@ import org.thingsboard.server.common.msg.TbMsg;
42 42 "and if your proxy with auth, the next ones should be added: \"tb.proxy.user\" and \"tb.proxy.password\" to the thingsboard.conf file.",
43 43 uiResources = {"static/rulenode/rulenode-core-config.js"},
44 44 configDirective = "tbActionNodeRestApiCallConfig",
45   - iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+",
46   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  45 + iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+"
47 46 )
48 47 public class TbRestApiCallNode implements TbNode {
49 48
... ...
... ... @@ -40,8 +40,7 @@ import java.util.UUID;
40 40 nodeDetails = "Expects messages with any message type. Will forward message body to the device.",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42 42 configDirective = "tbActionNodeRpcReplyConfig",
43   - icon = "call_merge",
44   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  43 + icon = "call_merge"
45 44 )
46 45 public class TbSendRPCReplyNode implements TbNode {
47 46
... ...
... ... @@ -51,8 +51,7 @@ import java.util.concurrent.TimeUnit;
51 51 "If the RPC call request is originated by REST API call from user, will forward the response to user immediately.",
52 52 uiResources = {"static/rulenode/rulenode-core-config.js"},
53 53 configDirective = "tbActionNodeRpcRequestConfig",
54   - icon = "call_made",
55   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  54 + icon = "call_made"
56 55 )
57 56 public class TbSendRPCRequestNode implements TbNode {
58 57
... ...
... ... @@ -45,8 +45,7 @@ import java.util.Set;
45 45 nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type",
46 46 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
47 47 configDirective = "tbActionNodeAttributesConfig",
48   - icon = "file_upload",
49   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  48 + icon = "file_upload"
50 49 )
51 50 public class TbMsgAttributesNode implements TbNode {
52 51
... ...
... ... @@ -46,8 +46,7 @@ import java.util.Map;
46 46 nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type",
47 47 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
48 48 configDirective = "tbActionNodeTimeseriesConfig",
49   - icon = "file_upload",
50   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  49 + icon = "file_upload"
51 50 )
52 51 public class TbMsgTimeseriesNode implements TbNode {
53 52
... ...
... ... @@ -39,8 +39,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
39 39 "Subsequent messages will not be processed until the previous message processing is completed or timeout event occurs.\n" +
40 40 "Size of the queue per originator and timeout values are configurable on a system level",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42   - configDirective = "tbNodeEmptyConfig",
43   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  42 + configDirective = "tbNodeEmptyConfig"
44 43 )
45 44 @Deprecated
46 45 public class TbSynchronizationBeginNode implements TbNode {
... ...
... ... @@ -39,8 +39,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
39 39 nodeDescription = "This Node is now deprecated. Use \"Checkpoint\" instead.",
40 40 nodeDetails = "",
41 41 uiResources = {"static/rulenode/rulenode-core-config.js"},
42   - configDirective = ("tbNodeEmptyConfig"),
43   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  42 + configDirective = ("tbNodeEmptyConfig")
44 43 )
45 44 @Deprecated
46 45 public class TbSynchronizationEndNode implements TbNode {
... ...
... ... @@ -47,8 +47,7 @@ import java.util.HashSet;
47 47 "Alarm Originator found only in case original Originator is <code>Alarm</code> entity.",
48 48 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
49 49 configDirective = "tbTransformationNodeChangeOriginatorConfig",
50   - icon = "find_replace",
51   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  50 + icon = "find_replace"
52 51 )
53 52 public class TbChangeOriginatorNode extends TbAbstractTransformNode {
54 53
... ...
... ... @@ -38,8 +38,7 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
38 38 "<code>{ msg: <i style=\"color: #666;\">new payload</i>,<br/>&nbsp&nbsp&nbspmetadata: <i style=\"color: #666;\">new metadata</i>,<br/>&nbsp&nbsp&nbspmsgType: <i style=\"color: #666;\">new msgType</i> }</code><br/>" +
39 39 "All fields in resulting object are optional and will be taken from original message if not specified.",
40 40 uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
41   - configDirective = "tbTransformationNodeScriptConfig",
42   - ruleChainTypes = {RuleChainType.CORE, RuleChainType.EDGE}
  41 + configDirective = "tbTransformationNodeScriptConfig"
43 42 )
44 43 public class TbTransformMsgNode extends TbAbstractTransformNode {
45 44
... ...