Browse Source

Merge branch 'feature/edge-last-week' into feature/edge

pull/2818/head
Volodymyr Babak 7 years ago
parent
commit
bb95ce99f8
  1. 145
      application/src/main/data/json/tenant/rule_chains/edge_root_rule_chain.json
  2. 2
      application/src/main/data/json/tenant/rule_chains/root_rule_chain.json
  3. 23
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  4. 33
      application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
  5. 6
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  6. 25
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  7. 54
      application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java
  8. 8
      application/src/main/java/org/thingsboard/server/service/component/ComponentDiscoveryService.java
  9. 35
      application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java
  10. 227
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  11. 78
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmUpdateMsgConstructor.java
  12. 36
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AssetUpdateMsgConstructor.java
  13. 45
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardUpdateMsgConstructor.java
  14. 35
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceUpdateMsgConstructor.java
  15. 67
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityViewUpdateMsgConstructor.java
  16. 141
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainUpdateMsgConstructor.java
  17. 272
      application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultInitEdgeService.java
  18. 28
      application/src/main/java/org/thingsboard/server/service/edge/rpc/init/InitEdgeService.java
  19. 1
      application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
  20. 6
      common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java
  21. 16
      common/edge-api/src/main/proto/edge.proto
  22. 3
      dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java
  23. 8
      dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
  24. 70
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  25. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java
  26. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNode.java
  27. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java
  28. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java
  29. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java
  30. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java
  31. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java
  32. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java
  33. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java
  34. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java
  35. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNode.java
  36. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java
  37. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java
  38. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java
  39. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java
  40. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToCloudNode.java
  41. 13
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java
  42. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java
  43. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java
  44. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java
  45. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java
  46. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java
  47. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java
  48. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java
  49. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java
  50. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java
  51. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java
  52. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java
  53. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java
  54. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java
  55. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java
  56. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java
  57. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java
  58. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java
  59. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java
  60. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java
  61. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java
  62. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java
  63. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java
  64. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java
  65. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java
  66. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java
  67. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java
  68. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java
  69. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java
  70. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java
  71. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java
  72. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationBeginNode.java
  73. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationEndNode.java
  74. 4
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java
  75. 5
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java
  76. 73
      ui/src/app/api/component-descriptor.service.js
  77. 47
      ui/src/app/api/rule-chain.service.js
  78. 10
      ui/src/app/import-export/import-export.service.js
  79. 6
      ui/src/app/locale/locale.constant-en_US.json
  80. 2
      ui/src/app/rulechain/add-rulechains-to-edge.controller.js
  81. 10
      ui/src/app/rulechain/rulechain.controller.js
  82. 15
      ui/src/app/rulechain/rulechain.routes.js
  83. 40
      ui/src/app/rulechain/rulechains.controller.js
  84. 4
      ui/src/app/services/item-buffer.service.js
  85. 4
      ui/src/app/services/menu.service.js

145
application/src/main/data/json/tenant/rule_chains/edge_root_rule_chain.json

@ -0,0 +1,145 @@
{
"ruleChain": {
"additionalInfo": null,
"name": "Edge Root Rule Chain",
"type": "EDGE",
"firstRuleNodeId": null,
"root": true,
"debugMode": false,
"configuration": null,
"assignedEdges": [],
"assignedEdgesIds": []
},
"metadata": {
"firstNodeIndex": 2,
"nodes": [
{
"additionalInfo": {
"layoutX": 823,
"layoutY": 157
},
"type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
"name": "Save Timeseries",
"debugMode": false,
"configuration": {
"defaultTTL": 0
}
},
{
"additionalInfo": {
"layoutX": 824,
"layoutY": 52
},
"type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode",
"name": "Save Client Attributes",
"debugMode": false,
"configuration": {
"scope": "CLIENT_SCOPE"
}
},
{
"additionalInfo": {
"layoutX": 347,
"layoutY": 149
},
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode",
"name": "Message Type Switch",
"debugMode": false,
"configuration": {
"version": 0
}
},
{
"additionalInfo": {
"layoutX": 825,
"layoutY": 266
},
"type": "org.thingsboard.rule.engine.action.TbLogNode",
"name": "Log RPC from Device",
"debugMode": false,
"configuration": {
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
}
},
{
"additionalInfo": {
"layoutX": 824,
"layoutY": 378
},
"type": "org.thingsboard.rule.engine.action.TbLogNode",
"name": "Log Other",
"debugMode": false,
"configuration": {
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
}
},
{
"additionalInfo": {
"layoutX": 824,
"layoutY": 466
},
"type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode",
"name": "RPC Call Request",
"debugMode": false,
"configuration": {
"timeoutInSeconds": 60
}
},
{
"additionalInfo": {
"layoutX": 1134,
"layoutY": 132
},
"type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode",
"name": "Push to cloud",
"debugMode": false,
"configuration": {
"version": 0
}
}
],
"connections": [
{
"fromIndex": 0,
"toIndex": 6,
"type": "Success"
},
{
"fromIndex": 1,
"toIndex": 6,
"type": "Success"
},
{
"fromIndex": 2,
"toIndex": 4,
"type": "Other"
},
{
"fromIndex": 2,
"toIndex": 1,
"type": "Post attributes"
},
{
"fromIndex": 2,
"toIndex": 0,
"type": "Post telemetry"
},
{
"fromIndex": 2,
"toIndex": 3,
"type": "RPC Request from Device"
},
{
"fromIndex": 2,
"toIndex": 5,
"type": "RPC Request to Device"
},
{
"fromIndex": 3,
"toIndex": 6,
"type": "Success"
}
],
"ruleChainConnections": null
}
}

2
application/src/main/data/json/tenant/rule_chains/root_rule_chain.json

@ -2,9 +2,9 @@
"ruleChain": { "ruleChain": {
"additionalInfo": null, "additionalInfo": null,
"name": "Root Rule Chain", "name": "Root Rule Chain",
"type": "SYSTEM",
"firstRuleNodeId": null, "firstRuleNodeId": null,
"root": true, "root": true,
"type": "SYSTEM",
"debugMode": false, "debugMode": false,
"configuration": null "configuration": null
}, },

23
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -67,6 +67,7 @@ import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundle;
@ -491,28 +492,10 @@ public abstract class BaseController {
} }
} }
ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException { List<ComponentDescriptor> checkComponentDescriptorsByTypes(Set<ComponentType> types, RuleChainType ruleChainType) throws ThingsboardException {
try {
log.debug("[{}] Lookup component descriptor", clazz);
return checkNotNull(componentDescriptorService.getComponent(clazz));
} catch (Exception e) {
throw handleException(e, false);
}
}
List<ComponentDescriptor> checkComponentDescriptorsByType(ComponentType type) throws ThingsboardException {
try {
log.debug("[{}] Lookup component descriptors", type);
return componentDescriptorService.getComponents(type);
} catch (Exception e) {
throw handleException(e, false);
}
}
List<ComponentDescriptor> checkComponentDescriptorsByTypes(Set<ComponentType> types) throws ThingsboardException {
try { try {
log.debug("[{}] Lookup component descriptors", types); log.debug("[{}] Lookup component descriptors", types);
return componentDescriptorService.getComponents(types); return componentDescriptorService.getComponents(types, ruleChainType);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e, false); throw handleException(e, false);
} }

33
application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java

@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -34,41 +35,21 @@ import java.util.Set;
@RequestMapping("/api") @RequestMapping("/api")
public class ComponentDescriptorController extends BaseController { public class ComponentDescriptorController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
@RequestMapping(value = "/component/{componentDescriptorClazz:.+}", method = RequestMethod.GET)
@ResponseBody
public ComponentDescriptor getComponentDescriptorByClazz(@PathVariable("componentDescriptorClazz") String strComponentDescriptorClazz) throws ThingsboardException {
checkParameter("strComponentDescriptorClazz", strComponentDescriptorClazz);
try {
return checkComponentDescriptorByClazz(strComponentDescriptorClazz);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
@RequestMapping(value = "/components/{componentType}", method = RequestMethod.GET)
@ResponseBody
public List<ComponentDescriptor> getComponentDescriptorsByType(@PathVariable("componentType") String strComponentType) throws ThingsboardException {
checkParameter("componentType", strComponentType);
try {
return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
@RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET) @RequestMapping(value = "/components/{ruleChainType}", params = {"componentTypes"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public List<ComponentDescriptor> getComponentDescriptorsByTypes(@RequestParam("componentTypes") String[] strComponentTypes) throws ThingsboardException { public List<ComponentDescriptor> getComponentDescriptorsByTypes(@PathVariable("ruleChainType") String strRuleChainType,
@RequestParam("componentTypes") String[] strComponentTypes) throws ThingsboardException {
checkArrayParameter("componentTypes", strComponentTypes); checkArrayParameter("componentTypes", strComponentTypes);
checkParameter("ruleChainType", strRuleChainType);
try { try {
RuleChainType ruleChainType = RuleChainType.valueOf(strRuleChainType);
Set<ComponentType> componentTypes = new HashSet<>(); Set<ComponentType> componentTypes = new HashSet<>();
for (String strComponentType : strComponentTypes) { for (String strComponentType : strComponentTypes) {
componentTypes.add(ComponentType.valueOf(strComponentType)); componentTypes.add(ComponentType.valueOf(strComponentType));
} }
return checkComponentDescriptorsByTypes(componentTypes); return checkComponentDescriptorsByTypes(componentTypes, ruleChainType);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

6
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -90,9 +90,9 @@ public class EdgeController extends BaseController {
Edge result = checkNotNull(edgeService.saveEdge(edge)); Edge result = checkNotNull(edgeService.saveEdge(edge));
if (created) { if (created) {
RuleChain rootTenantRuleChain = ruleChainService.getRootTenantRuleChain(tenantId); RuleChain defaultRootEdgeRuleChain = ruleChainService.getDefaultRootEdgeRuleChain(tenantId);
ruleChainService.assignRuleChainToEdge(tenantId, rootTenantRuleChain.getId(), result.getId()); ruleChainService.assignRuleChainToEdge(tenantId, defaultRootEdgeRuleChain.getId(), result.getId());
edgeService.setRootRuleChain(tenantId, result, rootTenantRuleChain.getId()); edgeService.setRootRuleChain(tenantId, result, defaultRootEdgeRuleChain.getId());
} }
logEntityAction(result.getId(), result, null, created ? ActionType.ADDED : ActionType.UPDATED, null); logEntityAction(result.getId(), result, null, created ? ActionType.ADDED : ActionType.UPDATED, null);

25
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -430,7 +430,7 @@ public class RuleChainController extends BaseController {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.UNASSIGN_FROM_EDGE); RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.UNASSIGN_FROM_EDGE);
RuleChain savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId)); RuleChain savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId, false));
logEntityAction(ruleChainId, ruleChain, logEntityAction(ruleChainId, ruleChain,
null, null,
@ -494,7 +494,7 @@ public class RuleChainController extends BaseController {
} }
for (EdgeId edgeId : removedEdgeIds) { for (EdgeId edgeId : removedEdgeIds) {
ShortEdgeInfo edgeInfo = ruleChain.getAssignedEdgeInfo(edgeId); ShortEdgeInfo edgeInfo = ruleChain.getAssignedEdgeInfo(edgeId);
savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId)); savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId, false));
logEntityAction(ruleChainId, ruleChain, logEntityAction(ruleChainId, ruleChain,
null, null,
ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, edgeId.toString(), edgeInfo.getTitle()); ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, edgeId.toString(), edgeInfo.getTitle());
@ -581,7 +581,7 @@ public class RuleChainController extends BaseController {
RuleChain savedRuleChain = null; RuleChain savedRuleChain = null;
for (EdgeId edgeId : edgeIds) { for (EdgeId edgeId : edgeIds) {
ShortEdgeInfo edgeInfo = ruleChain.getAssignedEdgeInfo(edgeId); ShortEdgeInfo edgeInfo = ruleChain.getAssignedEdgeInfo(edgeId);
savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId)); savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId, false));
logEntityAction(ruleChainId, ruleChain, logEntityAction(ruleChainId, ruleChain,
null, null,
ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, edgeId.toString(), edgeInfo.getTitle()); ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, edgeId.toString(), edgeInfo.getTitle());
@ -620,4 +620,23 @@ public class RuleChainController extends BaseController {
throw handleException(e); throw handleException(e);
} }
} }
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/defaultRootEdge", method = RequestMethod.POST)
@ResponseBody
public RuleChain setDefaultRootEdgeRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
ruleChainService.setDefaultRootEdgeRuleChain(getTenantId(), ruleChainId);
return ruleChain;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.RULE_CHAIN),
null,
null,
ActionType.UPDATED, e, strRuleChainId);
throw handleException(e);
}
}
} }

54
application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java

@ -33,6 +33,7 @@ import org.thingsboard.rule.engine.api.TbRelationTypes;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.dao.component.ComponentDescriptorService; import org.thingsboard.server.dao.component.ComponentDescriptorService;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
@ -64,7 +65,9 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
private Map<String, ComponentDescriptor> components = new HashMap<>(); private Map<String, ComponentDescriptor> components = new HashMap<>();
private Map<ComponentType, List<ComponentDescriptor>> componentsMap = new HashMap<>(); private Map<ComponentType, List<ComponentDescriptor>> systemComponentsMap = new HashMap<>();
private Map<ComponentType, List<ComponentDescriptor>> edgeComponentsMap = new HashMap<>();
private ObjectMapper mapper = new ObjectMapper(); private ObjectMapper mapper = new ObjectMapper();
@ -92,7 +95,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
ComponentType type = ruleNodeAnnotation.type(); ComponentType type = ruleNodeAnnotation.type();
ComponentDescriptor component = scanAndPersistComponent(def, type); ComponentDescriptor component = scanAndPersistComponent(def, type);
components.put(component.getClazz(), component); components.put(component.getClazz(), component);
componentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component); putComponentIntoMaps(type, ruleNodeAnnotation, component);
break; break;
} catch (Exception e) { } catch (Exception e) {
log.trace("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); log.trace("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e);
@ -112,22 +115,22 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
} }
} }
private void registerComponents(ComponentType type, Class<? extends Annotation> annotation) { private void putComponentIntoMaps(ComponentType type, RuleNode ruleNodeAnnotation, ComponentDescriptor component) {
List<ComponentDescriptor> components = persist(getBeanDefinitions(annotation), type); if (ruleChainTypeContainsArray(RuleChainType.SYSTEM, ruleNodeAnnotation.ruleChainTypes())) {
componentsMap.put(type, components); systemComponentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component);
registerComponents(components); }
} if (ruleChainTypeContainsArray(RuleChainType.EDGE, ruleNodeAnnotation.ruleChainTypes())) {
edgeComponentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component);
private void registerComponents(Collection<ComponentDescriptor> comps) { }
comps.forEach(c -> components.put(c.getClazz(), c));
} }
private List<ComponentDescriptor> persist(Set<BeanDefinition> filterDefs, ComponentType type) { private boolean ruleChainTypeContainsArray(RuleChainType ruleChainType, RuleChainType[] array) {
List<ComponentDescriptor> result = new ArrayList<>(); for (RuleChainType tmp : array) {
for (BeanDefinition def : filterDefs) { if (ruleChainType.equals(tmp)) {
result.add(scanAndPersistComponent(def, type)); return true;
}
} }
return result; return false;
} }
private ComponentDescriptor scanAndPersistComponent(BeanDefinition def, ComponentType type) { private ComponentDescriptor scanAndPersistComponent(BeanDefinition def, ComponentType type) {
@ -221,25 +224,22 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
} }
@Override @Override
public List<ComponentDescriptor> getComponents(ComponentType type) { public List<ComponentDescriptor> getComponents(Set<ComponentType> types, RuleChainType ruleChainType) {
if (componentsMap.containsKey(type)) { if (RuleChainType.SYSTEM.equals(ruleChainType)) {
return Collections.unmodifiableList(componentsMap.get(type)); return getComponents(types, systemComponentsMap);
} else if (RuleChainType.EDGE.equals(ruleChainType)) {
return getComponents(types, edgeComponentsMap);
} else { } else {
return Collections.emptyList(); log.error("Unsupported rule chain type {}", ruleChainType);
throw new RuntimeException("Unsupported rule chain type " + ruleChainType);
} }
} }
@Override private List<ComponentDescriptor> getComponents(Set<ComponentType> types, Map<ComponentType, List<ComponentDescriptor>> componentsMap) {
public List<ComponentDescriptor> getComponents(Set<ComponentType> types) {
List<ComponentDescriptor> result = new ArrayList<>(); List<ComponentDescriptor> result = new ArrayList<>();
types.stream().filter(type -> componentsMap.containsKey(type)).forEach(type -> { types.stream().filter(componentsMap::containsKey).forEach(type -> {
result.addAll(componentsMap.get(type)); result.addAll(componentsMap.get(type));
}); });
return Collections.unmodifiableList(result); return Collections.unmodifiableList(result);
} }
@Override
public Optional<ComponentDescriptor> getComponent(String clazz) {
return Optional.ofNullable(components.get(clazz));
}
} }

8
application/src/main/java/org/thingsboard/server/service/component/ComponentDiscoveryService.java

@ -17,9 +17,9 @@ package org.thingsboard.server.service.component;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
/** /**
@ -29,10 +29,6 @@ public interface ComponentDiscoveryService {
void discoverComponents(); void discoverComponents();
List<ComponentDescriptor> getComponents(ComponentType type); List<ComponentDescriptor> getComponents(Set<ComponentType> types, RuleChainType ruleChainType);
List<ComponentDescriptor> getComponents(Set<ComponentType> types);
Optional<ComponentDescriptor> getComponent(String clazz);
} }

35
application/src/main/java/org/thingsboard/server/service/edge/EdgeContextComponent.java

@ -29,6 +29,13 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.service.edge.rpc.constructor.AlarmUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.init.InitEdgeService;
import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor;
@Component @Component
@Data @Data
@ -73,4 +80,32 @@ public class EdgeContextComponent {
@Lazy @Lazy
@Autowired @Autowired
private ActorService actorService; private ActorService actorService;
@Lazy
@Autowired
private InitEdgeService initEdgeService;
@Lazy
@Autowired
private RuleChainUpdateMsgConstructor ruleChainUpdateMsgConstructor;
@Lazy
@Autowired
private AlarmUpdateMsgConstructor alarmUpdateMsgConstructor;
@Lazy
@Autowired
private DeviceUpdateMsgConstructor deviceUpdateMsgConstructor;
@Lazy
@Autowired
private AssetUpdateMsgConstructor assetUpdateMsgConstructor;
@Lazy
@Autowired
private EntityViewUpdateMsgConstructor entityViewUpdateMsgConstructor;
@Lazy
@Autowired
private DashboardUpdateMsgConstructor dashboardUpdateMsgConstructor;
} }

227
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
@ -38,7 +37,6 @@ import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeQueueEntry; import org.thingsboard.server.common.data.edge.EdgeQueueEntry;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
@ -46,7 +44,6 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
@ -57,48 +54,36 @@ import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.AlarmUpdateMsg; import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.ConnectRequestMsg; import org.thingsboard.server.gen.edge.ConnectRequestMsg;
import org.thingsboard.server.gen.edge.ConnectResponseCode; import org.thingsboard.server.gen.edge.ConnectResponseCode;
import org.thingsboard.server.gen.edge.ConnectResponseMsg; import org.thingsboard.server.gen.edge.ConnectResponseMsg;
import org.thingsboard.server.gen.edge.CustomerUpdateMsg; import org.thingsboard.server.gen.edge.CustomerUpdateMsg;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg; import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.DownlinkMsg; import org.thingsboard.server.gen.edge.DownlinkMsg;
import org.thingsboard.server.gen.edge.EdgeConfiguration; import org.thingsboard.server.gen.edge.EdgeConfiguration;
import org.thingsboard.server.gen.edge.EntityDataProto; import org.thingsboard.server.gen.edge.EntityDataProto;
import org.thingsboard.server.gen.edge.EntityUpdateMsg; import org.thingsboard.server.gen.edge.EntityUpdateMsg;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.NodeConnectionInfoProto;
import org.thingsboard.server.gen.edge.RequestMsg; import org.thingsboard.server.gen.edge.RequestMsg;
import org.thingsboard.server.gen.edge.RequestMsgType; import org.thingsboard.server.gen.edge.RequestMsgType;
import org.thingsboard.server.gen.edge.ResponseMsg; import org.thingsboard.server.gen.edge.ResponseMsg;
import org.thingsboard.server.gen.edge.RuleChainConnectionInfoProto; import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg; import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.RuleNodeProto;
import org.thingsboard.server.gen.edge.UpdateMsgType; import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.gen.edge.UplinkMsg; import org.thingsboard.server.gen.edge.UplinkMsg;
import org.thingsboard.server.gen.edge.UplinkResponseMsg; import org.thingsboard.server.gen.edge.UplinkResponseMsg;
import org.thingsboard.server.gen.edge.UserUpdateMsg; import org.thingsboard.server.gen.edge.UserUpdateMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.service.edge.EdgeContextComponent;
import javax.swing.text.html.parser.Entity;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -109,7 +94,6 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import static org.thingsboard.server.gen.edge.UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE; import static org.thingsboard.server.gen.edge.UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE;
import static org.thingsboard.server.gen.edge.UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE;
@Slf4j @Slf4j
@Data @Data
@ -151,6 +135,9 @@ public final class EdgeGrpcSession implements Cloneable {
if (ConnectResponseCode.ACCEPTED != responseMsg.getResponseCode()) { if (ConnectResponseCode.ACCEPTED != responseMsg.getResponseCode()) {
outputStream.onError(new RuntimeException(responseMsg.getErrorMsg())); outputStream.onError(new RuntimeException(responseMsg.getErrorMsg()));
} }
if (ConnectResponseCode.ACCEPTED == responseMsg.getResponseCode()) {
ctx.getInitEdgeService().init(edge, outputStream);
}
} }
if (connected) { if (connected) {
if (requestMsg.getMsgType().equals(RequestMsgType.UPLINK_RPC_MESSAGE) && requestMsg.hasUplinkMsg()) { if (requestMsg.getMsgType().equals(RequestMsgType.UPLINK_RPC_MESSAGE) && requestMsg.hasUplinkMsg()) {
@ -174,15 +161,14 @@ public final class EdgeGrpcSession implements Cloneable {
}; };
} }
void processHandleMessages() throws ExecutionException, InterruptedException { void processHandleMessages() throws ExecutionException, InterruptedException {
Long queueStartTs = getQueueStartTs().get(); Long queueStartTs = getQueueStartTs().get();
// TODO: this 100 value must be changed properly // TODO: this 100 value must be changed properly
TimePageLink pageLink = new TimePageLink(30, queueStartTs + 1000); TimePageLink pageLink = new TimePageLink(30, queueStartTs + 1000, null, true);
TimePageData<Event> pageData; TimePageData<Event> pageData;
UUID ifOffset = null; UUID ifOffset = null;
do { do {
pageData = ctx.getEdgeService().findQueueEvents(edge.getTenantId(), edge.getId(), pageLink); pageData = ctx.getEdgeService().findQueueEvents(edge.getTenantId(), edge.getId(), pageLink);
if (!pageData.getData().isEmpty()) { if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] event(s) are going to be processed.", this.sessionId, pageData.getData().size()); log.trace("[{}] [{}] event(s) are going to be processed.", this.sessionId, pageData.getData().size());
for (Event event : pageData.getData()) { for (Event event : pageData.getData()) {
@ -377,7 +363,7 @@ public final class EdgeGrpcSession implements Cloneable {
private void onDeviceUpdated(UpdateMsgType msgType, Device device) { private void onDeviceUpdated(UpdateMsgType msgType, Device device) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDeviceUpdateMsg(constructDeviceUpdatedMsg(msgType, device)) .setDeviceUpdateMsg(ctx.getDeviceUpdateMsgConstructor().constructDeviceUpdatedMsg(msgType, device))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg) .setEntityUpdateMsg(entityUpdateMsg)
@ -386,7 +372,7 @@ public final class EdgeGrpcSession implements Cloneable {
private void onAssetUpdated(UpdateMsgType msgType, Asset asset) { private void onAssetUpdated(UpdateMsgType msgType, Asset asset) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setAssetUpdateMsg(constructAssetUpdatedMsg(msgType, asset)) .setAssetUpdateMsg(ctx.getAssetUpdateMsgConstructor().constructAssetUpdatedMsg(msgType, asset))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg) .setEntityUpdateMsg(entityUpdateMsg)
@ -395,7 +381,7 @@ public final class EdgeGrpcSession implements Cloneable {
private void onEntityViewUpdated(UpdateMsgType msgType, EntityView entityView) { private void onEntityViewUpdated(UpdateMsgType msgType, EntityView entityView) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setEntityViewUpdateMsg(constructEntityViewUpdatedMsg(msgType, entityView)) .setEntityViewUpdateMsg(ctx.getEntityViewUpdateMsgConstructor().constructEntityViewUpdatedMsg(msgType, entityView))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg) .setEntityUpdateMsg(entityUpdateMsg)
@ -404,7 +390,7 @@ public final class EdgeGrpcSession implements Cloneable {
private void onRuleChainUpdated(UpdateMsgType msgType, RuleChain ruleChain) { private void onRuleChainUpdated(UpdateMsgType msgType, RuleChain ruleChain) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRuleChainUpdateMsg(constructRuleChainUpdatedMsg(msgType, ruleChain)) .setRuleChainUpdateMsg(ctx.getRuleChainUpdateMsgConstructor().constructRuleChainUpdatedMsg(edge, msgType, ruleChain))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg) .setEntityUpdateMsg(entityUpdateMsg)
@ -412,7 +398,8 @@ public final class EdgeGrpcSession implements Cloneable {
} }
private void onRuleChainMetadataUpdated(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) { private void onRuleChainMetadataUpdated(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) {
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg = constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData); RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
ctx.getRuleChainUpdateMsgConstructor().constructRuleChainMetadataUpdatedMsg(msgType, ruleChainMetaData);
if (ruleChainMetadataUpdateMsg != null) { if (ruleChainMetadataUpdateMsg != null) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg) .setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
@ -425,7 +412,7 @@ public final class EdgeGrpcSession implements Cloneable {
private void onDashboardUpdated(UpdateMsgType msgType, Dashboard dashboard) { private void onDashboardUpdated(UpdateMsgType msgType, Dashboard dashboard) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDashboardUpdateMsg(constructDashboardUpdatedMsg(msgType, dashboard)) .setDashboardUpdateMsg(ctx.getDashboardUpdateMsgConstructor().constructDashboardUpdatedMsg(msgType, dashboard))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg) .setEntityUpdateMsg(entityUpdateMsg)
@ -434,43 +421,13 @@ public final class EdgeGrpcSession implements Cloneable {
private void onAlarmUpdated(UpdateMsgType msgType, Alarm alarm) { private void onAlarmUpdated(UpdateMsgType msgType, Alarm alarm) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder() EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setAlarmUpdateMsg(constructAlarmUpdatedMsg(msgType, alarm)) .setAlarmUpdateMsg(ctx.getAlarmUpdateMsgConstructor().constructAlarmUpdatedMsg(edge.getTenantId(), msgType, alarm))
.build(); .build();
outputStream.onNext(ResponseMsg.newBuilder() outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg) .setEntityUpdateMsg(entityUpdateMsg)
.build()); .build());
} }
private AlarmUpdateMsg constructAlarmUpdatedMsg(UpdateMsgType msgType, Alarm alarm) {
String entityName = null;
switch (alarm.getOriginator().getEntityType()) {
case DEVICE:
entityName = ctx.getDeviceService().findDeviceById(edge.getTenantId(), new DeviceId(alarm.getOriginator().getId())).getName();
break;
case ASSET:
entityName = ctx.getAssetService().findAssetById(edge.getTenantId(), new AssetId(alarm.getOriginator().getId())).getName();
break;
case ENTITY_VIEW:
entityName = ctx.getEntityViewService().findEntityViewById(edge.getTenantId(), new EntityViewId(alarm.getOriginator().getId())).getName();
break;
}
AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(alarm.getName())
.setType(alarm.getType())
.setOriginatorName(entityName)
.setOriginatorType(alarm.getOriginator().getEntityType().name())
.setSeverity(alarm.getSeverity().name())
.setStatus(alarm.getStatus().name())
.setStartTs(alarm.getStartTs())
.setEndTs(alarm.getEndTs())
.setAckTs(alarm.getAckTs())
.setClearTs(alarm.getClearTs())
.setDetails(JacksonUtil.toString(alarm.getDetails()))
.setPropagate(alarm.isPropagate());
return builder.build();
}
private UpdateMsgType getResponseMsgType(String msgType) { private UpdateMsgType getResponseMsgType(String msgType) {
if (msgType.equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) || if (msgType.equals(SessionMsgType.POST_TELEMETRY_REQUEST.name()) ||
msgType.equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) || msgType.equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name()) ||
@ -497,22 +454,6 @@ public final class EdgeGrpcSession implements Cloneable {
} }
} }
private RuleChainUpdateMsg constructRuleChainUpdatedMsg(UpdateMsgType msgType, RuleChain ruleChain) {
RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(ruleChain.getId().getId().getMostSignificantBits())
.setIdLSB(ruleChain.getId().getId().getLeastSignificantBits())
.setName(ruleChain.getName())
.setRoot(ruleChain.getId().equals(edge.getRootRuleChainId()))
.setDebugMode(ruleChain.isDebugMode())
.setConfiguration(JacksonUtil.toString(ruleChain.getConfiguration()));
if (ruleChain.getFirstRuleNodeId() != null) {
builder.setFirstRuleNodeIdMSB(ruleChain.getFirstRuleNodeId().getId().getMostSignificantBits())
.setFirstRuleNodeIdLSB(ruleChain.getFirstRuleNodeId().getId().getLeastSignificantBits());
}
return builder.build();
}
private DownlinkMsg constructDownlinkEntityDataMsg(String entityName, TbMsg tbMsg) { private DownlinkMsg constructDownlinkEntityDataMsg(String entityName, TbMsg tbMsg) {
EntityDataProto entityData = EntityDataProto.newBuilder() EntityDataProto entityData = EntityDataProto.newBuilder()
.setEntityName(entityName) .setEntityName(entityName)
@ -524,96 +465,6 @@ public final class EdgeGrpcSession implements Cloneable {
return builder.build(); return builder.build();
} }
private RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) {
try {
RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder()
.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits())
.setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits())
.addAllNodes(constructNodes(ruleChainMetaData.getNodes()))
.addAllConnections(constructConnections(ruleChainMetaData.getConnections()))
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections()));
if (ruleChainMetaData.getFirstNodeIndex() != null) {
builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex());
}
builder.setMsgType(msgType);
return builder.build();
} catch (JsonProcessingException ex) {
log.error("Can't construct RuleChainMetadataUpdateMsg", ex);
}
return null;
}
private List<RuleChainConnectionInfoProto> constructRuleChainConnections(List<RuleChainConnectionInfo> ruleChainConnections) throws JsonProcessingException {
List<RuleChainConnectionInfoProto> result = new ArrayList<>();
if (ruleChainConnections != null && !ruleChainConnections.isEmpty()) {
for (RuleChainConnectionInfo ruleChainConnectionInfo : ruleChainConnections) {
result.add(constructRuleChainConnection(ruleChainConnectionInfo));
}
}
return result;
}
private RuleChainConnectionInfoProto constructRuleChainConnection(RuleChainConnectionInfo ruleChainConnectionInfo) throws JsonProcessingException {
return RuleChainConnectionInfoProto.newBuilder()
.setFromIndex(ruleChainConnectionInfo.getFromIndex())
.setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits())
.setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits())
.setType(ruleChainConnectionInfo.getType())
.setAdditionalInfo(objectMapper.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo()))
.build();
}
private List<NodeConnectionInfoProto> constructConnections(List<NodeConnectionInfo> connections) {
List<NodeConnectionInfoProto> result = new ArrayList<>();
if (connections != null && !connections.isEmpty()) {
for (NodeConnectionInfo connection : connections) {
result.add(constructConnection(connection));
}
}
return result;
}
private NodeConnectionInfoProto constructConnection(NodeConnectionInfo connection) {
return NodeConnectionInfoProto.newBuilder()
.setFromIndex(connection.getFromIndex())
.setToIndex(connection.getToIndex())
.setType(connection.getType())
.build();
}
private List<RuleNodeProto> constructNodes(List<RuleNode> nodes) throws JsonProcessingException {
List<RuleNodeProto> result = new ArrayList<>();
if (nodes != null && !nodes.isEmpty()) {
for (RuleNode node : nodes) {
result.add(constructNode(node));
}
}
return result;
}
private RuleNodeProto constructNode(RuleNode node) throws JsonProcessingException {
return RuleNodeProto.newBuilder()
.setIdMSB(node.getId().getId().getMostSignificantBits())
.setIdLSB(node.getId().getId().getLeastSignificantBits())
.setType(node.getType())
.setName(node.getName())
.setDebugMode(node.isDebugMode())
.setConfiguration(objectMapper.writeValueAsString(node.getConfiguration()))
.setAdditionalInfo(objectMapper.writeValueAsString(node.getAdditionalInfo()))
.build();
}
private DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) {
dashboard = ctx.getDashboardService().findDashboardById(edge.getTenantId(), dashboard.getId());
DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(dashboard.getId().getId().getMostSignificantBits())
.setIdLSB(dashboard.getId().getId().getLeastSignificantBits())
.setTitle(dashboard.getTitle())
.setConfiguration(JacksonUtil.toString(dashboard.getConfiguration()));
return builder.build();
}
private CustomerUpdateMsg constructCustomerUpdatedMsg(UpdateMsgType msgType, Customer customer) { private CustomerUpdateMsg constructCustomerUpdatedMsg(UpdateMsgType msgType, Customer customer) {
CustomerUpdateMsg.Builder builder = CustomerUpdateMsg.newBuilder() CustomerUpdateMsg.Builder builder = CustomerUpdateMsg.newBuilder()
.setMsgType(msgType); .setMsgType(msgType);
@ -626,47 +477,6 @@ public final class EdgeGrpcSession implements Cloneable {
return builder.build(); return builder.build();
} }
private DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) {
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(device.getName())
.setType(device.getType());
return builder.build();
}
private AssetUpdateMsg constructAssetUpdatedMsg(UpdateMsgType msgType, Asset asset) {
AssetUpdateMsg.Builder builder = AssetUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(asset.getName())
.setType(asset.getType());
return builder.build();
}
private EntityViewUpdateMsg constructEntityViewUpdatedMsg(UpdateMsgType msgType, EntityView entityView) {
String relatedName;
String relatedType;
org.thingsboard.server.gen.edge.EntityType relatedEntityType;
if (entityView.getEntityId().getEntityType().equals(EntityType.DEVICE)) {
Device device = ctx.getDeviceService().findDeviceById(entityView.getTenantId(), new DeviceId(entityView.getEntityId().getId()));
relatedName = device.getName();
relatedType = device.getType();
relatedEntityType = org.thingsboard.server.gen.edge.EntityType.DEVICE;
} else {
Asset asset = ctx.getAssetService().findAssetById(entityView.getTenantId(), new AssetId(entityView.getEntityId().getId()));
relatedName = asset.getName();
relatedType = asset.getType();
relatedEntityType = org.thingsboard.server.gen.edge.EntityType.ASSET;
}
EntityViewUpdateMsg.Builder builder = EntityViewUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(entityView.getName())
.setType(entityView.getType())
.setRelatedName(relatedName)
.setRelatedType(relatedType)
.setRelatedEntityType(relatedEntityType);
return builder.build();
}
private UplinkResponseMsg processUplinkMsg(UplinkMsg uplinkMsg) { private UplinkResponseMsg processUplinkMsg(UplinkMsg uplinkMsg) {
try { try {
if (uplinkMsg.getEntityDataList() != null && !uplinkMsg.getEntityDataList().isEmpty()) { if (uplinkMsg.getEntityDataList() != null && !uplinkMsg.getEntityDataList().isEmpty()) {
@ -716,11 +526,16 @@ public final class EdgeGrpcSession implements Cloneable {
} }
} }
} }
if (uplinkMsg.getAlarmUpdatemsgList() != null && !uplinkMsg.getAlarmUpdatemsgList().isEmpty()) { if (uplinkMsg.getAlarmUpdateMsgList() != null && !uplinkMsg.getAlarmUpdateMsgList().isEmpty()) {
for (AlarmUpdateMsg alarmUpdateMsg : uplinkMsg.getAlarmUpdatemsgList()) { for (AlarmUpdateMsg alarmUpdateMsg : uplinkMsg.getAlarmUpdateMsgList()) {
onAlarmUpdate(alarmUpdateMsg); onAlarmUpdate(alarmUpdateMsg);
} }
} }
if (uplinkMsg.getRuleChainMetadataRequestMsgList() != null && !uplinkMsg.getRuleChainMetadataRequestMsgList().isEmpty()) {
for (RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg : uplinkMsg.getRuleChainMetadataRequestMsgList()) {
ctx.getInitEdgeService().initRuleChainMetadata(edge, ruleChainMetadataRequestMsg, outputStream);
}
}
} catch (Exception e) { } catch (Exception e) {
return UplinkResponseMsg.newBuilder().setSuccess(false).setErrorMsg(e.getMessage()).build(); return UplinkResponseMsg.newBuilder().setSuccess(false).setErrorMsg(e.getMessage()).build();
} }

78
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AlarmUpdateMsgConstructor.java

@ -0,0 +1,78 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jcajce.provider.symmetric.DES;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class AlarmUpdateMsgConstructor {
@Autowired
private DeviceService deviceService;
@Autowired
private AssetService assetService;
@Autowired
private EntityViewService entityViewService;
public AlarmUpdateMsg constructAlarmUpdatedMsg(TenantId tenantId, UpdateMsgType msgType, Alarm alarm) {
String entityName = null;
switch (alarm.getOriginator().getEntityType()) {
case DEVICE:
entityName = deviceService.findDeviceById(tenantId, new DeviceId(alarm.getOriginator().getId())).getName();
break;
case ASSET:
entityName = assetService.findAssetById(tenantId, new AssetId(alarm.getOriginator().getId())).getName();
break;
case ENTITY_VIEW:
entityName = entityViewService.findEntityViewById(tenantId, new EntityViewId(alarm.getOriginator().getId())).getName();
break;
}
AlarmUpdateMsg.Builder builder = AlarmUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(alarm.getName())
.setType(alarm.getType())
.setOriginatorName(entityName)
.setOriginatorType(alarm.getOriginator().getEntityType().name())
.setSeverity(alarm.getSeverity().name())
.setStatus(alarm.getStatus().name())
.setStartTs(alarm.getStartTs())
.setEndTs(alarm.getEndTs())
.setAckTs(alarm.getAckTs())
.setClearTs(alarm.getClearTs())
.setDetails(JacksonUtil.toString(alarm.getDetails()))
.setPropagate(alarm.isPropagate());
return builder.build();
}
}

36
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/AssetUpdateMsgConstructor.java

@ -0,0 +1,36 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class AssetUpdateMsgConstructor {
public AssetUpdateMsg constructAssetUpdatedMsg(UpdateMsgType msgType, Asset asset) {
AssetUpdateMsg.Builder builder = AssetUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(asset.getName())
.setType(asset.getType());
return builder.build();
}
}

45
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DashboardUpdateMsgConstructor.java

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class DashboardUpdateMsgConstructor {
@Autowired
private DashboardService dashboardService;
public DashboardUpdateMsg constructDashboardUpdatedMsg(UpdateMsgType msgType, Dashboard dashboard) {
dashboard = dashboardService.findDashboardById(dashboard.getTenantId(), dashboard.getId());
DashboardUpdateMsg.Builder builder = DashboardUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(dashboard.getId().getId().getMostSignificantBits())
.setIdLSB(dashboard.getId().getId().getLeastSignificantBits())
.setTitle(dashboard.getTitle())
.setConfiguration(JacksonUtil.toString(dashboard.getConfiguration()));
return builder.build();
}
}

35
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/DeviceUpdateMsgConstructor.java

@ -0,0 +1,35 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class DeviceUpdateMsgConstructor {
public DeviceUpdateMsg constructDeviceUpdatedMsg(UpdateMsgType msgType, Device device) {
DeviceUpdateMsg.Builder builder = DeviceUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(device.getName())
.setType(device.getType());
return builder.build();
}
}

67
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/EntityViewUpdateMsgConstructor.java

@ -0,0 +1,67 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.constructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
@Component
@Slf4j
public class EntityViewUpdateMsgConstructor {
@Autowired
private DeviceService deviceService;
@Autowired
private AssetService assetService;
public EntityViewUpdateMsg constructEntityViewUpdatedMsg(UpdateMsgType msgType, EntityView entityView) {
String relatedName;
String relatedType;
org.thingsboard.server.gen.edge.EntityType relatedEntityType;
if (entityView.getEntityId().getEntityType().equals(EntityType.DEVICE)) {
Device device = deviceService.findDeviceById(entityView.getTenantId(), new DeviceId(entityView.getEntityId().getId()));
relatedName = device.getName();
relatedType = device.getType();
relatedEntityType = org.thingsboard.server.gen.edge.EntityType.DEVICE;
} else {
Asset asset = assetService.findAssetById(entityView.getTenantId(), new AssetId(entityView.getEntityId().getId()));
relatedName = asset.getName();
relatedType = asset.getType();
relatedEntityType = org.thingsboard.server.gen.edge.EntityType.ASSET;
}
EntityViewUpdateMsg.Builder builder = EntityViewUpdateMsg.newBuilder()
.setMsgType(msgType)
.setName(entityView.getName())
.setType(entityView.getType())
.setRelatedName(relatedName)
.setRelatedType(relatedType)
.setRelatedEntityType(relatedEntityType);
return builder.build();
}
}

141
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainUpdateMsgConstructor.java

@ -0,0 +1,141 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.constructor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.util.mapping.JacksonUtil;
import org.thingsboard.server.gen.edge.NodeConnectionInfoProto;
import org.thingsboard.server.gen.edge.RuleChainConnectionInfoProto;
import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.RuleNodeProto;
import org.thingsboard.server.gen.edge.UpdateMsgType;
import java.util.ArrayList;
import java.util.List;
@Component
@Slf4j
public class RuleChainUpdateMsgConstructor {
private static final ObjectMapper objectMapper = new ObjectMapper();
public RuleChainUpdateMsg constructRuleChainUpdatedMsg(Edge edge, UpdateMsgType msgType, RuleChain ruleChain) {
RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder()
.setMsgType(msgType)
.setIdMSB(ruleChain.getId().getId().getMostSignificantBits())
.setIdLSB(ruleChain.getId().getId().getLeastSignificantBits())
.setName(ruleChain.getName())
.setRoot(ruleChain.getId().equals(edge.getRootRuleChainId()))
.setDebugMode(ruleChain.isDebugMode())
.setConfiguration(JacksonUtil.toString(ruleChain.getConfiguration()));
if (ruleChain.getFirstRuleNodeId() != null) {
builder.setFirstRuleNodeIdMSB(ruleChain.getFirstRuleNodeId().getId().getMostSignificantBits())
.setFirstRuleNodeIdLSB(ruleChain.getFirstRuleNodeId().getId().getLeastSignificantBits());
}
return builder.build();
}
public RuleChainMetadataUpdateMsg constructRuleChainMetadataUpdatedMsg(UpdateMsgType msgType, RuleChainMetaData ruleChainMetaData) {
try {
RuleChainMetadataUpdateMsg.Builder builder = RuleChainMetadataUpdateMsg.newBuilder()
.setRuleChainIdMSB(ruleChainMetaData.getRuleChainId().getId().getMostSignificantBits())
.setRuleChainIdLSB(ruleChainMetaData.getRuleChainId().getId().getLeastSignificantBits())
.addAllNodes(constructNodes(ruleChainMetaData.getNodes()))
.addAllConnections(constructConnections(ruleChainMetaData.getConnections()))
.addAllRuleChainConnections(constructRuleChainConnections(ruleChainMetaData.getRuleChainConnections()));
if (ruleChainMetaData.getFirstNodeIndex() != null) {
builder.setFirstNodeIndex(ruleChainMetaData.getFirstNodeIndex());
}
builder.setMsgType(msgType);
return builder.build();
} catch (JsonProcessingException ex) {
log.error("Can't construct RuleChainMetadataUpdateMsg", ex);
}
return null;
}
private List<NodeConnectionInfoProto> constructConnections(List<NodeConnectionInfo> connections) {
List<NodeConnectionInfoProto> result = new ArrayList<>();
if (connections != null && !connections.isEmpty()) {
for (NodeConnectionInfo connection : connections) {
result.add(constructConnection(connection));
}
}
return result;
}
private NodeConnectionInfoProto constructConnection(NodeConnectionInfo connection) {
return NodeConnectionInfoProto.newBuilder()
.setFromIndex(connection.getFromIndex())
.setToIndex(connection.getToIndex())
.setType(connection.getType())
.build();
}
private List<RuleNodeProto> constructNodes(List<RuleNode> nodes) throws JsonProcessingException {
List<RuleNodeProto> result = new ArrayList<>();
if (nodes != null && !nodes.isEmpty()) {
for (RuleNode node : nodes) {
result.add(constructNode(node));
}
}
return result;
}
private List<RuleChainConnectionInfoProto> constructRuleChainConnections(List<RuleChainConnectionInfo> ruleChainConnections) throws JsonProcessingException {
List<RuleChainConnectionInfoProto> result = new ArrayList<>();
if (ruleChainConnections != null && !ruleChainConnections.isEmpty()) {
for (RuleChainConnectionInfo ruleChainConnectionInfo : ruleChainConnections) {
result.add(constructRuleChainConnection(ruleChainConnectionInfo));
}
}
return result;
}
private RuleChainConnectionInfoProto constructRuleChainConnection(RuleChainConnectionInfo ruleChainConnectionInfo) throws JsonProcessingException {
return RuleChainConnectionInfoProto.newBuilder()
.setFromIndex(ruleChainConnectionInfo.getFromIndex())
.setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits())
.setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits())
.setType(ruleChainConnectionInfo.getType())
.setAdditionalInfo(objectMapper.writeValueAsString(ruleChainConnectionInfo.getAdditionalInfo()))
.build();
}
private RuleNodeProto constructNode(RuleNode node) throws JsonProcessingException {
return RuleNodeProto.newBuilder()
.setIdMSB(node.getId().getId().getMostSignificantBits())
.setIdLSB(node.getId().getId().getLeastSignificantBits())
.setType(node.getType())
.setName(node.getName())
.setDebugMode(node.isDebugMode())
.setConfiguration(objectMapper.writeValueAsString(node.getConfiguration()))
.setAdditionalInfo(objectMapper.writeValueAsString(node.getAdditionalInfo()))
.build();
}
}

272
application/src/main/java/org/thingsboard/server/service/edge/rpc/init/DefaultInitEdgeService.java

@ -0,0 +1,272 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.init;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.gen.edge.AssetUpdateMsg;
import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
import org.thingsboard.server.gen.edge.EntityUpdateMsg;
import org.thingsboard.server.gen.edge.EntityViewUpdateMsg;
import org.thingsboard.server.gen.edge.ResponseMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataUpdateMsg;
import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
import org.thingsboard.server.gen.edge.UpdateMsgType;
import org.thingsboard.server.service.edge.rpc.constructor.AssetUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DashboardUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.DeviceUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgConstructor;
import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor;
import java.util.UUID;
@Service
@Slf4j
public class DefaultInitEdgeService implements InitEdgeService {
@Autowired
private RuleChainService ruleChainService;
@Autowired
private DeviceService deviceService;
@Autowired
private AssetService assetService;
@Autowired
private EntityViewService entityViewService;
@Autowired
private DashboardService dashboardService;
@Autowired
private RuleChainUpdateMsgConstructor ruleChainUpdateMsgConstructor;
@Autowired
private DeviceUpdateMsgConstructor deviceUpdateMsgConstructor;
@Autowired
private AssetUpdateMsgConstructor assetUpdateMsgConstructor;
@Autowired
private EntityViewUpdateMsgConstructor entityViewUpdateMsgConstructor;
@Autowired
private DashboardUpdateMsgConstructor dashboardUpdateMsgConstructor;
@Override
public void init(Edge edge, StreamObserver<ResponseMsg> outputStream) {
initRuleChains(edge, outputStream);
initDevices(edge, outputStream);
initAssets(edge, outputStream);
initEntityViews(edge, outputStream);
initDashboards(edge, outputStream);
}
private void initDevices(Edge edge, StreamObserver<ResponseMsg> outputStream) {
try {
TextPageLink pageLink = new TextPageLink(100);
TextPageData<Device> pageData;
do {
pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink);
if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Device device : pageData.getData()) {
DeviceUpdateMsg deviceUpdateMsg =
deviceUpdateMsgConstructor.constructDeviceUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
device);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDeviceUpdateMsg(deviceUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
} catch (Exception e) {
log.error("Exception during loading edge device(s) on init!");
}
}
private void initAssets(Edge edge, StreamObserver<ResponseMsg> outputStream) {
try {
TextPageLink pageLink = new TextPageLink(100);
TextPageData<Asset> pageData;
do {
pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink);
if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Asset asset : pageData.getData()) {
AssetUpdateMsg assetUpdateMsg =
assetUpdateMsgConstructor.constructAssetUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
asset);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setAssetUpdateMsg(assetUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
} catch (Exception e) {
log.error("Exception during loading edge asset(s) on init!");
}
}
private void initEntityViews(Edge edge, StreamObserver<ResponseMsg> outputStream) {
try {
TextPageLink pageLink = new TextPageLink(100);
TextPageData<EntityView> pageData;
do {
pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink);
if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (EntityView entityView : pageData.getData()) {
EntityViewUpdateMsg entityViewUpdateMsg =
entityViewUpdateMsgConstructor.constructEntityViewUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
entityView);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setEntityViewUpdateMsg(entityViewUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
} catch (Exception e) {
log.error("Exception during loading edge entity view(s) on init!");
}
}
private void initDashboards(Edge edge, StreamObserver<ResponseMsg> outputStream) {
try {
TimePageLink pageLink = new TimePageLink(100);
TimePageData<DashboardInfo> pageData;
do {
pageData = dashboardService.findDashboardsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] dashboard(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (DashboardInfo dashboardInfo : pageData.getData()) {
Dashboard dashboard = dashboardService.findDashboardById(edge.getTenantId(), dashboardInfo.getId());
DashboardUpdateMsg dashboardUpdateMsg =
dashboardUpdateMsgConstructor.constructDashboardUpdatedMsg(
UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE,
dashboard);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setDashboardUpdateMsg(dashboardUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
} catch (Exception e) {
log.error("Exception during loading edge dashboard(s) on init!");
}
}
private void initRuleChains(Edge edge, StreamObserver<ResponseMsg> outputStream) {
try {
TimePageLink pageLink = new TimePageLink(100);
TimePageData<RuleChain> pageData;
do {
pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
if (!pageData.getData().isEmpty()) {
log.trace("[{}] [{}] rule chains(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (RuleChain ruleChain : pageData.getData()) {
RuleChainUpdateMsg ruleChainUpdateMsg =
ruleChainUpdateMsgConstructor.constructRuleChainUpdatedMsg(
edge,
UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
ruleChain);
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRuleChainUpdateMsg(ruleChainUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
} catch (Exception e) {
log.error("Exception during loading edge rule chain(s) on init!");
}
}
@Override
public void initRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream) {
if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {
RuleChainId ruleChainId = new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
RuleChainMetaData ruleChainMetaData = ruleChainService.loadRuleChainMetaData(edge.getTenantId(), ruleChainId);
RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg =
ruleChainUpdateMsgConstructor.constructRuleChainMetadataUpdatedMsg(
UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE,
ruleChainMetaData);
if (ruleChainMetadataUpdateMsg != null) {
EntityUpdateMsg entityUpdateMsg = EntityUpdateMsg.newBuilder()
.setRuleChainMetadataUpdateMsg(ruleChainMetadataUpdateMsg)
.build();
outputStream.onNext(ResponseMsg.newBuilder()
.setEntityUpdateMsg(entityUpdateMsg)
.build());
}
}
}
}

28
application/src/main/java/org/thingsboard/server/service/edge/rpc/init/InitEdgeService.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc.init;
import io.grpc.stub.StreamObserver;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.gen.edge.ResponseMsg;
import org.thingsboard.server.gen.edge.RuleChainMetadataRequestMsg;
public interface InitEdgeService {
void init(Edge edge, StreamObserver<ResponseMsg> outputStream);
void initRuleChainMetadata(Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg, StreamObserver<ResponseMsg> outputStream);
}

1
application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java

@ -115,7 +115,6 @@ public class InstallScripts {
RuleChainMetaData ruleChainMetaData = objectMapper.treeToValue(ruleChainJson.get("metadata"), RuleChainMetaData.class); RuleChainMetaData ruleChainMetaData = objectMapper.treeToValue(ruleChainJson.get("metadata"), RuleChainMetaData.class);
ruleChain.setTenantId(tenantId); ruleChain.setTenantId(tenantId);
ruleChain.setType(RuleChainType.SYSTEM);
ruleChain = ruleChainService.saveRuleChain(ruleChain); ruleChain = ruleChainService.saveRuleChain(ruleChain);
ruleChainMetaData.setRuleChainId(ruleChain.getId()); ruleChainMetaData.setRuleChainId(ruleChain.getId());

6
common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java

@ -71,11 +71,15 @@ public interface RuleChainService {
RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId); RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId);
RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId); RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId, boolean remove);
void unassignEdgeRuleChains(TenantId tenantId, EdgeId edgeId); void unassignEdgeRuleChains(TenantId tenantId, EdgeId edgeId);
void updateEdgeRuleChains(TenantId tenantId, EdgeId edgeId); void updateEdgeRuleChains(TenantId tenantId, EdgeId edgeId);
ListenableFuture<TimePageData<RuleChain>> findRuleChainsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink); ListenableFuture<TimePageData<RuleChain>> findRuleChainsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
RuleChain getDefaultRootEdgeRuleChain(TenantId tenantId);
boolean setDefaultRootEdgeRuleChain(TenantId tenantId, RuleChainId ruleChainId);
} }

16
common/edge-api/src/main/proto/edge.proto

@ -81,10 +81,10 @@ message ConnectResponseMsg {
message EdgeConfiguration { message EdgeConfiguration {
int64 tenantIdMSB = 1; int64 tenantIdMSB = 1;
int64 tenantIdLSB = 2; int64 tenantIdLSB = 2;
string name = 5; string name = 3;
string routingKey = 6; string routingKey = 4;
string type = 7; string type = 5;
string cloudType = 8; string cloudType = 6;
} }
enum UpdateMsgType { enum UpdateMsgType {
@ -224,6 +224,11 @@ message UserUpdateMsg {
string password = 13; string password = 13;
} }
message RuleChainMetadataRequestMsg {
int64 ruleChainIdMSB = 1;
int64 ruleChainIdLSB = 2;
}
enum EntityType { enum EntityType {
DEVICE = 0; DEVICE = 0;
ASSET = 1; ASSET = 1;
@ -237,7 +242,8 @@ message UplinkMsg {
int32 uplinkMsgId = 1; int32 uplinkMsgId = 1;
repeated EntityDataProto entityData = 2; repeated EntityDataProto entityData = 2;
repeated DeviceUpdateMsg deviceUpdateMsg = 3; repeated DeviceUpdateMsg deviceUpdateMsg = 3;
repeated AlarmUpdateMsg alarmUpdatemsg = 4; repeated AlarmUpdateMsg alarmUpdateMsg = 4;
repeated RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg = 5;
} }
message UplinkResponseMsg { message UplinkResponseMsg {

3
dao/src/main/java/org/thingsboard/server/dao/edge/BaseEdgeService.java

@ -216,7 +216,8 @@ public class BaseEdgeService extends AbstractEntityService implements EdgeServic
Edge edge = edgeDao.findById(tenantId, edgeId.getId()); Edge edge = edgeDao.findById(tenantId, edgeId.getId());
dashboardService.unassignEdgeDashboards(tenantId, edgeId); dashboardService.unassignEdgeDashboards(tenantId, edgeId);
ruleChainService.unassignEdgeRuleChains(tenantId, edgeId); // TODO: validate that rule chains are removed by deleteEntityRelations(tenantId, edgeId); call
ruleChainService.unassignEdgeRuleChains(tenantId, edgeId);
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
list.add(edge.getTenantId()); list.add(edge.getTenantId());

8
dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java

@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
@ -38,6 +39,7 @@ import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.tenant.TenantService;
@ -77,6 +79,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
@Autowired @Autowired
private RuleChainService ruleChainService; private RuleChainService ruleChainService;
@Autowired
private EdgeService edgeService;
@Override @Override
public void deleteEntityRelations(TenantId tenantId, EntityId entityId) { public void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
super.deleteEntityRelations(tenantId, entityId); super.deleteEntityRelations(tenantId, entityId);
@ -115,6 +120,9 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
case RULE_CHAIN: case RULE_CHAIN:
hasName = ruleChainService.findRuleChainByIdAsync(tenantId, new RuleChainId(entityId.getId())); hasName = ruleChainService.findRuleChainByIdAsync(tenantId, new RuleChainId(entityId.getId()));
break; break;
case EDGE:
hasName = edgeService.findEdgeByIdAsync(tenantId, new EdgeId(entityId.getId()));
break;
default: default:
throw new IllegalStateException("Not Implemented!"); throw new IllegalStateException("Not Implemented!");
} }

70
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.dao.rule; package org.thingsboard.server.dao.rule;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -47,7 +46,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.rule.RuleNode; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.edge.EdgeDao; import org.thingsboard.server.dao.edge.EdgeDao;
import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.DataValidator;
@ -62,9 +60,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import static org.thingsboard.server.dao.service.Validator.validateString;
/** /**
* Created by igor on 3/12/18. * Created by igor on 3/12/18.
@ -73,8 +68,6 @@ import static org.thingsboard.server.dao.service.Validator.validateString;
@Slf4j @Slf4j
public class BaseRuleChainService extends AbstractEntityService implements RuleChainService { public class BaseRuleChainService extends AbstractEntityService implements RuleChainService {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Autowired @Autowired
private RuleChainDao ruleChainDao; private RuleChainDao ruleChainDao;
@ -87,9 +80,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
@Autowired @Autowired
private EdgeDao edgeDao; private EdgeDao edgeDao;
@Autowired
private EdgeService edgeService;
@Override @Override
public RuleChain saveRuleChain(RuleChain ruleChain) { public RuleChain saveRuleChain(RuleChain ruleChain) {
ruleChainValidator.validate(ruleChain, RuleChain::getTenantId); ruleChainValidator.validate(ruleChain, RuleChain::getTenantId);
@ -121,7 +111,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(), createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
ruleChain.setRoot(true); ruleChain.setRoot(true);
ruleChain.setType(RuleChainType.SYSTEM);
ruleChainDao.save(tenantId, ruleChain); ruleChainDao.save(tenantId, ruleChain);
return true; return true;
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
@ -285,17 +274,27 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
@Override @Override
public RuleChain getRootTenantRuleChain(TenantId tenantId) { public RuleChain getRootTenantRuleChain(TenantId tenantId) {
return getRootRuleChainByType(tenantId, RuleChainType.SYSTEM);
}
private RuleChain getRootRuleChainByType(TenantId tenantId, RuleChainType type) {
Validator.validateId(tenantId, "Incorrect tenant id for search request."); Validator.validateId(tenantId, "Incorrect tenant id for search request.");
List<EntityRelation> relations = relationService.findByFrom(tenantId, tenantId, RelationTypeGroup.RULE_CHAIN); List<EntityRelation> relations = relationService.findByFrom(tenantId, tenantId, RelationTypeGroup.RULE_CHAIN);
if (relations != null && !relations.isEmpty()) { if (relations != null && !relations.isEmpty()) {
EntityRelation relation = relations.get(0); for (EntityRelation relation : relations) {
RuleChainId ruleChainId = new RuleChainId(relation.getTo().getId()); RuleChainId ruleChainId = new RuleChainId(relation.getTo().getId());
return findRuleChainById(tenantId, ruleChainId); RuleChain ruleChainById = findRuleChainById(tenantId, ruleChainId);
if (type.equals(ruleChainById.getType())) {
return ruleChainById;
}
}
return null;
} else { } else {
return null; return null;
} }
} }
@Override @Override
public List<RuleNode> getRuleChainNodes(TenantId tenantId, RuleChainId ruleChainId) { public List<RuleNode> getRuleChainNodes(TenantId tenantId, RuleChainId ruleChainId) {
Validator.validateId(ruleChainId, "Incorrect rule chain id for search request."); Validator.validateId(ruleChainId, "Incorrect rule chain id for search request.");
@ -417,13 +416,13 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
} }
@Override @Override
public RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId) { public RuleChain unassignRuleChainFromEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId, boolean remove) {
RuleChain ruleChain = findRuleChainById(tenantId, ruleChainId); RuleChain ruleChain = findRuleChainById(tenantId, ruleChainId);
Edge edge = edgeDao.findById(tenantId, edgeId.getId()); Edge edge = edgeDao.findById(tenantId, edgeId.getId());
if (edge == null) { if (edge == null) {
throw new DataValidationException("Can't unassign rule chain from non-existent edge!"); throw new DataValidationException("Can't unassign rule chain from non-existent edge!");
} }
if (edge.getRootRuleChainId() != null && edge.getRootRuleChainId().equals(ruleChainId)) { if (!remove && edge.getRootRuleChainId() != null && edge.getRootRuleChainId().equals(ruleChainId)) {
throw new DataValidationException("Can't unassign root rule chain from edge [" + edge.getName() + "]. Please assign another root rule chain first!"); throw new DataValidationException("Can't unassign root rule chain from edge [" + edge.getName() + "]. Please assign another root rule chain first!");
} }
if (ruleChain.removeAssignedEdge(edge)) { if (ruleChain.removeAssignedEdge(edge)) {
@ -479,6 +478,34 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
} }
@Override
public RuleChain getDefaultRootEdgeRuleChain(TenantId tenantId) {
return getRootRuleChainByType(tenantId, RuleChainType.EDGE);
}
@Override
public boolean setDefaultRootEdgeRuleChain(TenantId tenantId, RuleChainId ruleChainId) {
RuleChain ruleChain = ruleChainDao.findById(tenantId, ruleChainId.getId());
RuleChain previousDefaultRootEdgeRuleChain = getDefaultRootEdgeRuleChain(ruleChain.getTenantId());
if (!previousDefaultRootEdgeRuleChain.getId().equals(ruleChain.getId())) {
try {
deleteRelation(tenantId, new EntityRelation(previousDefaultRootEdgeRuleChain.getTenantId(), previousDefaultRootEdgeRuleChain.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
previousDefaultRootEdgeRuleChain.setRoot(false);
ruleChainDao.save(tenantId, previousDefaultRootEdgeRuleChain);
createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
ruleChain.setRoot(true);
ruleChainDao.save(tenantId, ruleChain);
return true;
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to set default root edge rule chain, ruleChainId: [{}]", ruleChainId);
throw new RuntimeException(e);
}
}
return false;
}
private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) { private void checkRuleNodesAndDelete(TenantId tenantId, RuleChainId ruleChainId) {
List<EntityRelation> nodeRelations = getRuleChainToNodeRelations(tenantId, ruleChainId); List<EntityRelation> nodeRelations = getRuleChainToNodeRelations(tenantId, ruleChainId);
for (EntityRelation relation : nodeRelations) { for (EntityRelation relation : nodeRelations) {
@ -537,12 +564,18 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
if (tenant == null) { if (tenant == null) {
throw new DataValidationException("Rule chain is referencing to non-existent tenant!"); throw new DataValidationException("Rule chain is referencing to non-existent tenant!");
} }
if (ruleChain.isRoot()) { if (ruleChain.isRoot() && RuleChainType.SYSTEM.equals(ruleChain.getType())) {
RuleChain rootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId()); RuleChain rootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId());
if (rootRuleChain != null && !rootRuleChain.getId().equals(ruleChain.getId())) { if (rootRuleChain != null && !rootRuleChain.getId().equals(ruleChain.getId())) {
throw new DataValidationException("Another root rule chain is present in scope of current tenant!"); throw new DataValidationException("Another root rule chain is present in scope of current tenant!");
} }
} }
if (ruleChain.isRoot() && RuleChainType.EDGE.equals(ruleChain.getType())) {
RuleChain defaultRootEdgeRuleChain = getDefaultRootEdgeRuleChain(ruleChain.getTenantId());
if (defaultRootEdgeRuleChain != null && !defaultRootEdgeRuleChain.getId().equals(ruleChain.getId())) {
throw new DataValidationException("Another default root edge rule chain is present in scope of current tenant!");
}
}
} }
}; };
@ -580,9 +613,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
@Override @Override
protected void removeEntity(TenantId tenantId, RuleChain entity) { protected void removeEntity(TenantId tenantId, RuleChain entity) {
unassignRuleChainFromEdge(edge.getTenantId(), new RuleChainId(entity.getUuidId()), this.edge.getId()); unassignRuleChainFromEdge(edge.getTenantId(), new RuleChainId(entity.getUuidId()), this.edge.getId(), true);
} }
} }
private class EdgeRuleChainsUpdater extends TimePaginatedRemover<Edge, RuleChain> { private class EdgeRuleChainsUpdater extends TimePaginatedRemover<Edge, RuleChain> {

3
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java

@ -17,6 +17,7 @@ package org.thingsboard.rule.engine.api;
import org.thingsboard.server.common.data.plugin.ComponentScope; import org.thingsboard.server.common.data.plugin.ComponentScope;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -57,4 +58,6 @@ public @interface RuleNode {
boolean customRelations() default false; boolean customRelations() default false;
RuleChainType[] ruleChainTypes() default RuleChainType.SYSTEM;
} }

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAssignToCustomerNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.*; import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -36,7 +37,8 @@ import org.thingsboard.server.common.msg.TbMsg;
"Will create new Customer if it doesn't exists and 'Create new Customer if not exists' is set to true.", "Will create new Customer if it doesn't exists and 'Create new Customer if not exists' is set to true.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeAssignToCustomerConfig", configDirective = "tbActionNodeAssignToCustomerConfig",
icon = "add_circle" icon = "add_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> { public class TbAssignToCustomerNode extends TbAbstractCustomerActionNode<TbAssignToCustomerNodeConfiguration> {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java

@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -44,7 +45,8 @@ import org.thingsboard.server.common.msg.TbMsg;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.", "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeClearAlarmConfig", configDirective = "tbActionNodeClearAlarmConfig",
icon = "notifications_off" icon = "notifications_off",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> { public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfiguration> {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCopyAttributesToEntityViewNode.java

@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.JsonConverter;
@ -56,7 +57,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"Changes message originator to related entity view and produces new messages according to count of updated entity views", "Changes message originator to related entity view and produces new messages according to count of updated entity views",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig", configDirective = "tbNodeEmptyConfig",
icon = "content_copy" icon = "content_copy",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbCopyAttributesToEntityViewNode implements TbNode { public class TbCopyAttributesToEntityViewNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.alarm.AlarmStatus;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.io.IOException; import java.io.IOException;
@ -50,7 +51,8 @@ import java.util.List;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.", "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCreateAlarmConfig", configDirective = "tbActionNodeCreateAlarmConfig",
icon = "notifications_active" icon = "notifications_active",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> { public class TbCreateAlarmNode extends TbAbstractAlarmNode<TbCreateAlarmNodeConfiguration> {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java

@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.ArrayList; import java.util.ArrayList;
@ -53,7 +54,8 @@ import java.util.List;
nodeDetails = "If the relation already exists or successfully created - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.", nodeDetails = "If the relation already exists or successfully created - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCreateRelationConfig", configDirective = "tbActionNodeCreateRelationConfig",
icon = "add_circle" icon = "add_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> { public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java

@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.util.EntityContainer;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.ArrayList; import java.util.ArrayList;
@ -44,7 +45,8 @@ import java.util.List;
nodeDetails = "If the relation(s) successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.", nodeDetails = "If the relation(s) successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeDeleteRelationConfig", configDirective = "tbActionNodeDeleteRelationConfig",
icon = "remove_circle" icon = "remove_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> { public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbLogNode.java

@ -20,6 +20,7 @@ import org.thingsboard.common.util.ListeningExecutor;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.common.util.DonAsynchron.withCallback; import static org.thingsboard.common.util.DonAsynchron.withCallback;
@ -36,7 +37,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.", "Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeLogConfig", configDirective = "tbActionNodeLogConfig",
icon = "menu" icon = "menu",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbLogNode implements TbNode { public class TbLogNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbMsgCountNode.java

@ -22,6 +22,7 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -42,7 +43,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDetails = "Count incoming messages for specified interval and produces POST_TELEMETRY_REQUEST msg with messages count", nodeDetails = "Count incoming messages for specified interval and produces POST_TELEMETRY_REQUEST msg with messages count",
icon = "functions", icon = "functions",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeMsgCountConfig" configDirective = "tbActionNodeMsgCountConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbMsgCountNode implements TbNode { public class TbMsgCountNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbSaveToCustomCassandraTableNode.java

@ -40,6 +40,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.cassandra.CassandraCluster; import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.model.type.AuthorityCodec; import org.thingsboard.server.dao.model.type.AuthorityCodec;
@ -77,7 +78,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
" otherwise, the message will be routed via <b>success</b> chain.", " otherwise, the message will be routed via <b>success</b> chain.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeCustomTableConfig", configDirective = "tbActionNodeCustomTableConfig",
icon = "file_upload") icon = "file_upload"
)
public class TbSaveToCustomCassandraTableNode implements TbNode { public class TbSaveToCustomCassandraTableNode implements TbNode {
private static final String TABLE_PREFIX = "cs_tb_"; private static final String TABLE_PREFIX = "cs_tb_";

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbUnassignFromCustomerNode.java

@ -23,6 +23,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.*; import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@RuleNode( @RuleNode(
@ -33,7 +34,8 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "Finds target Entity Customer by Customer name pattern and then unassign Originator Entity from this customer.", nodeDetails = "Finds target Entity Customer by Customer name pattern and then unassign Originator Entity from this customer.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeUnAssignToCustomerConfig", configDirective = "tbActionNodeUnAssignToCustomerConfig",
icon = "remove_circle" icon = "remove_circle",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> { public class TbUnassignFromCustomerNode extends TbAbstractCustomerActionNode<TbUnassignFromCustomerNodeConfiguration> {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sns/TbSnsNode.java

@ -27,6 +27,7 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -45,7 +46,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.", "For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSnsConfig", configDirective = "tbActionNodeSnsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+" iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbSnsNode implements TbNode { public class TbSnsNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/aws/sqs/TbSqsNode.java

@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -50,7 +51,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
" For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.", " For example <b>requestId</b> field can be accessed with <code>metadata.requestId</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSqsConfig", configDirective = "tbActionNodeSqsConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+" iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBkPSJNMTMuMjMgMTAuNTZWMTBjLTEuOTQgMC0zLjk5LjM5LTMuOTkgMi42NyAwIDEuMTYuNjEgMS45NSAxLjYzIDEuOTUuNzYgMCAxLjQzLS40NyAxLjg2LTEuMjIuNTItLjkzLjUtMS44LjUtMi44NG0yLjcgNi41M2MtLjE4LjE2LS40My4xNy0uNjMuMDYtLjg5LS43NC0xLjA1LTEuMDgtMS41NC0xLjc5LTEuNDcgMS41LTIuNTEgMS45NS00LjQyIDEuOTUtMi4yNSAwLTQuMDEtMS4zOS00LjAxLTQuMTcgMC0yLjE4IDEuMTctMy42NCAyLjg2LTQuMzggMS40Ni0uNjQgMy40OS0uNzYgNS4wNC0uOTNWNy41YzAtLjY2LjA1LTEuNDEtLjMzLTEuOTYtLjMyLS40OS0uOTUtLjctMS41LS43LTEuMDIgMC0xLjkzLjUzLTIuMTUgMS42MS0uMDUuMjQtLjI1LjQ4LS40Ny40OWwtMi42LS4yOGMtLjIyLS4wNS0uNDYtLjIyLS40LS41Ni42LTMuMTUgMy40NS00LjEgNi00LjEgMS4zIDAgMyAuMzUgNC4wMyAxLjMzQzE3LjExIDQuNTUgMTcgNi4xOCAxNyA3Ljk1djQuMTdjMCAxLjI1LjUgMS44MSAxIDIuNDguMTcuMjUuMjEuNTQgMCAuNzFsLTIuMDYgMS43OGgtLjAxIj48L3BhdGg+PHBhdGggZD0iTTIwLjE2IDE5LjU0QzE4IDIxLjE0IDE0LjgyIDIyIDEyLjEgMjJjLTMuODEgMC03LjI1LTEuNDEtOS44NS0zLjc2LS4yLS4xOC0uMDItLjQzLjI1LS4yOSAyLjc4IDEuNjMgNi4yNSAyLjYxIDkuODMgMi42MSAyLjQxIDAgNS4wNy0uNSA3LjUxLTEuNTMuMzctLjE2LjY2LjI0LjMyLjUxIj48L3BhdGg+PHBhdGggZD0iTTIxLjA3IDE4LjVjLS4yOC0uMzYtMS44NS0uMTctMi41Ny0uMDgtLjE5LjAyLS4yMi0uMTYtLjAzLS4zIDEuMjQtLjg4IDMuMjktLjYyIDMuNTMtLjMzLjI0LjMtLjA3IDIuMzUtMS4yNCAzLjMyLS4xOC4xNi0uMzUuMDctLjI2LS4xMS4yNi0uNjcuODUtMi4xNC41Ny0yLjV6Ij48L3BhdGg+PC9zdmc+",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbSqsNode implements TbNode { public class TbSqsNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/debug/TbMsgGeneratorNode.java

@ -23,6 +23,7 @@ import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
@ -43,7 +44,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
inEnabled = false, inEnabled = false,
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeGeneratorConfig", configDirective = "tbActionNodeGeneratorConfig",
icon = "repeat" icon = "repeat",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbMsgGeneratorNode implements TbNode { public class TbMsgGeneratorNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/delay/TbMsgDelayNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -44,7 +45,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDetails = "Delays messages for configurable period.", nodeDetails = "Delays messages for configurable period.",
icon = "pause", icon = "pause",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeMsgDelayConfig" configDirective = "tbActionNodeMsgDelayConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbMsgDelayNode implements TbNode { public class TbMsgDelayNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToCloudNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -35,7 +36,8 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "Pushes messages to cloud. This node is used only on Edge instances to push messages from Edge to Cloud.", nodeDetails = "Pushes messages to cloud. This node is used only on Edge instances to push messages from Edge to Cloud.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbNodeEmptyConfig", configDirective = "tbNodeEmptyConfig",
icon = "cloud_upload" icon = "cloud_upload",
ruleChainTypes = RuleChainType.EDGE
) )
public class TbMsgPushToCloudNode implements TbNode { public class TbMsgPushToCloudNode implements TbNode {

13
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/edge/TbMsgPushToEdgeNode.java

@ -25,6 +25,7 @@ import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@Slf4j @Slf4j
@RuleNode( @RuleNode(
@ -39,6 +40,11 @@ import org.thingsboard.server.common.msg.TbMsg;
) )
public class TbMsgPushToEdgeNode implements TbNode { public class TbMsgPushToEdgeNode implements TbNode {
private static final String CLOUD_MSG_SOURCE = "cloud";
private static final String EDGE_MSG_SOURCE = "edge";
private static final String MSG_SOURCE_KEY = "source";
private static final String TS_METADATA_KEY = "ts";
private EmptyNodeConfiguration config; private EmptyNodeConfiguration config;
@Override @Override
@ -48,6 +54,13 @@ public class TbMsgPushToEdgeNode implements TbNode {
@Override @Override
public void onMsg(TbContext ctx, TbMsg msg) { public void onMsg(TbContext ctx, TbMsg msg) {
if (EDGE_MSG_SOURCE.equalsIgnoreCase(msg.getMetaData().getValue(MSG_SOURCE_KEY))) {
return;
}
if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) {
msg.getMetaData().putValue(TS_METADATA_KEY, Long.toString(System.currentTimeMillis()));
}
msg.getMetaData().putValue(MSG_SOURCE_KEY, CLOUD_MSG_SOURCE);
ctx.getEdgeService().pushEventToEdge(ctx.getTenantId(), msg, new PushToEdgeNodeCallback(ctx, msg)); ctx.getEdgeService().pushEventToEdge(ctx.getTenantId(), msg, new PushToEdgeNodeCallback(ctx, msg));
} }

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckMessageNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.List; import java.util.List;
@ -39,7 +40,9 @@ import java.util.Map;
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" + 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" +
"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. ", "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. ",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckMessageConfig") configDirective = "tbFilterNodeCheckMessageConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbCheckMessageNode implements TbNode { public class TbCheckMessageNode implements TbNode {
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.List; import java.util.List;
@ -51,7 +52,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
" any relation to the originator of the message by type and direction.", " any relation to the originator of the message by type and direction.",
nodeDetails = "If at least one relation exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.", nodeDetails = "If at least one relation exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckRelationConfig") configDirective = "tbFilterNodeCheckRelationConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbCheckRelationNode implements TbNode { public class TbCheckRelationNode implements TbNode {
private TbCheckRelationNodeConfiguration config; private TbCheckRelationNodeConfiguration config;

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java

@ -20,6 +20,7 @@ import org.thingsboard.common.util.ListeningExecutor;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.common.util.DonAsynchron.withCallback; import static org.thingsboard.common.util.DonAsynchron.withCallback;
@ -36,7 +37,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" + "Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
"Message type can be accessed via <code>msgType</code> property.", "Message type can be accessed via <code>msgType</code> property.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeScriptConfig") configDirective = "tbFilterNodeScriptConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbJsFilterNode implements TbNode { public class TbJsFilterNode implements TbNode {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java

@ -20,6 +20,7 @@ import org.thingsboard.common.util.ListeningExecutor;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.Set; import java.util.Set;
@ -39,7 +40,9 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" + "Message metadata can be accessed via <code>metadata</code> property. For example <code>metadata.customerName === 'John';</code><br/>" +
"Message type can be accessed via <code>msgType</code> property.", "Message type can be accessed via <code>msgType</code> property.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeSwitchConfig") configDirective = "tbFilterNodeSwitchConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbJsSwitchNode implements TbNode { public class TbJsSwitchNode implements TbNode {
private TbJsSwitchNodeConfiguration config; private TbJsSwitchNodeConfiguration config;

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java

@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
/** /**
@ -33,7 +34,9 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDescription = "Filter incoming messages by Message Type", nodeDescription = "Filter incoming messages by Message Type",
nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.", nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbFilterNodeMessageTypeConfig") configDirective = "tbFilterNodeMessageTypeConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbMsgTypeFilterNode implements TbNode { public class TbMsgTypeFilterNode implements TbNode {
TbMsgTypeFilterNodeConfiguration config; TbMsgTypeFilterNodeConfiguration config;

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java

@ -20,6 +20,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
@ -34,7 +35,9 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
nodeDescription = "Route incoming messages by Message Type", nodeDescription = "Route incoming messages by Message Type",
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.", 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.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig") configDirective = "tbNodeEmptyConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbMsgTypeSwitchNode implements TbNode { public class TbMsgTypeSwitchNode implements TbNode {
EmptyNodeConfiguration config; EmptyNodeConfiguration config;

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java

@ -20,6 +20,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -31,7 +32,9 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDescription = "Filter incoming messages by message Originator Type", nodeDescription = "Filter incoming messages by message Originator Type",
nodeDetails = "If Originator Type of incoming message is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.", nodeDetails = "If Originator Type of incoming message is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbFilterNodeOriginatorTypeConfig") configDirective = "tbFilterNodeOriginatorTypeConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbOriginatorTypeFilterNode implements TbNode { public class TbOriginatorTypeFilterNode implements TbNode {
TbOriginatorTypeFilterNodeConfiguration config; TbOriginatorTypeFilterNodeConfiguration config;

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java

@ -20,6 +20,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -31,7 +32,9 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDescription = "Route incoming messages by Message Originator Type", nodeDescription = "Route incoming messages by Message Originator Type",
nodeDetails = "Routes messages to chain according to the originator type ('Device', 'Asset', etc.).", nodeDetails = "Routes messages to chain according to the originator type ('Device', 'Asset', etc.).",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig") configDirective = "tbNodeEmptyConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbOriginatorTypeSwitchNode implements TbNode { public class TbOriginatorTypeSwitchNode implements TbNode {
EmptyNodeConfiguration config; EmptyNodeConfiguration config;

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/gcp/pubsub/TbPubSubNode.java

@ -29,6 +29,7 @@ import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -49,7 +50,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
"<b>messageId</b> field can be accessed with <code>metadata.messageId</code>.", "<b>messageId</b> field can be accessed with <code>metadata.messageId</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodePubSubConfig", configDirective = "tbActionNodePubSubConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=" iconUrl = "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+Cjx0aXRsZT5DbG91ZCBQdWJTdWI8L3RpdGxlPgo8Zz4KPHBhdGggZD0iTTEyNi40Nyw1OC4xMmwtMjYuMy00NS43NEExMS41NiwxMS41NiwwLDAsMCw5MC4zMSw2LjVIMzcuN2ExMS41NSwxMS41NSwwLDAsMC05Ljg2LDUuODhMMS41Myw1OGExMS40OCwxMS40OCwwLDAsMCwwLDExLjQ0bDI2LjMsNDZhMTEuNzcsMTEuNzcsMCwwLDAsOS44Niw2LjA5SDkwLjNhMTEuNzMsMTEuNzMsMCwwLDAsOS44Ny02LjA2bDI2LjMtNDUuNzRBMTEuNzMsMTEuNzMsMCwwLDAsMTI2LjQ3LDU4LjEyWiIgc3R5bGU9ImZpbGw6ICM3MzViMmYiLz4KPHBhdGggZD0iTTg5LjIyLDQ3Ljc0LDgzLjM2LDQ5bC0xNC42LTE0LjZMNjQuMDksNDMuMSw2MS41NSw1My4ybDQuMjksNC4yOUw1Ny42LDU5LjE4LDQ2LjMsNDcuODhsLTcuNjcsNy4zOEw1Mi43Niw2OS4zN2wtMTUsMTEuOUw3OCwxMjEuNUg5MC4zYTExLjczLDExLjczLDAsMCwwLDkuODctNi4wNmwyMC43Mi0zNloiIHN0eWxlPSJvcGFjaXR5OiAwLjA3MDAwMDAwMDI5ODAyMztpc29sYXRpb246IGlzb2xhdGUiLz4KPHBhdGggZD0iTTgyLjg2LDQ3YTUuMzIsNS4zMiwwLDEsMS0xLjk1LDcuMjdBNS4zMiw1LjMyLDAsMCwxLDgyLjg2LDQ3IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNMzkuODIsNTYuMThhNS4zMiw1LjMyLDAsMSwxLDcuMjctMS45NSw1LjMyLDUuMzIsMCwwLDEtNy4yNywxLjk1IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNjkuMzIsODguODVBNS4zMiw1LjMyLDAsMSwxLDY0LDgzLjUyYTUuMzIsNS4zMiwwLDAsMSw1LjMyLDUuMzIiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxnPgo8cGF0aCBkPSJNNjQsNTIuOTRhMTEuMDYsMTEuMDYsMCwwLDEsMi40Ni4yOFYzOS4xNUg2MS41NFY1My4yMkExMS4wNiwxMS4wNiwwLDAsMSw2NCw1Mi45NFoiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik03NC41Nyw2Ny4yNmExMSwxMSwwLDAsMS0yLjQ3LDQuMjVsMTIuMTksNywyLjQ2LTQuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8cGF0aCBkPSJNNTMuNDMsNjcuMjZsLTEyLjE4LDcsMi40Niw0LjI2LDEyLjE5LTdBMTEsMTEsMCwwLDEsNTMuNDMsNjcuMjZaIiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+CjxwYXRoIGQ9Ik03Mi42LDY0QTguNiw4LjYsMCwxLDEsNjQsNTUuNCw4LjYsOC42LDAsMCwxLDcyLjYsNjQiIHN0eWxlPSJmaWxsOiAjZmZmIi8+CjxwYXRoIGQ9Ik0zOS4xLDcwLjU3YTYuNzYsNi43NiwwLDEsMS0yLjQ3LDkuMjMsNi43Niw2Ljc2LDAsMCwxLDIuNDctOS4yMyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTgyLjE0LDgyLjI3YTYuNzYsNi43NiwwLDEsMSw5LjIzLTIuNDcsNi43NSw2Ljc1LDAsMCwxLTkuMjMsMi40NyIgc3R5bGU9ImZpbGw6ICNmZmYiLz4KPHBhdGggZD0iTTcwLjc2LDM5LjE1QTYuNzYsNi43NiwwLDEsMSw2NCwzMi4zOWE2Ljc2LDYuNzYsMCwwLDEsNi43Niw2Ljc2IiBzdHlsZT0iZmlsbDogI2ZmZiIvPgo8L2c+Cjwvc3ZnPgo=",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbPubSubNode implements TbNode { public class TbPubSubNode implements TbNode {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingActionNode.java

@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.Collections; import java.util.Collections;
@ -51,7 +52,9 @@ import java.util.concurrent.TimeoutException;
nodeDescription = "Produces incoming messages using GPS based geofencing", nodeDescription = "Produces incoming messages using GPS based geofencing",
nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns different events based on configuration parameters", nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns different events based on configuration parameters",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeGpsGeofencingConfig") configDirective = "tbActionNodeGpsGeofencingConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGpsGeofencingActionNode extends AbstractGeofencingNode<TbGpsGeofencingActionNodeConfiguration> { public class TbGpsGeofencingActionNode extends AbstractGeofencingNode<TbGpsGeofencingActionNodeConfiguration> {
private final Map<EntityId, EntityGeofencingState> entityStates = new HashMap<>(); private final Map<EntityId, EntityGeofencingState> entityStates = new HashMap<>();

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/geo/TbGpsGeofencingFilterNode.java

@ -35,6 +35,7 @@ import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.filter.TbMsgTypeFilterNodeConfiguration; import org.thingsboard.rule.engine.filter.TbMsgTypeFilterNodeConfiguration;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.Collections; import java.util.Collections;
@ -52,7 +53,9 @@ import java.util.List;
nodeDescription = "Filter incoming messages by GPS based geofencing", nodeDescription = "Filter incoming messages by GPS based geofencing",
nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns 'True' if they are inside configured perimeters, 'False' otherwise.", nodeDetails = "Extracts latitude and longitude parameters from incoming message and returns 'True' if they are inside configured perimeters, 'False' otherwise.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeGpsGeofencingConfig") configDirective = "tbFilterNodeGpsGeofencingConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofencingFilterNodeConfiguration> { public class TbGpsGeofencingFilterNode extends AbstractGeofencingNode<TbGpsGeofencingFilterNodeConfiguration> {
@Override @Override

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/kafka/TbKafkaNode.java

@ -24,6 +24,7 @@ import org.apache.kafka.common.header.internals.RecordHeaders;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -43,7 +44,8 @@ import java.util.concurrent.ExecutionException;
" from the Kafka in the Message Metadata. For example <b>partition</b> field can be accessed with <code>metadata.partition</code>.", " from the Kafka in the Message Metadata. For example <b>partition</b> field can be accessed with <code>metadata.partition</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeKafkaConfig", configDirective = "tbActionNodeKafkaConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==" iconUrl = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTUzOCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDQxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTIwMS44MTYgMjMwLjIxNmMtMTYuMTg2IDAtMzAuNjk3IDcuMTcxLTQwLjYzNCAxOC40NjFsLTI1LjQ2My0xOC4wMjZjMi43MDMtNy40NDIgNC4yNTUtMTUuNDMzIDQuMjU1LTIzLjc5NyAwLTguMjE5LTEuNDk4LTE2LjA3Ni00LjExMi0yMy40MDhsMjUuNDA2LTE3LjgzNWM5LjkzNiAxMS4yMzMgMjQuNDA5IDE4LjM2NSA0MC41NDggMTguMzY1IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI5Ljg3OS0yNC4zMDktNTQuMTg0LTU0LjE4NC01NC4xODQtMjkuODc1IDAtNTQuMTg0IDI0LjMwNS01NC4xODQgNTQuMTg0IDAgNS4zNDguODA4IDEwLjUwNSAyLjI1OCAxNS4zODlsLTI1LjQyMyAxNy44NDRjLTEwLjYyLTEzLjE3NS0yNS45MTEtMjIuMzc0LTQzLjMzMy0yNS4xODJ2LTMwLjY0YzI0LjU0NC01LjE1NSA0My4wMzctMjYuOTYyIDQzLjAzNy01My4wMTlDMTI0LjE3MSAyNC4zMDUgOTkuODYyIDAgNjkuOTg3IDAgNDAuMTEyIDAgMTUuODAzIDI0LjMwNSAxNS44MDMgNTQuMTg0YzAgMjUuNzA4IDE4LjAxNCA0Ny4yNDYgNDIuMDY3IDUyLjc2OXYzMS4wMzhDMjUuMDQ0IDE0My43NTMgMCAxNzIuNDAxIDAgMjA2Ljg1NGMwIDM0LjYyMSAyNS4yOTIgNjMuMzc0IDU4LjM1NSA2OC45NHYzMi43NzRjLTI0LjI5OSA1LjM0MS00Mi41NTIgMjcuMDExLTQyLjU1MiA1Mi44OTQgMCAyOS44NzkgMjQuMzA5IDU0LjE4NCA1NC4xODQgNTQuMTg0IDI5Ljg3NSAwIDU0LjE4NC0yNC4zMDUgNTQuMTg0LTU0LjE4NCAwLTI1Ljg4My0xOC4yNTMtNDcuNTUzLTQyLjU1Mi01Mi44OTR2LTMyLjc3NWE2OS45NjUgNjkuOTY1IDAgMCAwIDQyLjYtMjQuNzc2bDI1LjYzMyAxOC4xNDNjLTEuNDIzIDQuODQtMi4yMiA5Ljk0Ni0yLjIyIDE1LjI0IDAgMjkuODc5IDI0LjMwOSA1NC4xODQgNTQuMTg0IDU0LjE4NCAyOS44NzUgMCA1NC4xODQtMjQuMzA1IDU0LjE4NC01NC4xODQgMC0yOS44NzktMjQuMzA5LTU0LjE4NC01NC4xODQtNTQuMTg0em0wLTEyNi42OTVjMTQuNDg3IDAgMjYuMjcgMTEuNzg4IDI2LjI3IDI2LjI3MXMtMTEuNzgzIDI2LjI3LTI2LjI3IDI2LjI3LTI2LjI3LTExLjc4Ny0yNi4yNy0yNi4yN2MwLTE0LjQ4MyAxMS43ODMtMjYuMjcxIDI2LjI3LTI2LjI3MXptLTE1OC4xLTQ5LjMzN2MwLTE0LjQ4MyAxMS43ODQtMjYuMjcgMjYuMjcxLTI2LjI3czI2LjI3IDExLjc4NyAyNi4yNyAyNi4yN2MwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3em01Mi41NDEgMzA3LjI3OGMwIDE0LjQ4My0xMS43ODMgMjYuMjctMjYuMjcgMjYuMjdzLTI2LjI3MS0xMS43ODctMjYuMjcxLTI2LjI3YzAtMTQuNDgzIDExLjc4NC0yNi4yNyAyNi4yNzEtMjYuMjdzMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3em0tMjYuMjcyLTExNy45N2MtMjAuMjA1IDAtMzYuNjQyLTE2LjQzNC0zNi42NDItMzYuNjM4IDAtMjAuMjA1IDE2LjQzNy0zNi42NDIgMzYuNjQyLTM2LjY0MiAyMC4yMDQgMCAzNi42NDEgMTYuNDM3IDM2LjY0MSAzNi42NDIgMCAyMC4yMDQtMTYuNDM3IDM2LjYzOC0zNi42NDEgMzYuNjM4em0xMzEuODMxIDY3LjE3OWMtMTQuNDg3IDAtMjYuMjctMTEuNzg4LTI2LjI3LTI2LjI3MXMxMS43ODMtMjYuMjcgMjYuMjctMjYuMjcgMjYuMjcgMTEuNzg3IDI2LjI3IDI2LjI3YzAgMTQuNDgzLTExLjc4MyAyNi4yNzEtMjYuMjcgMjYuMjcxeiIvPjwvc3ZnPg==",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbKafkaNode implements TbNode { public class TbKafkaNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java

@ -22,6 +22,7 @@ import org.springframework.util.StringUtils;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -40,7 +41,8 @@ import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
"Set 'SEND_EMAIL' output message type.", "Set 'SEND_EMAIL' output message type.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbTransformationNodeToEmailConfig", configDirective = "tbTransformationNodeToEmailConfig",
icon = "email" icon = "email",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbMsgToEmailNode implements TbNode { public class TbMsgToEmailNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java

@ -27,6 +27,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage;
@ -47,7 +48,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"with <code>to Email</code> Node using <code>Successful</code> chain.", "with <code>to Email</code> Node using <code>Successful</code> chain.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeSendEmailConfig", configDirective = "tbActionNodeSendEmailConfig",
icon = "send" icon = "send",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbSendEmailNode implements TbNode { public class TbSendEmailNode implements TbNode {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java

@ -25,6 +25,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
/** /**
@ -40,7 +41,9 @@ import org.thingsboard.server.common.msg.TbMsg;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ", "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeOriginatorAttributesConfig") configDirective = "tbEnrichmentNodeOriginatorAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> { public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttributesNodeConfiguration, EntityId> {
@Override @Override

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java

@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
@RuleNode( @RuleNode(
type = ComponentType.ENRICHMENT, type = ComponentType.ENRICHMENT,
@ -33,7 +34,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.temperature</code>.", "<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeCustomerAttributesConfig") configDirective = "tbEnrichmentNodeCustomerAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> { public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> {
@Override @Override

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerDetailsNode.java

@ -30,6 +30,7 @@ import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -41,7 +42,9 @@ import org.thingsboard.server.common.msg.TbMsg;
"<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" + "<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" +
"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.", "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.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeEntityDetailsConfig") configDirective = "tbEnrichmentNodeEntityDetailsConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration> { public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration> {
private static final String CUSTOMER_PREFIX = "customer_"; private static final String CUSTOMER_PREFIX = "customer_";

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetDeviceAttrNode.java

@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.util.EntitiesRelatedDeviceIdAsyncLoader;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -38,7 +39,9 @@ import org.thingsboard.server.common.msg.TbMsg;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ", "<code>metadata.cs_temperature</code> or <code>metadata.shared_limit</code> ",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeDeviceAttributesConfig") configDirective = "tbEnrichmentNodeDeviceAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> { public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDeviceAttrNodeConfiguration, DeviceId> {
@Override @Override

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetOriginatorFieldsNode.java

@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.util.EntitiesFieldsAsyncLoader; import org.thingsboard.rule.engine.util.EntitiesFieldsAsyncLoader;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.common.util.DonAsynchron.withCallback; import static org.thingsboard.common.util.DonAsynchron.withCallback;
@ -43,7 +44,9 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDescription = "Add Message Originator fields values into Message Metadata", nodeDescription = "Add Message Originator fields values into Message Metadata",
nodeDetails = "Will fetch fields values specified in mapping. If specified field is not part of originator fields it will be ignored.", nodeDetails = "Will fetch fields values specified in mapping. If specified field is not part of originator fields it will be ignored.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeOriginatorFieldsConfig") configDirective = "tbEnrichmentNodeOriginatorFieldsConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetOriginatorFieldsNode implements TbNode { public class TbGetOriginatorFieldsNode implements TbNode {
private TbGetOriginatorFieldsConfiguration config; private TbGetOriginatorFieldsConfiguration config;

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java

@ -22,6 +22,7 @@ import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
@RuleNode( @RuleNode(
type = ComponentType.ENRICHMENT, type = ComponentType.ENRICHMENT,
@ -35,7 +36,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.temperature</code>.", "<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeRelatedAttributesConfig") configDirective = "tbEnrichmentNodeRelatedAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> { public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java

@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.io.IOException; import java.io.IOException;
@ -66,7 +67,9 @@ import static org.thingsboard.server.common.data.kv.Aggregation.NONE;
"Also, the rule node allows you to select telemetry sampling order: <b>ASC</b> or <b>DESC</b>. </br>" + "Also, the rule node allows you to select telemetry sampling order: <b>ASC</b> or <b>DESC</b>. </br>" +
"<b>Note</b>: The maximum size of the fetched array is 1000 records.\n ", "<b>Note</b>: The maximum size of the fetched array is 1000 records.\n ",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase") configDirective = "tbEnrichmentNodeGetTelemetryFromDatabase",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetTelemetryNode implements TbNode { public class TbGetTelemetryNode implements TbNode {
private static final String DESC_ORDER = "DESC"; private static final String DESC_ORDER = "DESC";

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java

@ -23,6 +23,7 @@ import org.thingsboard.rule.engine.util.EntitiesTenantIdAsyncLoader;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
@Slf4j @Slf4j
@RuleNode( @RuleNode(
@ -35,7 +36,9 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
"To access those attributes in other nodes this template can be used " + "To access those attributes in other nodes this template can be used " +
"<code>metadata.temperature</code>.", "<code>metadata.temperature</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbEnrichmentNodeTenantAttributesConfig") configDirective = "tbEnrichmentNodeTenantAttributesConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> { public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> {
@Override @Override

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java

@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.ContactBased; import org.thingsboard.server.common.data.ContactBased;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -37,7 +38,9 @@ import org.thingsboard.server.common.msg.TbMsg;
"<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" + "<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" +
"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.", "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.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeEntityDetailsConfig") configDirective = "tbEnrichmentNodeEntityDetailsConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetTenantDetailsNodeConfiguration> { public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetTenantDetailsNodeConfiguration> {
private static final String TENANT_PREFIX = "tenant_"; private static final String TENANT_PREFIX = "tenant_";

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java

@ -30,6 +30,7 @@ import org.springframework.util.StringUtils;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -49,7 +50,8 @@ import java.util.concurrent.TimeoutException;
nodeDetails = "Will publish message payload to the MQTT broker with QoS <b>AT_LEAST_ONCE</b>.", nodeDetails = "Will publish message payload to the MQTT broker with QoS <b>AT_LEAST_ONCE</b>.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeMqttConfig", configDirective = "tbActionNodeMqttConfig",
icon = "call_split" icon = "call_split",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbMqttNode implements TbNode { public class TbMqttNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rabbitmq/TbRabbitMqNode.java

@ -22,6 +22,7 @@ import org.apache.commons.lang3.StringUtils;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
@ -39,7 +40,8 @@ import static org.thingsboard.common.util.DonAsynchron.withCallback;
nodeDetails = "Will publish message payload to RabbitMQ queue.", nodeDetails = "Will publish message payload to RabbitMQ queue.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRabbitMqConfig", configDirective = "tbActionNodeRabbitMqConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=" iconUrl = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIHN0cm9rZS13aWR0aD0iLjg0OTU2IiBkPSJtODYwLjQ3IDQxNi4zMmgtMjYyLjAxYy0xMi45MTMgMC0yMy42MTgtMTAuNzA0LTIzLjYxOC0yMy42MTh2LTI3Mi43MWMwLTIwLjMwNS0xNi4yMjctMzYuMjc2LTM2LjI3Ni0zNi4yNzZoLTkzLjc5MmMtMjAuMzA1IDAtMzYuMjc2IDE2LjIyNy0zNi4yNzYgMzYuMjc2djI3MC44NGMtMC4yNTQ4NyAxNC4xMDMtMTEuNDY5IDI1LjU3Mi0yNS43NDIgMjUuNTcybC04NS42MzYgMC42Nzk2NWMtMTQuMTAzIDAtMjUuNTcyLTExLjQ2OS0yNS41NzItMjUuNTcybDAuNjc5NjUtMjcxLjUyYzAtMjAuMzA1LTE2LjIyNy0zNi4yNzYtMzYuMjc2LTM2LjI3NmgtOTMuNTM3Yy0yMC4zMDUgMC0zNi4yNzYgMTYuMjI3LTM2LjI3NiAzNi4yNzZ2NzYzLjg0YzAgMTguMDk2IDE0Ljc4MiAzMi40NTMgMzIuNDUzIDMyLjQ1M2g3MjIuODFjMTguMDk2IDAgMzIuNDUzLTE0Ljc4MiAzMi40NTMtMzIuNDUzdi00MzUuMzFjLTEuMTg5NC0xOC4xODEtMTUuMjkyLTMyLjE5OC0zMy4zODgtMzIuMTk4em0tMTIyLjY4IDI4Ny4wN2MwIDIzLjYxOC0xOC44NiA0Mi40NzgtNDIuNDc4IDQyLjQ3OGgtNzMuOTk3Yy0yMy42MTggMC00Mi40NzgtMTguODYtNDIuNDc4LTQyLjQ3OHYtNzQuMjUyYzAtMjMuNjE4IDE4Ljg2LTQyLjQ3OCA0Mi40NzgtNDIuNDc4aDczLjk5N2MyMy42MTggMCA0Mi40NzggMTguODYgNDIuNDc4IDQyLjQ3OHoiLz48L3N2Zz4=",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbRabbitMqNode implements TbNode { public class TbRabbitMqNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rest/TbRestApiCallNode.java

@ -23,6 +23,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -41,7 +42,8 @@ import java.util.concurrent.ExecutionException;
"For example <b>statusCode</b> field can be accessed with <code>metadata.statusCode</code>.", "For example <b>statusCode</b> field can be accessed with <code>metadata.statusCode</code>.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRestApiCallConfig", configDirective = "tbActionNodeRestApiCallConfig",
iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+" iconUrl = "data:image/svg+xml;base64,PHN2ZyBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB2ZXJzaW9uPSIxLjEiIHk9IjBweCIgeD0iMHB4Ij48ZyB0cmFuc2Zvcm09Im1hdHJpeCguOTQ5NzUgMCAwIC45NDk3NSAxNy4xMiAyNi40OTIpIj48cGF0aCBkPSJtMTY5LjExIDEwOC41NGMtOS45MDY2IDAuMDczNC0xOS4wMTQgNi41NzI0LTIyLjAxNCAxNi40NjlsLTY5Ljk5MyAyMzEuMDhjLTMuNjkwNCAxMi4xODEgMy4yODkyIDI1LjIyIDE1LjQ2OSAyOC45MSAyLjIyNTkgMC42NzQ4MSA0LjQ5NjkgMSA2LjcyODUgMSA5Ljk3MjEgMCAxOS4xNjUtNi41MTUzIDIyLjE4Mi0xNi40NjdhNi41MjI0IDYuNTIyNCAwIDAgMCAwLjAwMiAtMC4wMDJsNjkuOTktMjMxLjA3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMCAtMC4wMDJjMy42ODU1LTEyLjE4MS0zLjI4Ny0yNS4yMjUtMTUuNDcxLTI4LjkxMi0yLjI4MjUtMC42OTE0NS00LjYxMTYtMS4wMTY5LTYuODk4NC0xem04NC45ODggMGMtOS45MDQ4IDAuMDczNC0xOS4wMTggNi41Njc1LTIyLjAxOCAxNi40NjlsLTY5Ljk4NiAyMzEuMDhjLTMuNjg5OCAxMi4xNzkgMy4yODUzIDI1LjIxNyAxNS40NjUgMjguOTA4IDIuMjI5NyAwLjY3NjQ3IDQuNTAwOCAxLjAwMiA2LjczMjQgMS4wMDIgOS45NzIxIDAgMTkuMTY1LTYuNTE1MyAyMi4xODItMTYuNDY3YTYuNTIyNCA2LjUyMjQgMCAwIDAgMC4wMDIgLTAuMDAybDY5Ljk4OC0yMzEuMDdjMy42OTA4LTEyLjE4MS0zLjI4NTItMjUuMjIzLTE1LjQ2Ny0yOC45MTItMi4yODE0LTAuNjkyMzEtNC42MTA4LTEuMDE4OS02Ljg5ODQtMS4wMDJ6bS0yMTcuMjkgNDIuMjNjLTEyLjcyOS0wLjAwMDg3LTIzLjE4OCAxMC40NTYtMjMuMTg4IDIzLjE4NiAwLjAwMSAxMi43MjggMTAuNDU5IDIzLjE4NiAyMy4xODggMjMuMTg2IDEyLjcyNy0wLjAwMSAyMy4xODMtMTAuNDU5IDIzLjE4NC0yMy4xODYgMC4wMDA4NzYtMTIuNzI4LTEwLjQ1Ni0yMy4xODUtMjMuMTg0LTIzLjE4NnptMCAxNDYuNjRjLTEyLjcyNy0wLjAwMDg3LTIzLjE4NiAxMC40NTUtMjMuMTg4IDIzLjE4NC0wLjAwMDg3MyAxMi43MjkgMTAuNDU4IDIzLjE4OCAyMy4xODggMjMuMTg4IDEyLjcyOC0wLjAwMSAyMy4xODQtMTAuNDYgMjMuMTg0LTIzLjE4OC0wLjAwMS0xMi43MjYtMTAuNDU3LTIzLjE4My0yMy4xODQtMjMuMTg0em0yNzAuNzkgNDIuMjExYy0xMi43MjcgMC0yMy4xODQgMTAuNDU3LTIzLjE4NCAyMy4xODRzMTAuNDU1IDIzLjE4OCAyMy4xODQgMjMuMTg4aDE1NC45OGMxMi43MjkgMCAyMy4xODYtMTAuNDYgMjMuMTg2LTIzLjE4OCAwLjAwMS0xMi43MjgtMTAuNDU4LTIzLjE4NC0yMy4xODYtMjMuMTg0eiIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzc2IDAgMCAxLjAzNzYgLTcuNTY3NiAtMTQuOTI1KSIgc3Ryb2tlLXdpZHRoPSIxLjI2OTMiLz48L2c+PC9zdmc+",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbRestApiCallNode implements TbNode { public class TbRestApiCallNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCReplyNode.java

@ -26,6 +26,7 @@ import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
@Slf4j @Slf4j
@ -37,7 +38,8 @@ import org.thingsboard.server.common.msg.TbMsg;
nodeDetails = "Expects messages with any message type. Will forward message body to the device.", nodeDetails = "Expects messages with any message type. Will forward message body to the device.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRpcReplyConfig", configDirective = "tbActionNodeRpcReplyConfig",
icon = "call_merge" icon = "call_merge",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbSendRPCReplyNode implements TbNode { public class TbSendRPCReplyNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/rpc/TbSendRPCRequestNode.java

@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.io.IOException; import java.io.IOException;
@ -53,7 +54,8 @@ import java.util.concurrent.TimeUnit;
"If the RPC call request is originated by REST API call from user, will forward the response to user immediately.", "If the RPC call request is originated by REST API call from user, will forward the response to user immediately.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeRpcRequestConfig", configDirective = "tbActionNodeRpcRequestConfig",
icon = "call_made" icon = "call_made",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbSendRPCRequestNode implements TbNode { public class TbSendRPCRequestNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgAttributesNode.java

@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.JsonConverter;
@ -44,7 +45,8 @@ import java.util.Set;
nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type", nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeAttributesConfig", configDirective = "tbActionNodeAttributesConfig",
icon = "file_upload" icon = "file_upload",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbMsgAttributesNode implements TbNode { public class TbMsgAttributesNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/telemetry/TbMsgTimeseriesNode.java

@ -28,6 +28,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.JsonConverter;
@ -45,7 +46,8 @@ import java.util.Map;
nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type", nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeTimeseriesConfig", configDirective = "tbActionNodeTimeseriesConfig",
icon = "file_upload" icon = "file_upload",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbMsgTimeseriesNode implements TbNode { public class TbMsgTimeseriesNode implements TbNode {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationBeginNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgTransactionData; import org.thingsboard.server.common.msg.TbMsgTransactionData;
@ -42,7 +43,9 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"Subsequent messages will not be processed until the previous message processing is completed or timeout event occurs.\n" + "Subsequent messages will not be processed until the previous message processing is completed or timeout event occurs.\n" +
"Size of the queue per originator and timeout values are configurable on a system level", "Size of the queue per originator and timeout values are configurable on a system level",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig") configDirective = "tbNodeEmptyConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbSynchronizationBeginNode implements TbNode { public class TbSynchronizationBeginNode implements TbNode {
private EmptyNodeConfiguration config; private EmptyNodeConfiguration config;

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transaction/TbSynchronizationEndNode.java

@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -38,7 +39,8 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
nodeDescription = "Stops synchronization of message processing based on message originator", nodeDescription = "Stops synchronization of message processing based on message originator",
nodeDetails = "", nodeDetails = "",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = ("tbNodeEmptyConfig") configDirective = ("tbNodeEmptyConfig"),
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbSynchronizationEndNode implements TbNode { public class TbSynchronizationEndNode implements TbNode {

4
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java

@ -31,6 +31,7 @@ import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader;
import org.thingsboard.rule.engine.util.EntitiesTenantIdAsyncLoader; import org.thingsboard.rule.engine.util.EntitiesTenantIdAsyncLoader;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.HashSet; import java.util.HashSet;
@ -46,7 +47,8 @@ import java.util.HashSet;
"Alarm Originator found only in case original Originator is <code>Alarm</code> entity.", "Alarm Originator found only in case original Originator is <code>Alarm</code> entity.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbTransformationNodeChangeOriginatorConfig", configDirective = "tbTransformationNodeChangeOriginatorConfig",
icon = "find_replace" icon = "find_replace",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
) )
public class TbChangeOriginatorNode extends TbAbstractTransformNode { public class TbChangeOriginatorNode extends TbAbstractTransformNode {

5
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java

@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE;
@ -37,7 +38,9 @@ import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
"<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/>" + "<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/>" +
"All fields in resulting object are optional and will be taken from original message if not specified.", "All fields in resulting object are optional and will be taken from original message if not specified.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"}, uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbTransformationNodeScriptConfig") configDirective = "tbTransformationNodeScriptConfig",
ruleChainTypes = {RuleChainType.SYSTEM, RuleChainType.EDGE}
)
public class TbTransformMsgNode extends TbAbstractTransformNode { public class TbTransformMsgNode extends TbAbstractTransformNode {
private TbTransformMsgNodeConfiguration config; private TbTransformMsgNodeConfiguration config;

73
ui/src/app/api/component-descriptor.service.js

@ -21,60 +21,38 @@ function ComponentDescriptorService($http, $q) {
var componentsByType = {}; var componentsByType = {};
var componentsByClazz = {}; var componentsByClazz = {};
var actionsByPlugin = {};
var service = { var service = {
getComponentDescriptorsByType: getComponentDescriptorsByType,
getComponentDescriptorByClazz: getComponentDescriptorByClazz,
getPluginActionsByPluginClazz: getPluginActionsByPluginClazz,
getComponentDescriptorsByTypes: getComponentDescriptorsByTypes getComponentDescriptorsByTypes: getComponentDescriptorsByTypes
} }
return service; return service;
function getComponentDescriptorsByType(componentType) { function getComponentDescriptorsByTypes(componentTypes, ruleChainType) {
var deferred = $q.defer();
if (componentsByType[componentType]) {
deferred.resolve(componentsByType[componentType]);
} else {
var url = '/api/components/' + componentType;
$http.get(url, null).then(function success(response) {
componentsByType[componentType] = response.data;
for (var i = 0; i < componentsByType[componentType].length; i++) {
var component = componentsByType[componentType][i];
componentsByClazz[component.clazz] = component;
}
deferred.resolve(componentsByType[componentType]);
}, function fail() {
deferred.reject();
});
}
return deferred.promise;
}
function getComponentDescriptorsByTypes(componentTypes) {
var deferred = $q.defer(); var deferred = $q.defer();
var result = []; var result = [];
if (!componentsByType[ruleChainType]) {
componentsByType[ruleChainType] = {};
}
for (var i=componentTypes.length-1;i>=0;i--) { for (var i=componentTypes.length-1;i>=0;i--) {
var componentType = componentTypes[i]; var componentType = componentTypes[i];
if (componentsByType[componentType]) { if (componentsByType[ruleChainType][componentType]) {
result = result.concat(componentsByType[componentType]); result = result.concat(componentsByType[ruleChainType][componentType]);
componentTypes.splice(i, 1); componentTypes.splice(i, 1);
} }
} }
if (!componentTypes.length) { if (!componentTypes.length) {
deferred.resolve(result); deferred.resolve(result);
} else { } else {
var url = '/api/components?componentTypes=' + componentTypes.join(','); var url = '/api/components/' + ruleChainType + '?componentTypes=' + componentTypes.join(',');
$http.get(url, null).then(function success(response) { $http.get(url, null).then(function success(response) {
var components = response.data; var components = response.data;
for (var i = 0; i < components.length; i++) { for (var i = 0; i < components.length; i++) {
var component = components[i]; var component = components[i];
var componentsList = componentsByType[component.type]; var componentsList = componentsByType[ruleChainType][component.type];
if (!componentsList) { if (!componentsList) {
componentsList = []; componentsList = [];
componentsByType[component.type] = componentsList; componentsByType[ruleChainType][component.type] = componentsList;
} }
componentsList.push(component); componentsList.push(component);
componentsByClazz[component.clazz] = component; componentsByClazz[component.clazz] = component;
@ -87,37 +65,4 @@ function ComponentDescriptorService($http, $q) {
} }
return deferred.promise; return deferred.promise;
} }
function getComponentDescriptorByClazz(componentDescriptorClazz) {
var deferred = $q.defer();
if (componentsByClazz[componentDescriptorClazz]) {
deferred.resolve(componentsByClazz[componentDescriptorClazz]);
} else {
var url = '/api/component/' + componentDescriptorClazz;
$http.get(url, null).then(function success(response) {
componentsByClazz[componentDescriptorClazz] = response.data;
deferred.resolve(componentsByClazz[componentDescriptorClazz]);
}, function fail() {
deferred.reject();
});
}
return deferred.promise;
}
function getPluginActionsByPluginClazz(pluginClazz) {
var deferred = $q.defer();
if (actionsByPlugin[pluginClazz]) {
deferred.resolve(actionsByPlugin[pluginClazz]);
} else {
var url = '/api/components/actions/' + pluginClazz;
$http.get(url, null).then(function success(response) {
actionsByPlugin[pluginClazz] = response.data;
deferred.resolve(actionsByPlugin[pluginClazz]);
}, function fail() {
deferred.reject();
});
}
return deferred.promise;
}
} }

47
ui/src/app/api/rule-chain.service.js

@ -19,7 +19,7 @@ export default angular.module('thingsboard.api.ruleChain', [])
/*@ngInject*/ /*@ngInject*/
function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, componentDescriptorService) { function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, componentDescriptorService) {
var ruleNodeComponents = null; var ruleNodeComponents = {};
var service = { var service = {
getRuleChains: getRuleChains, getRuleChains: getRuleChains,
@ -40,13 +40,15 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
addRuleChainEdges: addRuleChainEdges, addRuleChainEdges: addRuleChainEdges,
removeRuleChainEdges: removeRuleChainEdges, removeRuleChainEdges: removeRuleChainEdges,
getEdgeRuleChains: getEdgeRuleChains, getEdgeRuleChains: getEdgeRuleChains,
getEdgesRuleChains: getEdgesRuleChains,
assignRuleChainToEdge: assignRuleChainToEdge, assignRuleChainToEdge: assignRuleChainToEdge,
unassignRuleChainFromEdge: unassignRuleChainFromEdge unassignRuleChainFromEdge: unassignRuleChainFromEdge,
setDefaultRootEdgeRuleChain: setDefaultRootEdgeRuleChain
}; };
return service; return service;
function getRuleChains (pageLink, config, type) { function getRuleChains(pageLink, config, type) {
var deferred = $q.defer(); var deferred = $q.defer();
var url = '/api/ruleChains?limit=' + pageLink.limit; var url = '/api/ruleChains?limit=' + pageLink.limit;
if (angular.isDefined(pageLink.textSearch)) { if (angular.isDefined(pageLink.textSearch)) {
@ -152,20 +154,20 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return component.configurationDescriptor.nodeDefinition.customRelations; return component.configurationDescriptor.nodeDefinition.customRelations;
} }
function getRuleNodeComponents() { function getRuleNodeComponents(ruleChainType) {
var deferred = $q.defer(); var deferred = $q.defer();
if (ruleNodeComponents) { if (ruleNodeComponents[ruleChainType]) {
deferred.resolve(ruleNodeComponents); deferred.resolve(ruleNodeComponents[ruleChainType]);
} else { } else {
loadRuleNodeComponents().then( loadRuleNodeComponents(ruleChainType).then(
(components) => { (components) => {
resolveRuleNodeComponentsUiResources(components).then( resolveRuleNodeComponentsUiResources(components).then(
(components) => { (components) => {
ruleNodeComponents = components; ruleNodeComponents[ruleChainType] = components;
ruleNodeComponents.push( ruleNodeComponents[ruleChainType].push(
types.ruleChainNodeComponent types.ruleChainNodeComponent
); );
ruleNodeComponents.sort( ruleNodeComponents[ruleChainType].sort(
(comp1, comp2) => { (comp1, comp2) => {
var result = comp1.type.localeCompare(comp2.type); var result = comp1.type.localeCompare(comp2.type);
if (result == 0) { if (result == 0) {
@ -174,7 +176,7 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return result; return result;
} }
); );
deferred.resolve(ruleNodeComponents); deferred.resolve(ruleNodeComponents[ruleChainType]);
}, },
() => { () => {
deferred.reject(); deferred.reject();
@ -231,8 +233,8 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return deferred.promise; return deferred.promise;
} }
function getRuleNodeComponentByClazz(clazz) { function getRuleNodeComponentByClazz(clazz, ruleNodeType) {
var res = $filter('filter')(ruleNodeComponents, {clazz: clazz}, true); var res = $filter('filter')(ruleNodeComponents[ruleNodeType], {clazz: clazz}, true);
if (res && res.length) { if (res && res.length) {
return res[0]; return res[0];
} }
@ -282,8 +284,8 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return deferred.promise; return deferred.promise;
} }
function loadRuleNodeComponents() { function loadRuleNodeComponents(ruleChainType) {
return componentDescriptorService.getComponentDescriptorsByTypes(types.ruleNodeTypeComponentTypes); return componentDescriptorService.getComponentDescriptorsByTypes(types.ruleNodeTypeComponentTypes, ruleChainType);
} }
function testScript(inputParams) { function testScript(inputParams) {
@ -341,6 +343,10 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return deferred.promise; return deferred.promise;
} }
function getEdgesRuleChains(pageLink, config) {
return getRuleChains(pageLink, config, types.edgeRuleChainType);
}
function getEdgeRuleChains(edgeId, pageLink, config) { function getEdgeRuleChains(edgeId, pageLink, config) {
var deferred = $q.defer(); var deferred = $q.defer();
var url = '/api/edge/' + edgeId + '/ruleChains?limit=' + pageLink.limit; var url = '/api/edge/' + edgeId + '/ruleChains?limit=' + pageLink.limit;
@ -381,6 +387,17 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return deferred.promise; return deferred.promise;
} }
function setDefaultRootEdgeRuleChain(ruleChainId) {
var deferred = $q.defer();
var url = '/api/ruleChain/' + ruleChainId + '/defaultRootEdge';
$http.post(url).then(function success(response) {
deferred.resolve(response.data);
}, function fail() {
deferred.reject();
});
return deferred.promise;
}
function prepareRuleChains(ruleChainsData) { function prepareRuleChains(ruleChainsData) {
if (ruleChainsData.data) { if (ruleChainsData.data) {
for (var i = 0; i < ruleChainsData.data.length; i++) { for (var i = 0; i < ruleChainsData.data.length; i++) {

10
ui/src/app/import-export/import-export.service.js

@ -258,6 +258,8 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
} }
ruleChain.root = false; ruleChain.root = false;
delete ruleChain.assignedEdgesText; delete ruleChain.assignedEdgesText;
delete ruleChain.assignedEdges;
delete ruleChain.assignedEdgesIds;
return ruleChain; return ruleChain;
} }
@ -279,13 +281,16 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
toast.showError($translate.instant('rulechain.export-failed-error', {error: message})); toast.showError($translate.instant('rulechain.export-failed-error', {error: message}));
} }
function importRuleChain($event) { function importRuleChain($event, expectedRuleChainType) {
var deferred = $q.defer(); var deferred = $q.defer();
openImportDialog($event, 'rulechain.import', 'rulechain.rulechain-file').then( openImportDialog($event, 'rulechain.import', 'rulechain.rulechain-file').then(
function success(ruleChainImport) { function success(ruleChainImport) {
if (!validateImportedRuleChain(ruleChainImport)) { if (!validateImportedRuleChain(ruleChainImport)) {
toast.showError($translate.instant('rulechain.invalid-rulechain-file-error')); toast.showError($translate.instant('rulechain.invalid-rulechain-file-error'));
deferred.reject(); deferred.reject();
} else if (ruleChainImport.ruleChain.type !== expectedRuleChainType) {
toast.showError($translate.instant('rulechain.invalid-rulechain-type-error', {expectedRuleChainType: expectedRuleChainType}));
deferred.reject();
} else { } else {
deferred.resolve(ruleChainImport); deferred.resolve(ruleChainImport);
} }
@ -307,6 +312,9 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
if (angular.isUndefined(ruleChainImport.ruleChain.name)) { if (angular.isUndefined(ruleChainImport.ruleChain.name)) {
return false; return false;
} }
if (angular.isUndefined(ruleChainImport.ruleChain.type)) {
return false;
}
return true; return true;
} }

6
ui/src/app/locale/locale.constant-en_US.json

@ -1559,7 +1559,11 @@
"assign-to-edges-text": "Please select the edges to assign the rulechain(s)", "assign-to-edges-text": "Please select the edges to assign the rulechain(s)",
"unassign-from-edges": "Unassign Rule Chain(s) From Edges", "unassign-from-edges": "Unassign Rule Chain(s) From Edges",
"unassign-from-edges-text": "Please select the edges to unassign from the rulechain(s)", "unassign-from-edges-text": "Please select the edges to unassign from the rulechain(s)",
"assigned-to-edges": "Assigned to edges" "assigned-to-edges": "Assigned to edges",
"set-default-root-edge": "Make rule chain default root",
"set-default-root-edge-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' default edge root?",
"set-default-root-edge-rulechain-text": "After the confirmation the rule chain will become default edge root and will handle all incoming transport messages.",
"invalid-rulechain-type-error": "Unable to import rule chain: Invalid rule chain type. Expected type is {{expectedRuleChainType}}."
}, },
"rulenode": { "rulenode": {
"details": "Details", "details": "Details",

2
ui/src/app/rulechain/add-rulechains-to-edge.controller.js

@ -52,7 +52,7 @@ export default function AddRuleChainsToEdgeController(ruleChainService, $mdDialo
fetchMoreItems_: function () { fetchMoreItems_: function () {
if (vm.ruleChains.hasNext && !vm.ruleChains.pending) { if (vm.ruleChains.hasNext && !vm.ruleChains.pending) {
vm.ruleChains.pending = true; vm.ruleChains.pending = true;
ruleChainService.getRuleChains(vm.ruleChains.nextPageLink).then( ruleChainService.getEdgesRuleChains(vm.ruleChains.nextPageLink).then(
function success(ruleChains) { function success(ruleChains) {
vm.ruleChains.data = ruleChains.data; vm.ruleChains.data = ruleChains.data;
vm.ruleChains.nextPageLink = ruleChains.nextPageLink; vm.ruleChains.nextPageLink = ruleChains.nextPageLink;

10
ui/src/app/rulechain/rulechain.controller.js

@ -774,7 +774,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
x = scrollLeft + scrollParent.width()/2; x = scrollLeft + scrollParent.width()/2;
y = scrollTop + scrollParent.height()/2; y = scrollTop + scrollParent.height()/2;
} }
var ruleNodes = itembuffer.pasteRuleNodes(x, y, event); var ruleNodes = itembuffer.pasteRuleNodes(vm.ruleChain.type, x, y);
if (ruleNodes) { if (ruleNodes) {
vm.modelservice.deselectAll(); vm.modelservice.deselectAll();
var nodes = []; var nodes = [];
@ -972,7 +972,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
var nodes = []; var nodes = [];
for (var i=0;i<vm.ruleChainMetaData.nodes.length;i++) { for (var i=0;i<vm.ruleChainMetaData.nodes.length;i++) {
var ruleNode = vm.ruleChainMetaData.nodes[i]; var ruleNode = vm.ruleChainMetaData.nodes[i];
var component = ruleChainService.getRuleNodeComponentByClazz(ruleNode.type); var component = ruleChainService.getRuleNodeComponentByClazz(ruleNode.type, vm.ruleChain.type);
if (component) { if (component) {
var icon = vm.types.ruleNodeType[component.type].icon; var icon = vm.types.ruleNodeType[component.type].icon;
var iconUrl = null; var iconUrl = null;
@ -1269,7 +1269,11 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
vm.isDirty = false; vm.isDirty = false;
vm.isImport = false; vm.isImport = false;
$mdUtil.nextTick(() => { $mdUtil.nextTick(() => {
$state.go('home.ruleChains.ruleChain', {ruleChainId: vm.ruleChain.id.id}); if (vm.ruleChain.type === vm.types.systemRuleChainType) {
$state.go('home.ruleChains.system.ruleChain', {ruleChainId: vm.ruleChain.id.id});
} else {
$state.go('home.ruleChains.edge.ruleChain', {ruleChainId: vm.ruleChain.id.id});
}
}); });
} else { } else {
prepareRuleChain(); prepareRuleChain();

15
ui/src/app/rulechain/rulechain.routes.js

@ -22,7 +22,7 @@ import ruleChainTemplate from './rulechain.tpl.html';
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/ /*@ngInject*/
export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider) { export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider, types) {
NodeTemplatePathProvider.setTemplatePath(ruleNodeTemplate); NodeTemplatePathProvider.setTemplatePath(ruleNodeTemplate);
@ -56,7 +56,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ncyBreadcrumb: { ncyBreadcrumb: {
label: '{"icon": "settings_ethernet", "label": "rulechain.system-rulechains"}' label: '{"icon": "settings_ethernet", "label": "rulechain.system-rulechains"}'
} }
}).state('home.ruleChains.ruleChain', { }).state('home.ruleChains.system.ruleChain', {
url: '/:ruleChainId', url: '/:ruleChainId',
reloadOnSearch: false, reloadOnSearch: false,
module: 'private', module: 'private',
@ -82,7 +82,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ruleNodeComponents: ruleNodeComponents:
/*@ngInject*/ /*@ngInject*/
function($stateParams, ruleChainService) { function($stateParams, ruleChainService) {
return ruleChainService.getRuleNodeComponents(); return ruleChainService.getRuleNodeComponents(types.systemRuleChainType);
} }
}, },
data: { data: {
@ -106,7 +106,8 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
} }
}, },
params: { params: {
ruleChainImport: {} ruleChainImport: {},
ruleChainType: {}
}, },
resolve: { resolve: {
ruleChain: ruleChain:
@ -122,7 +123,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ruleNodeComponents: ruleNodeComponents:
/*@ngInject*/ /*@ngInject*/
function($stateParams, ruleChainService) { function($stateParams, ruleChainService) {
return ruleChainService.getRuleNodeComponents(); return ruleChainService.getRuleNodeComponents($stateParams.ruleChainType);
} }
}, },
data: { data: {
@ -179,7 +180,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ruleNodeComponents: ruleNodeComponents:
/*@ngInject*/ /*@ngInject*/
function($stateParams, ruleChainService) { function($stateParams, ruleChainService) {
return ruleChainService.getRuleNodeComponents(); return ruleChainService.getRuleNodeComponents(types.edgeRuleChainType);
} }
}, },
data: { data: {
@ -236,7 +237,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
ruleNodeComponents: ruleNodeComponents:
/*@ngInject*/ /*@ngInject*/
function($stateParams, ruleChainService) { function($stateParams, ruleChainService) {
return ruleChainService.getRuleNodeComponents(); return ruleChainService.getRuleNodeComponents(types.edgeRuleChainType);
} }
}, },
data: { data: {

40
ui/src/app/rulechain/rulechains.controller.js

@ -164,9 +164,9 @@ export default function RuleChainsController(ruleChainService, userService, edge
}); });
vm.ruleChainGridConfig.addItemActions.push({ vm.ruleChainGridConfig.addItemActions.push({
onAction: function ($event) { onAction: function ($event) {
importExport.importRuleChain($event).then( importExport.importRuleChain($event, types.systemRuleChainType).then(
function(ruleChainImport) { function(ruleChainImport) {
$state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport}); $state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.systemRuleChainType});
} }
); );
}, },
@ -202,6 +202,16 @@ export default function RuleChainsController(ruleChainService, userService, edge
isEnabled: isNonRootRuleChain isEnabled: isNonRootRuleChain
}); });
ruleChainActionsList.push({
onAction: function ($event, item) {
setDefaultRootEdgeRuleChain($event, item);
},
name: function() { return $translate.instant('rulechain.set-default-root-edge') },
details: function() { return $translate.instant('rulechain.set-default-root-edge') },
icon: "flag",
isEnabled: isNonRootRuleChain
});
ruleChainGroupActionsList.push( ruleChainGroupActionsList.push(
{ {
onAction: function ($event, items) { onAction: function ($event, items) {
@ -250,9 +260,9 @@ export default function RuleChainsController(ruleChainService, userService, edge
}); });
vm.ruleChainGridConfig.addItemActions.push({ vm.ruleChainGridConfig.addItemActions.push({
onAction: function ($event) { onAction: function ($event) {
importExport.importRuleChain($event).then( importExport.importRuleChain($event, types.edgeRuleChainType).then(
function(ruleChainImport) { function(ruleChainImport) {
$state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport}); $state.go('home.ruleChains.importRuleChain', {ruleChainImport:ruleChainImport, ruleChainType: types.edgeRuleChainType});
} }
); );
}, },
@ -366,7 +376,7 @@ export default function RuleChainsController(ruleChainService, userService, edge
} else if (vm.ruleChainsScope === 'edges') { } else if (vm.ruleChainsScope === 'edges') {
$state.go('home.ruleChains.edge.ruleChain', {ruleChainId: ruleChain.id.id}); $state.go('home.ruleChains.edge.ruleChain', {ruleChainId: ruleChain.id.id});
} else { } else {
$state.go('home.ruleChains.ruleChain', {ruleChainId: ruleChain.id.id}); $state.go('home.ruleChains.system.ruleChain', {ruleChainId: ruleChain.id.id});
} }
} }
@ -426,6 +436,24 @@ export default function RuleChainsController(ruleChainService, userService, edge
}); });
} }
function setDefaultRootEdgeRuleChain($event, ruleChain) {
$event.stopPropagation();
var confirm = $mdDialog.confirm()
.targetEvent($event)
.title($translate.instant('rulechain.set-default-root-edge-rulechain-title', {ruleChainName: ruleChain.name}))
.htmlContent($translate.instant('rulechain.set-default-root-edge-rulechain-text'))
.ariaLabel($translate.instant('rulechain.set-root-rulechain-text'))
.cancel($translate.instant('action.no'))
.ok($translate.instant('action.yes'));
$mdDialog.show(confirm).then(function () {
ruleChainService.setDefaultRootEdgeRuleChain(ruleChain.id.id).then(
() => {
vm.grid.refreshList();
}
);
});
}
function manageAssignedEdges($event, ruleChain) { function manageAssignedEdges($event, ruleChain) {
showManageAssignedEdgesDialog($event, [ruleChain.id.id], 'manage', ruleChain.assignedEdgesIds); showManageAssignedEdgesDialog($event, [ruleChain.id.id], 'manage', ruleChain.assignedEdgesIds);
} }
@ -488,7 +516,7 @@ export default function RuleChainsController(ruleChainService, userService, edge
$event.stopPropagation(); $event.stopPropagation();
} }
var pageSize = 10; var pageSize = 10;
ruleChainService.getRuleChains({limit: pageSize, textSearch: ''}).then( ruleChainService.getEdgesRuleChains({limit: pageSize, textSearch: ''}).then(
function success(_ruleChains) { function success(_ruleChains) {
var ruleChains = { var ruleChains = {
pageSize: pageSize, pageSize: pageSize,

4
ui/src/app/services/item-buffer.service.js

@ -204,7 +204,7 @@ function ItemBuffer($q, bufferStore, types, utils, dashboardUtils, ruleChainServ
return bufferStore.get(RULE_NODES); return bufferStore.get(RULE_NODES);
} }
function pasteRuleNodes(x, y) { function pasteRuleNodes(ruleChainType, x, y) {
var ruleNodesJson = bufferStore.get(RULE_NODES); var ruleNodesJson = bufferStore.get(RULE_NODES);
if (ruleNodesJson) { if (ruleNodesJson) {
var ruleNodes = angular.fromJson(ruleNodesJson); var ruleNodes = angular.fromJson(ruleNodesJson);
@ -212,7 +212,7 @@ function ItemBuffer($q, bufferStore, types, utils, dashboardUtils, ruleChainServ
var deltaY = y - ruleNodes.originY; var deltaY = y - ruleNodes.originY;
for (var i=0;i<ruleNodes.nodes.length;i++) { for (var i=0;i<ruleNodes.nodes.length;i++) {
var node = ruleNodes.nodes[i]; var node = ruleNodes.nodes[i];
var component = ruleChainService.getRuleNodeComponentByClazz(node.componentClazz); var component = ruleChainService.getRuleNodeComponentByClazz(node.componentClazz, ruleChainType);
if (component) { if (component) {
var icon = types.ruleNodeType[component.type].icon; var icon = types.ruleNodeType[component.type].icon;
var iconUrl = null; var iconUrl = null;

4
ui/src/app/services/menu.service.js

@ -231,12 +231,12 @@ function Menu(userService, $state, $rootScope) {
{ {
name: 'rulechain.system-rulechains', name: 'rulechain.system-rulechains',
icon: 'settings_ethernet', icon: 'settings_ethernet',
state: 'home.ruleChains' state: 'home.ruleChains.system'
}, },
{ {
name: 'rulechain.edge-rulechains', name: 'rulechain.edge-rulechains',
icon: 'router', icon: 'router',
state: 'home.edgesRuleChains' state: 'home.ruleChains.edge'
} }
] ]
}, },

Loading…
Cancel
Save