Browse Source

Merge pull request #725 from thingsboard/feature/rpc-refactoring

Server Side RPC, Telemetry, Default Rule Chain(s), Fixed Integration Tests
pull/748/head
Andrew Shvayka 9 years ago
committed by GitHub
parent
commit
de3dd0f7d3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      application/src/main/conf/thingsboard.conf
  2. 13
      application/src/main/data/json/demo/plugins/demo_device_messaging_rpc_plugin.json
  3. 28
      application/src/main/data/json/demo/plugins/demo_email_plugin.json
  4. 11
      application/src/main/data/json/demo/plugins/demo_time_rpc_plugin.json
  5. 46
      application/src/main/data/json/demo/rules/demo_alarm_rule.json
  6. 35
      application/src/main/data/json/demo/rules/demo_gettime_rpc_rule.json
  7. 38
      application/src/main/data/json/demo/rules/demo_messaging_rpc_rule.json
  8. 11
      application/src/main/data/json/system/plugins/system_rpc_plugin.json
  9. 9
      application/src/main/data/json/system/plugins/system_telemetry_plugin.json
  10. 29
      application/src/main/data/json/system/rules/system_telemetry_rule.json
  11. 102
      application/src/main/data/json/tenant/rule_chains/root_rule_chain.json
  12. 25
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  13. 71
      application/src/main/java/org/thingsboard/server/actors/app/AppActor.java
  14. 68
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java
  15. 326
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  16. 38
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorToRuleEngineMsg.java
  17. 36
      application/src/main/java/org/thingsboard/server/actors/device/PendingSessionMsgData.java
  18. 18
      application/src/main/java/org/thingsboard/server/actors/device/RuleEngineQueuePutAckMsg.java
  19. 4
      application/src/main/java/org/thingsboard/server/actors/device/ToDeviceRpcRequestMetadata.java
  20. 5
      application/src/main/java/org/thingsboard/server/actors/plugin/PluginActor.java
  21. 9
      application/src/main/java/org/thingsboard/server/actors/plugin/PluginActorMessageProcessor.java
  22. 21
      application/src/main/java/org/thingsboard/server/actors/plugin/PluginProcessingContext.java
  23. 13
      application/src/main/java/org/thingsboard/server/actors/plugin/SharedPluginProcessingContext.java
  24. 23
      application/src/main/java/org/thingsboard/server/actors/plugin/ValidationResult.java
  25. 23
      application/src/main/java/org/thingsboard/server/actors/rpc/BasicRpcSessionListener.java
  26. 4
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java
  27. 32
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
  28. 10
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java
  29. 4
      application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java
  30. 11
      application/src/main/java/org/thingsboard/server/actors/session/ASyncMsgProcessor.java
  31. 26
      application/src/main/java/org/thingsboard/server/actors/session/AbstractSessionActorMsgProcessor.java
  32. 4
      application/src/main/java/org/thingsboard/server/actors/session/SyncMsgProcessor.java
  33. 71
      application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
  34. 2
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  35. 149
      application/src/main/java/org/thingsboard/server/controller/RpcController.java
  36. 32
      application/src/main/java/org/thingsboard/server/controller/TenantController.java
  37. 4
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  38. 30
      application/src/main/java/org/thingsboard/server/service/cluster/rpc/ClusterGrpcService.java
  39. 9
      application/src/main/java/org/thingsboard/server/service/cluster/rpc/ClusterRpcService.java
  40. 6
      application/src/main/java/org/thingsboard/server/service/cluster/rpc/RpcMsgListener.java
  41. 147
      application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
  42. 182
      application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
  43. 4
      application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java
  44. 215
      application/src/main/java/org/thingsboard/server/service/rpc/DefaultDeviceRpcService.java
  45. 40
      application/src/main/java/org/thingsboard/server/service/rpc/DeviceRpcService.java
  46. 8
      application/src/main/java/org/thingsboard/server/service/rpc/LocalRequestMetaData.java
  47. 23
      application/src/main/java/org/thingsboard/server/service/rpc/ToDeviceRpcRequestMsg.java
  48. 54
      application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java
  49. 3
      application/src/main/proto/cluster.proto
  50. 16
      application/src/main/resources/thingsboard.yml
  51. 27
      application/src/test/java/org/thingsboard/server/actors/ActorsTestSuite.java
  52. 245
      application/src/test/java/org/thingsboard/server/actors/DefaultActorServiceTest.java
  53. 63
      application/src/test/java/org/thingsboard/server/actors/DummySessionID.java
  54. 17
      application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java
  55. 21
      application/src/test/java/org/thingsboard/server/controller/BaseComponentDescriptorControllerTest.java
  56. 232
      application/src/test/java/org/thingsboard/server/controller/BasePluginControllerTest.java
  57. 247
      application/src/test/java/org/thingsboard/server/controller/BaseRuleControllerTest.java
  58. 26
      application/src/test/java/org/thingsboard/server/controller/nosql/PluginControllerNoSqlTest.java
  59. 26
      application/src/test/java/org/thingsboard/server/controller/nosql/RuleControllerNoSqlTest.java
  60. 26
      application/src/test/java/org/thingsboard/server/controller/sql/PluginControllerSqlTest.java
  61. 26
      application/src/test/java/org/thingsboard/server/controller/sql/RuleControllerSqlTest.java
  62. 2
      application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java
  63. 3
      application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java
  64. 13
      application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java
  65. 5
      application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
  66. 1
      application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java
  67. 2
      common/data/src/main/java/org/thingsboard/server/common/data/rpc/RpcRequest.java
  68. 2
      common/data/src/main/java/org/thingsboard/server/common/data/rpc/ToDeviceRpcRequestBody.java
  69. 4
      common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java
  70. 44
      common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java
  71. 4
      common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java
  72. 8
      common/message/src/main/java/org/thingsboard/server/common/msg/cluster/ClusterEventMsg.java
  73. 6
      common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesSubscribeMsg.java
  74. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesUnsubscribeMsg.java
  75. 8
      common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesUpdateNotification.java
  76. 2
      common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesUpdateRequest.java
  77. 14
      common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicAttributesUpdateRequest.java
  78. 13
      common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicCommandAckResponse.java
  79. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicGetAttributesRequest.java
  80. 11
      common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicGetAttributesResponse.java
  81. 18
      common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicResponseMsg.java
  82. 13
      common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicStatusCodeResponse.java
  83. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicTelemetryUploadRequest.java
  84. 4
      common/message/src/main/java/org/thingsboard/server/common/msg/core/ResponseMsg.java
  85. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/RpcSubscribeMsg.java
  86. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/RpcUnsubscribeMsg.java
  87. 2
      common/message/src/main/java/org/thingsboard/server/common/msg/core/RuleEngineError.java
  88. 28
      common/message/src/main/java/org/thingsboard/server/common/msg/core/RuleEngineErrorMsg.java
  89. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/SessionCloseMsg.java
  90. 8
      common/message/src/main/java/org/thingsboard/server/common/msg/core/SessionCloseNotification.java
  91. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/SessionOpenMsg.java
  92. 8
      common/message/src/main/java/org/thingsboard/server/common/msg/core/ToDeviceRpcRequestMsg.java
  93. 7
      common/message/src/main/java/org/thingsboard/server/common/msg/core/ToDeviceRpcResponseMsg.java
  94. 6
      common/message/src/main/java/org/thingsboard/server/common/msg/core/ToServerRpcRequestMsg.java
  95. 8
      common/message/src/main/java/org/thingsboard/server/common/msg/core/ToServerRpcResponseMsg.java
  96. 20
      common/message/src/main/java/org/thingsboard/server/common/msg/device/BasicDeviceToDeviceActorMsg.java
  97. 5
      common/message/src/main/java/org/thingsboard/server/common/msg/device/DeviceToDeviceActorMsg.java
  98. 5
      common/message/src/main/java/org/thingsboard/server/common/msg/rpc/ToDeviceRpcRequest.java
  99. 2
      common/message/src/main/java/org/thingsboard/server/common/msg/session/FromDeviceMsg.java
  100. 6
      common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java

2
application/src/main/conf/thingsboard.conf

@ -14,7 +14,7 @@
# limitations under the License.
#
export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@"
export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@ -Dinstall.data_dir=@pkg.installFolder@"
export LOG_FILENAME=${pkg.name}.out
export LOADER_PATH=${pkg.installFolder}/conf,${pkg.installFolder}/extensions
export SQL_DATA_FOLDER=${pkg.installFolder}/data/sql

13
application/src/main/data/json/demo/plugins/demo_device_messaging_rpc_plugin.json

@ -1,13 +0,0 @@
{
"apiToken": "messaging",
"name": "Demo Device Messaging RPC Plugin",
"clazz": "org.thingsboard.server.extensions.core.plugin.messaging.DeviceMessagingPlugin",
"publicAccess": false,
"state": "ACTIVE",
"configuration": {
"maxDeviceCountPerCustomer": 1024,
"defaultTimeout": 20000,
"maxTimeout": 60000
},
"additionalInfo": null
}

28
application/src/main/data/json/demo/plugins/demo_email_plugin.json

@ -1,28 +0,0 @@
{
"apiToken": "mail",
"name": "Demo Email Plugin",
"clazz": "org.thingsboard.server.extensions.core.plugin.mail.MailPlugin",
"publicAccess": true,
"state": "ACTIVE",
"configuration": {
"host": "smtp.sendgrid.net",
"port": 2525,
"username": "apikey",
"password": "your_api_key",
"otherProperties": [
{
"key": "mail.smtp.auth",
"value": "true"
},
{
"key": "mail.smtp.timeout",
"value": "10000"
},
{
"key": "mail.smtp.starttls.enable",
"value": "true"
}
]
},
"additionalInfo": null
}

11
application/src/main/data/json/demo/plugins/demo_time_rpc_plugin.json

@ -1,11 +0,0 @@
{
"apiToken": "time",
"name": "Demo Time RPC Plugin",
"clazz": "org.thingsboard.server.extensions.core.plugin.time.TimePlugin",
"publicAccess": false,
"state": "ACTIVE",
"configuration": {
"timeFormat": "yyyy MM dd HH:mm:ss.SSS"
},
"additionalInfo": null
}

46
application/src/main/data/json/demo/rules/demo_alarm_rule.json

@ -1,46 +0,0 @@
{
"name": "Demo Alarm Rule",
"state": "ACTIVE",
"weight": 0,
"pluginToken": "mail",
"filters": [
{
"clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter",
"name": "MsgTypeFilter",
"configuration": {
"messageTypes": [
"POST_TELEMETRY",
"POST_ATTRIBUTES",
"GET_ATTRIBUTES"
]
}
},
{
"clazz": "org.thingsboard.server.extensions.core.filter.DeviceTelemetryFilter",
"name": "Temperature filter",
"configuration": {
"filter": "typeof temperature !== 'undefined' && temperature >= 100"
}
}
],
"processor": {
"clazz": "org.thingsboard.server.extensions.core.processor.AlarmDeduplicationProcessor",
"name": "AlarmDeduplicationProcessor",
"configuration": {
"alarmIdTemplate": "[$date.get('yyyy-MM-dd HH:mm')] Device $cs.get('serialNumber')($cs.get('model')) temperature is high!",
"alarmBodyTemplate": "[$date.get('yyyy-MM-dd HH:mm:ss')] Device $cs.get('serialNumber')($cs.get('model')) temperature is $temp.valueAsString!"
}
},
"action": {
"clazz": "org.thingsboard.server.extensions.core.action.mail.SendMailAction",
"name": "Send Mail Action",
"configuration": {
"sendFlag": "isNewAlarm",
"fromTemplate": "thingsboard@gmail.com",
"toTemplate": "thingsboard@gmail.com",
"subjectTemplate": "$alarmId",
"bodyTemplate": "$alarmBody"
}
},
"additionalInfo": null
}

35
application/src/main/data/json/demo/rules/demo_gettime_rpc_rule.json

@ -1,35 +0,0 @@
{
"name": "Demo getTime RPC Rule",
"state": "ACTIVE",
"weight": 0,
"pluginToken": "time",
"filters": [
{
"configuration": {
"messageTypes": [
"RPC_REQUEST"
]
},
"name": "RPC Request Filter",
"clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter"
},
{
"configuration": {
"methodNames": [
{
"name": "getTime"
}
]
},
"name": "getTime method filter",
"clazz": "org.thingsboard.server.extensions.core.filter.MethodNameFilter"
}
],
"processor": null,
"action": {
"configuration": {},
"clazz": "org.thingsboard.server.extensions.core.action.rpc.RpcPluginAction",
"name": "getTimeAction"
},
"additionalInfo": null
}

38
application/src/main/data/json/demo/rules/demo_messaging_rpc_rule.json

@ -1,38 +0,0 @@
{
"name": "Demo Messaging RPC Rule",
"state": "ACTIVE",
"weight": 0,
"pluginToken": "messaging",
"filters": [
{
"configuration": {
"messageTypes": [
"RPC_REQUEST"
]
},
"name": "RPC Request Filter",
"clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter"
},
{
"configuration": {
"methodNames": [
{
"name": "getDevices"
},
{
"name": "sendMsg"
}
]
},
"name": "Messaging methods filter",
"clazz": "org.thingsboard.server.extensions.core.filter.MethodNameFilter"
}
],
"processor": null,
"action": {
"configuration": {},
"clazz": "org.thingsboard.server.extensions.core.action.rpc.RpcPluginAction",
"name": "Messaging RPC Action"
},
"additionalInfo": null
}

11
application/src/main/data/json/system/plugins/system_rpc_plugin.json

@ -1,11 +0,0 @@
{
"apiToken": "rpc",
"name": "System RPC Plugin",
"clazz": "org.thingsboard.server.extensions.core.plugin.rpc.RpcPlugin",
"publicAccess": true,
"state": "ACTIVE",
"configuration": {
"defaultTimeout": 20000
},
"additionalInfo": null
}

9
application/src/main/data/json/system/plugins/system_telemetry_plugin.json

@ -1,9 +0,0 @@
{
"apiToken": "telemetry",
"name": "System Telemetry Plugin",
"clazz": "org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin",
"publicAccess": true,
"state": "ACTIVE",
"configuration": {},
"additionalInfo": null
}

29
application/src/main/data/json/system/rules/system_telemetry_rule.json

@ -1,29 +0,0 @@
{
"name": "System Telemetry Rule",
"state": "ACTIVE",
"weight": 0,
"pluginToken": "telemetry",
"filters": [
{
"clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter",
"name": "TelemetryFilter",
"configuration": {
"messageTypes": [
"POST_TELEMETRY",
"POST_ATTRIBUTES",
"GET_ATTRIBUTES"
]
}
}
],
"processor": null,
"action": {
"clazz": "org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction",
"name": "TelemetryMsgConverterAction",
"configuration": {
"timeUnit": "DAYS",
"ttlValue": 365
}
},
"additionalInfo": null
}

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

@ -0,0 +1,102 @@
{
"ruleChain": {
"additionalInfo": null,
"name": "Root Rule Chain",
"firstRuleNodeId": null,
"root": true,
"debugMode": false,
"configuration": null
},
"metadata": {
"firstNodeIndex": 2,
"nodes": [
{
"additionalInfo": {
"layoutX": 639,
"layoutY": 113
},
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode",
"name": "PostAttributes",
"debugMode": true,
"configuration": {
"messageTypes": [
"POST_ATTRIBUTES_REQUEST"
]
}
},
{
"additionalInfo": {
"layoutX": 638,
"layoutY": 206
},
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode",
"name": "PostTelemetry",
"debugMode": true,
"configuration": {
"messageTypes": [
"POST_TELEMETRY_REQUEST"
]
}
},
{
"additionalInfo": {
"layoutX": 297,
"layoutY": 148
},
"type": "org.thingsboard.rule.engine.action.TbLogNode",
"name": "Log",
"debugMode": false,
"configuration": {
"jsScript": "return 'incoming message = ' + msg;"
}
},
{
"additionalInfo": {
"layoutX": 905,
"layoutY": 203
},
"type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
"name": "SaveTS",
"debugMode": true,
"configuration": {
"defaultTTL": 0
}
},
{
"additionalInfo": {
"layoutX": 904,
"layoutY": 110
},
"type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode",
"name": "save client attributes",
"debugMode": true,
"configuration": {
"scope": "CLIENT_SCOPE"
}
}
],
"connections": [
{
"fromIndex": 0,
"toIndex": 4,
"type": "True"
},
{
"fromIndex": 1,
"toIndex": 3,
"type": "True"
},
{
"fromIndex": 2,
"toIndex": 0,
"type": "Success"
},
{
"fromIndex": 2,
"toIndex": 1,
"type": "Success"
}
],
"ruleChainConnections": null
}
}

25
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -61,6 +61,7 @@ import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.mail.MailExecutorService;
import org.thingsboard.server.service.rpc.DeviceRpcService;
import org.thingsboard.server.service.script.JsExecutorService;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
@ -161,6 +162,10 @@ public class ActorSystemContext {
@Getter
private TelemetrySubscriptionService tsSubService;
@Autowired
@Getter
private DeviceRpcService deviceRpcService;
@Autowired
@Getter
@Setter
@ -186,17 +191,13 @@ public class ActorSystemContext {
@Getter
private long syncSessionTimeout;
@Value("${actors.plugin.termination.delay}")
@Getter
private long pluginActorTerminationDelay;
@Value("${actors.plugin.processing.timeout}")
@Value("${actors.queue.enabled}")
@Getter
private long pluginProcessingTimeout;
private boolean queuePersistenceEnabled;
@Value("${actors.plugin.error_persist_frequency}")
@Value("${actors.queue.timeout}")
@Getter
private long pluginErrorPersistFrequency;
private long queuePersistenceTimeout;
@Value("${actors.rule.chain.error_persist_frequency}")
@Getter
@ -206,14 +207,6 @@ public class ActorSystemContext {
@Getter
private long ruleNodeErrorPersistFrequency;
@Value("${actors.rule.termination.delay}")
@Getter
private long ruleActorTerminationDelay;
@Value("${actors.rule.error_persist_frequency}")
@Getter
private long ruleErrorPersistFrequency;
@Value("${actors.statistics.enabled}")
@Getter
private boolean statisticsEnabled;

71
application/src/main/java/org/thingsboard/server/actors/app/AppActor.java

@ -29,13 +29,12 @@ import org.thingsboard.server.actors.shared.plugin.SystemPluginManager;
import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager;
import org.thingsboard.server.actors.tenant.TenantActor;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.model.ModelConstants;
@ -90,12 +89,22 @@ public class AppActor extends RuleChainManagerActor {
@Override
protected boolean process(TbActorMsg msg) {
switch (msg.getMsgType()) {
case CLUSTER_EVENT_MSG:
broadcast(msg);
break;
case COMPONENT_LIFE_CYCLE_MSG:
onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
break;
case SERVICE_TO_RULE_ENGINE_MSG:
onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
break;
case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG:
case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
onToDeviceActorMsg((TenantAwareMsg) msg);
break;
default:
return false;
}
@ -110,48 +119,12 @@ public class AppActor extends RuleChainManagerActor {
}
}
// @Override
// public void onReceive(Object msg) throws Exception {
// logger.debug("Received message: {}", msg);
// if (msg instanceof ToDeviceActorMsg) {
// processDeviceMsg((ToDeviceActorMsg) msg);
// } else if (msg instanceof ToPluginActorMsg) {
// onToPluginMsg((ToPluginActorMsg) msg);
// } else if (msg instanceof ToDeviceActorNotificationMsg) {
// onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg);
// } else if (msg instanceof Terminated) {
// processTermination((Terminated) msg);
// } else if (msg instanceof ClusterEventMsg) {
// broadcast(msg);
// } else if (msg instanceof ComponentLifecycleMsg) {
// onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
// } else if (msg instanceof PluginTerminationMsg) {
// onPluginTerminated((PluginTerminationMsg) msg);
// } else {
// logger.warning("Unknown message: {}!", msg);
// }
// }
private void onPluginTerminated(PluginTerminationMsg msg) {
pluginManager.remove(msg.getId());
}
private void broadcast(Object msg) {
pluginManager.broadcast(msg);
@Override
protected void broadcast(Object msg) {
super.broadcast(msg);
tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
}
private void onToPluginMsg(ToPluginActorMsg msg) {
ActorRef target;
if (SYSTEM_TENANT.equals(msg.getPluginTenantId())) {
target = pluginManager.getOrCreateActor(this.context(), msg.getPluginId());
} else {
target = getOrCreateTenantActor(msg.getPluginTenantId());
}
target.tell(msg, ActorRef.noSender());
}
private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
ActorRef target;
if (SYSTEM_TENANT.equals(msg.getTenantId())) {
@ -166,17 +139,17 @@ public class AppActor extends RuleChainManagerActor {
}
}
private void onToDeviceActorMsg(ToDeviceActorNotificationMsg msg) {
private void onToDeviceActorMsg(TenantAwareMsg msg) {
getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender());
}
private void processDeviceMsg(ToDeviceActorMsg toDeviceActorMsg) {
TenantId tenantId = toDeviceActorMsg.getTenantId();
private void processDeviceMsg(DeviceToDeviceActorMsg deviceToDeviceActorMsg) {
TenantId tenantId = deviceToDeviceActorMsg.getTenantId();
ActorRef tenantActor = getOrCreateTenantActor(tenantId);
if (toDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) {
// tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self());
if (deviceToDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) {
// tenantActor.tell(new RuleChainDeviceMsg(deviceToDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self());
} else {
tenantActor.tell(toDeviceActorMsg, context().self());
tenantActor.tell(deviceToDeviceActorMsg, context().self());
}
}

68
application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java

@ -24,59 +24,59 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg;
import org.thingsboard.server.common.msg.timeout.DeviceActorRpcTimeoutMsg;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg;
import org.thingsboard.server.common.msg.timeout.TimeoutMsg;
import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg;
public class DeviceActor extends ContextAwareActor {
private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);
private final TenantId tenantId;
private final DeviceId deviceId;
private final DeviceActorMessageProcessor processor;
private DeviceActor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) {
super(systemContext);
this.tenantId = tenantId;
this.deviceId = deviceId;
this.processor = new DeviceActorMessageProcessor(systemContext, logger, deviceId);
this.processor = new DeviceActorMessageProcessor(systemContext, logger, tenantId, deviceId);
}
@Override
protected boolean process(TbActorMsg msg) {
return false;
}
@Override
public void onReceive(Object msg) throws Exception {
// if (msg instanceof RuleChainDeviceMsg) {
// processor.process(context(), (RuleChainDeviceMsg) msg);
// } else if (msg instanceof RulesProcessedMsg) {
// processor.onRulesProcessedMsg(context(), (RulesProcessedMsg) msg);
if (msg instanceof ToDeviceActorMsg) {
processor.process(context(), (ToDeviceActorMsg) msg);
} else if (msg instanceof ToDeviceActorNotificationMsg) {
if (msg instanceof DeviceAttributesEventNotificationMsg) {
switch (msg.getMsgType()) {
case CLUSTER_EVENT_MSG:
processor.processClusterEventMsg((ClusterEventMsg) msg);
break;
case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG:
processor.process(context(), (DeviceToDeviceActorMsg) msg);
break;
case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg);
} else if (msg instanceof ToDeviceRpcRequestPluginMsg) {
processor.processRpcRequest(context(), (ToDeviceRpcRequestPluginMsg) msg);
} else if (msg instanceof DeviceCredentialsUpdateNotificationMsg){
break;
case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
processor.processCredentialsUpdate();
} else if (msg instanceof DeviceNameOrTypeUpdateMsg){
break;
case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg);
}
} else if (msg instanceof TimeoutMsg) {
processor.processTimeout(context(), (TimeoutMsg) msg);
} else if (msg instanceof ClusterEventMsg) {
processor.processClusterEventMsg((ClusterEventMsg) msg);
} else {
logger.debug("[{}][{}] Unknown msg type.", tenantId, deviceId, msg.getClass().getName());
break;
case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
processor.processRpcRequest(context(), (ToDeviceRpcRequestMsg) msg);
break;
case DEVICE_ACTOR_RPC_TIMEOUT_MSG:
processor.processRpcTimeout(context(), (DeviceActorRpcTimeoutMsg) msg);
break;
case DEVICE_ACTOR_QUEUE_TIMEOUT_MSG:
processor.processQueueTimeout(context(), (DeviceActorQueueTimeoutMsg) msg);
break;
case RULE_ENGINE_QUEUE_PUT_ACK_MSG:
processor.processQueueAck(context(), (RuleEngineQueuePutAckMsg) msg);
break;
default:
return false;
}
return true;
}
public static class ActorCreator extends ContextBasedCreator<DeviceActor> {

326
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -18,29 +18,75 @@ package org.thingsboard.server.actors.device;
import akka.actor.ActorContext;
import akka.actor.ActorRef;
import akka.event.LoggingAdapter;
import com.datastax.driver.core.utils.UUIDs;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKey;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.core.*;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.core.AttributesUpdateNotification;
import org.thingsboard.server.common.msg.core.AttributesUpdateRequest;
import org.thingsboard.server.common.msg.core.BasicCommandAckResponse;
import org.thingsboard.server.common.msg.core.BasicGetAttributesResponse;
import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse;
import org.thingsboard.server.common.msg.core.BasicToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.core.GetAttributesRequest;
import org.thingsboard.server.common.msg.core.RuleEngineError;
import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg;
import org.thingsboard.server.common.msg.core.SessionCloseMsg;
import org.thingsboard.server.common.msg.core.SessionCloseNotification;
import org.thingsboard.server.common.msg.core.SessionOpenMsg;
import org.thingsboard.server.common.msg.core.StatusCodeResponse;
import org.thingsboard.server.common.msg.core.TelemetryUploadRequest;
import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg;
import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg;
import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
import org.thingsboard.server.extensions.api.device.DeviceAttributes;
import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg;
import org.thingsboard.server.common.msg.timeout.DeviceActorRpcTimeoutMsg;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.extensions.api.plugins.msg.*;
import java.util.*;
import org.thingsboard.server.extensions.api.plugins.PluginCallback;
import org.thingsboard.server.extensions.api.plugins.PluginContext;
import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
@ -52,46 +98,43 @@ import java.util.stream.Collectors;
*/
public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
private final TenantId tenantId;
private final DeviceId deviceId;
private final Map<SessionId, SessionInfo> sessions;
private final Map<SessionId, SessionInfo> attributeSubscriptions;
private final Map<SessionId, SessionInfo> rpcSubscriptions;
private final Map<Integer, ToDeviceRpcRequestMetadata> rpcPendingMap;
private final Map<UUID, PendingSessionMsgData> pendingMsgs;
private final Gson gson = new Gson();
private int rpcSeq = 0;
private String deviceName;
private String deviceType;
private DeviceAttributes deviceAttributes;
private TbMsgMetaData defaultMetaData;
public DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, DeviceId deviceId) {
public DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, DeviceId deviceId) {
super(systemContext, logger);
this.tenantId = tenantId;
this.deviceId = deviceId;
this.sessions = new HashMap<>();
this.attributeSubscriptions = new HashMap<>();
this.rpcSubscriptions = new HashMap<>();
this.rpcPendingMap = new HashMap<>();
this.pendingMsgs = new HashMap<>();
initAttributes();
}
private void initAttributes() {
//TODO: add invalidation of deviceType cache.
Device device = systemContext.getDeviceService().findDeviceById(deviceId);
this.deviceName = device.getName();
this.deviceType = device.getType();
this.deviceAttributes = new DeviceAttributes(fetchAttributes(DataConstants.CLIENT_SCOPE),
fetchAttributes(DataConstants.SERVER_SCOPE), fetchAttributes(DataConstants.SHARED_SCOPE));
}
private void refreshAttributes(DeviceAttributesEventNotificationMsg msg) {
if (msg.isDeleted()) {
msg.getDeletedKeys().forEach(key -> deviceAttributes.remove(key));
} else {
deviceAttributes.update(msg.getScope(), msg.getValues());
}
this.defaultMetaData = new TbMsgMetaData();
this.defaultMetaData.putValue("deviceName", deviceName);
this.defaultMetaData.putValue("deviceType", deviceType);
}
void processRpcRequest(ActorContext context, ToDeviceRpcRequestPluginMsg msg) {
void processRpcRequest(ActorContext context, org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg msg) {
ToDeviceRpcRequest request = msg.getMsg();
ToDeviceRpcRequestBody body = request.getBody();
ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg(
@ -118,9 +161,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
syncSessionSet.forEach(rpcSubscriptions::remove);
if (request.isOneway() && sent) {
ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(msg, (String) null);
context.parent().tell(responsePluginMsg, ActorRef.noSender());
logger.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId());
systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null));
} else {
registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout);
}
@ -132,18 +174,36 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
}
private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestPluginMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) {
private void registerPendingRpcRequest(ActorContext context, org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) {
rpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent));
TimeoutIntMsg timeoutMsg = new TimeoutIntMsg(rpcRequest.getRequestId(), timeout);
DeviceActorRpcTimeoutMsg timeoutMsg = new DeviceActorRpcTimeoutMsg(rpcRequest.getRequestId(), timeout);
scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout());
}
public void processTimeout(ActorContext context, TimeoutMsg msg) {
void processRpcTimeout(ActorContext context, DeviceActorRpcTimeoutMsg msg) {
ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(msg.getId());
if (requestMd != null) {
logger.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId());
ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(requestMd.getMsg(), requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION);
context.parent().tell(responsePluginMsg, ActorRef.noSender());
systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION));
}
}
void processQueueTimeout(ActorContext context, DeviceActorQueueTimeoutMsg msg) {
PendingSessionMsgData data = pendingMsgs.remove(msg.getId());
if (data != null) {
logger.debug("[{}] Queue put [{}] timeout detected!", deviceId, msg.getId());
ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(data.getSessionMsgType(), RuleEngineError.QUEUE_PUT_TIMEOUT);
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress());
}
}
void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) {
PendingSessionMsgData data = pendingMsgs.remove(msg.getId());
if (data != null) {
logger.debug("[{}] Queue put [{}] ack detected!", deviceId, msg.getId());
ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId());
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress());
}
}
@ -173,8 +233,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
ToDeviceRpcRequestBody body = request.getBody();
if (request.isOneway()) {
sentOneWayIds.add(entry.getKey());
ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(entry.getValue().getMsg(), (String) null);
context.parent().tell(responsePluginMsg, ActorRef.noSender());
systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(request.getId(), null, null));
}
ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg(
entry.getKey(),
@ -186,14 +245,120 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
};
}
void process(ActorContext context, ToDeviceActorMsg msg) {
void process(ActorContext context, DeviceToDeviceActorMsg msg) {
processSubscriptionCommands(context, msg);
processRpcResponses(context, msg);
processSessionStateMsgs(msg);
SessionMsgType sessionMsgType = msg.getPayload().getMsgType();
if (sessionMsgType.requiresRulesProcessing()) {
switch (sessionMsgType) {
case GET_ATTRIBUTES_REQUEST:
handleGetAttributesRequest(msg);
break;
case POST_ATTRIBUTES_REQUEST:
handlePostAttributesRequest(context, msg);
break;
case POST_TELEMETRY_REQUEST:
handlePostTelemetryRequest(context, msg);
break;
case TO_SERVER_RPC_REQUEST:
break;
//TODO: push to queue and start processing!
}
}
}
private void handleGetAttributesRequest(DeviceToDeviceActorMsg src) {
GetAttributesRequest request = (GetAttributesRequest) src.getPayload();
ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, request.getClientAttributeNames());
ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, request.getClientAttributeNames());
Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() {
@Override
public void onSuccess(@Nullable List<List<AttributeKvEntry>> result) {
BasicGetAttributesResponse response = BasicGetAttributesResponse.onSuccess(request.getMsgType(),
request.getRequestId(), BasicAttributeKVMsg.from(result.get(0), result.get(1)));
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(response, src.getSessionId()), src.getServerAddress());
}
@Override
public void onFailure(Throwable t) {
if (t instanceof Exception) {
ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onError(SessionMsgType.GET_ATTRIBUTES_REQUEST, request.getRequestId(), (Exception) t);
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, src.getSessionId()), src.getServerAddress());
} else {
logger.error("[{}] Failed to process attributes request", deviceId, t);
}
}
});
}
private ListenableFuture<List<AttributeKvEntry>> getAttributeKvEntries(DeviceId deviceId, String scope, Optional<Set<String>> names) {
if (names.isPresent()) {
if (!names.get().isEmpty()) {
return systemContext.getAttributesService().find(deviceId, scope, names.get());
} else {
return systemContext.getAttributesService().findAll(deviceId, scope);
}
} else {
return Futures.immediateFuture(Collections.emptyList());
}
}
private void handlePostAttributesRequest(ActorContext context, DeviceToDeviceActorMsg src) {
AttributesUpdateRequest request = (AttributesUpdateRequest) src.getPayload();
JsonObject json = new JsonObject();
for (AttributeKvEntry kv : request.getAttributes()) {
kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v));
kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v));
kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v));
kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v));
}
TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json));
pushToRuleEngineWithTimeout(context, tbMsg, src, request);
}
private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) {
TelemetryUploadRequest request = (TelemetryUploadRequest) src.getPayload();
Map<Long, List<KvEntry>> tsData = request.getData();
JsonArray json = new JsonArray();
for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) {
JsonObject ts = new JsonObject();
ts.addProperty("ts", entry.getKey());
JsonObject values = new JsonObject();
for (KvEntry kv : entry.getValue()) {
kv.getBooleanValue().ifPresent(v -> values.addProperty(kv.getKey(), v));
kv.getLongValue().ifPresent(v -> values.addProperty(kv.getKey(), v));
kv.getDoubleValue().ifPresent(v -> values.addProperty(kv.getKey(), v));
kv.getStrValue().ifPresent(v -> values.addProperty(kv.getKey(), v));
}
ts.add("values", values);
json.add(ts);
}
TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json));
pushToRuleEngineWithTimeout(context, tbMsg, src, request);
}
private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg) {
SessionMsgType sessionMsgType = fromDeviceRequestMsg.getMsgType();
int requestId = fromDeviceRequestMsg.getRequestId();
if (systemContext.isQueuePersistenceEnabled()) {
pendingMsgs.put(tbMsg.getId(), new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), sessionMsgType, requestId));
scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout());
} else {
ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), src.getSessionId());
sendMsgToSessionActor(response, src.getServerAddress());
}
context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self());
}
void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) {
refreshAttributes(msg);
if (attributeSubscriptions.size() > 0) {
ToDeviceMsg notification = null;
if (msg.isDeleted()) {
@ -223,50 +388,29 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
}
}
// void process(ActorContext context, RuleChainDeviceMsg srcMsg) {
// ChainProcessingMetaData md = new ChainProcessingMetaData(srcMsg.getRuleChain(),
// srcMsg.getToDeviceActorMsg(), new DeviceMetaData(deviceId, deviceName, deviceType, deviceAttributes), context.self());
// ChainProcessingContext ctx = new ChainProcessingContext(md);
// if (ctx.getChainLength() > 0) {
// RuleProcessingMsg msg = new RuleProcessingMsg(ctx);
// ActorRef ruleActorRef = ctx.getCurrentActor();
// ruleActorRef.tell(msg, ActorRef.noSender());
// } else {
// context.self().tell(new RulesProcessedMsg(ctx), context.self());
// }
// }
void processRpcResponses(ActorContext context, ToDeviceActorMsg msg) {
private void processRpcResponses(ActorContext context, DeviceToDeviceActorMsg msg) {
SessionId sessionId = msg.getSessionId();
FromDeviceMsg inMsg = msg.getPayload();
if (inMsg.getMsgType() == MsgType.TO_DEVICE_RPC_RESPONSE) {
if (inMsg.getMsgType() == SessionMsgType.TO_DEVICE_RPC_RESPONSE) {
logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId);
ToDeviceRpcResponseMsg responseMsg = (ToDeviceRpcResponseMsg) inMsg;
ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(responseMsg.getRequestId());
boolean success = requestMd != null;
if (success) {
ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(requestMd.getMsg(), responseMsg.getData());
Optional<ServerAddress> pluginServerAddress = requestMd.getMsg().getServerAddress();
if (pluginServerAddress.isPresent()) {
systemContext.getRpcService().tell(pluginServerAddress.get(), responsePluginMsg);
logger.debug("[{}] Rpc command response sent to remote plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId());
} else {
context.parent().tell(responsePluginMsg, ActorRef.noSender());
logger.debug("[{}] Rpc command response sent to local plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId());
}
systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), responseMsg.getData(), null));
} else {
logger.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId());
}
if (msg.getSessionType() == SessionType.SYNC) {
BasicCommandAckResponse response = success
? BasicCommandAckResponse.onSuccess(MsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId())
: BasicCommandAckResponse.onError(MsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId(), new TimeoutException());
? BasicCommandAckResponse.onSuccess(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId())
: BasicCommandAckResponse.onError(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId(), new TimeoutException());
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(response, msg.getSessionId()), msg.getServerAddress());
}
}
}
public void processClusterEventMsg(ClusterEventMsg msg) {
void processClusterEventMsg(ClusterEventMsg msg) {
if (!msg.isAdded()) {
logger.debug("[{}] Clearing attributes/rpc subscription for server [{}]", deviceId, msg.getServerAddress());
Predicate<Map.Entry<SessionId, SessionInfo>> filter = e -> e.getValue().getServer()
@ -276,59 +420,27 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
}
}
private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, String data) {
return toPluginRpcResponseMsg(requestMsg, data, null);
}
private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, RpcError error) {
return toPluginRpcResponseMsg(requestMsg, null, error);
}
private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, String data, RpcError error) {
return new ToPluginRpcResponseDeviceMsg(
requestMsg.getPluginId(),
requestMsg.getPluginTenantId(),
new FromDeviceRpcResponse(requestMsg.getMsg().getId(),
data,
error
)
);
}
// void onRulesProcessedMsg(ActorContext context, RulesProcessedMsg msg) {
// ChainProcessingContext ctx = msg.getCtx();
// ToDeviceActorMsg inMsg = ctx.getInMsg();
// SessionId sid = inMsg.getSessionId();
// ToDeviceSessionActorMsg response;
// if (ctx.getResponse() != null) {
// response = new BasicToDeviceSessionActorMsg(ctx.getResponse(), sid);
// } else {
// response = new BasicToDeviceSessionActorMsg(ctx.getError(), sid);
// }
// sendMsgToSessionActor(response, inMsg.getServerAddress());
// }
private void processSubscriptionCommands(ActorContext context, ToDeviceActorMsg msg) {
private void processSubscriptionCommands(ActorContext context, DeviceToDeviceActorMsg msg) {
SessionId sessionId = msg.getSessionId();
SessionType sessionType = msg.getSessionType();
FromDeviceMsg inMsg = msg.getPayload();
if (inMsg.getMsgType() == MsgType.SUBSCRIBE_ATTRIBUTES_REQUEST) {
if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST) {
logger.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId);
attributeSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress()));
} else if (inMsg.getMsgType() == MsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST) {
} else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST) {
logger.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId);
attributeSubscriptions.remove(sessionId);
} else if (inMsg.getMsgType() == MsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST) {
} else if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST) {
logger.debug("[{}] Registering rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType);
rpcSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress()));
sendPendingRequests(context, sessionId, sessionType, msg.getServerAddress());
} else if (inMsg.getMsgType() == MsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST) {
} else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST) {
logger.debug("[{}] Canceling rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType);
rpcSubscriptions.remove(sessionId);
}
}
private void processSessionStateMsgs(ToDeviceActorMsg msg) {
private void processSessionStateMsgs(DeviceToDeviceActorMsg msg) {
SessionId sessionId = msg.getSessionId();
FromDeviceMsg inMsg = msg.getPayload();
if (inMsg instanceof SessionOpenMsg) {
@ -352,17 +464,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
}
}
private List<AttributeKvEntry> fetchAttributes(String scope) {
try {
//TODO: replace this with async operation. Happens only during actor creation, but is still criticla for performance,
return systemContext.getAttributesService().findAll(this.deviceId, scope).get();
} catch (InterruptedException | ExecutionException e) {
logger.warning("[{}] Failed to fetch attributes for scope: {}", deviceId, scope);
throw new RuntimeException(e);
}
}
public void processCredentialsUpdate() {
void processCredentialsUpdate() {
sessions.forEach((k, v) -> {
sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(new SessionCloseNotification(), k), v.getServer());
});
@ -370,8 +472,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
rpcSubscriptions.clear();
}
public void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) {
void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) {
this.deviceName = msg.getDeviceName();
this.deviceType = msg.getDeviceType();
this.defaultMetaData = new TbMsgMetaData();
this.defaultMetaData.putValue("deviceName", deviceName);
this.defaultMetaData.putValue("deviceType", deviceType);
}
}

38
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorToRuleEngineMsg.java

@ -0,0 +1,38 @@
/**
* Copyright © 2016-2018 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.actors.device;
import akka.actor.ActorRef;
import lombok.Data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.TbMsg;
/**
* Created by ashvayka on 15.03.18.
*/
@Data
public final class DeviceActorToRuleEngineMsg implements TbActorMsg {
private final ActorRef callbackRef;
private final TbMsg tbMsg;
@Override
public MsgType getMsgType() {
return MsgType.DEVICE_ACTOR_TO_RULE_ENGINE_MSG;
}
}

36
application/src/main/java/org/thingsboard/server/actors/device/PendingSessionMsgData.java

@ -0,0 +1,36 @@
/**
* Copyright © 2016-2018 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.actors.device;
import lombok.Data;
import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import java.util.Optional;
/**
* Created by ashvayka on 17.04.18.
*/
@Data
public final class PendingSessionMsgData {
private final SessionId sessionId;
private final Optional<ServerAddress> serverAddress;
private final SessionMsgType sessionMsgType;
private final int requestId;
}

18
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/rpc/RpcPluginConfiguration.java → application/src/main/java/org/thingsboard/server/actors/device/RuleEngineQueuePutAckMsg.java

@ -13,14 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.extensions.core.plugin.rpc;
package org.thingsboard.server.actors.device;
import lombok.Data;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;
import java.util.UUID;
/**
* @author Andrew Shvayka
* Created by ashvayka on 15.03.18.
*/
@Data
public class RpcPluginConfiguration {
private long defaultTimeout;
public final class RuleEngineQueuePutAckMsg implements TbActorMsg {
private final UUID id;
@Override
public MsgType getMsgType() {
return MsgType.RULE_ENGINE_QUEUE_PUT_ACK_MSG;
}
}

4
application/src/main/java/org/thingsboard/server/actors/device/ToDeviceRpcRequestMetadata.java

@ -16,13 +16,13 @@
package org.thingsboard.server.actors.device;
import lombok.Data;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg;
import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg;
/**
* @author Andrew Shvayka
*/
@Data
public class ToDeviceRpcRequestMetadata {
private final ToDeviceRpcRequestPluginMsg msg;
private final ToDeviceRpcRequestMsg msg;
private final boolean sent;
}

5
application/src/main/java/org/thingsboard/server/actors/plugin/PluginActor.java

@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
import org.thingsboard.server.common.msg.timeout.TimeoutMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg;
import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg;
import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
@ -153,6 +153,7 @@ public class PluginActor extends ComponentActor<PluginId, PluginActorMessageProc
@Override
protected long getErrorPersistFrequency() {
return systemContext.getPluginErrorPersistFrequency();
return 0;
// return systemContext.getPluginErrorPersistFrequency();
}
}

9
application/src/main/java/org/thingsboard/server/actors/plugin/PluginActorMessageProcessor.java

@ -30,13 +30,14 @@ import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse;
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.extensions.api.plugins.Plugin;
import org.thingsboard.server.extensions.api.plugins.PluginInitializationException;
import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg;
import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg;
import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
import org.thingsboard.server.common.msg.timeout.TimeoutMsg;
import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg;
import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg;
@ -108,7 +109,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId>
} catch (Exception ex) {
logger.debug("[{}] Failed to process RuleToPlugin msg: [{}] [{}]", tenantId, msg.getMsg(), ex);
RuleToPluginMsg ruleMsg = msg.getMsg();
MsgType responceMsgType = MsgType.RULE_ENGINE_ERROR;
SessionMsgType responceMsgType = SessionMsgType.RULE_ENGINE_ERROR;
Integer requestId = 0;
if (ruleMsg.getPayload() instanceof FromDeviceRequestMsg) {
requestId = ((FromDeviceRequestMsg) ruleMsg.getPayload()).getRequestId();
@ -216,7 +217,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId>
@Override
public void onStop(ActorContext context) {
onStop();
scheduleMsgWithDelay(context, new PluginTerminationMsg(entityId), systemContext.getPluginActorTerminationDelay());
// scheduleMsgWithDelay(context, new PluginTerminationMsg(entityId), systemContext.getPluginActorTerminationDelay());
}
private void onStop() {

21
application/src/main/java/org/thingsboard/server/actors/plugin/PluginProcessingContext.java

@ -36,9 +36,12 @@ import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleMetaData;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.common.msg.timeout.TimeoutMsg;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext;
import org.thingsboard.server.extensions.api.plugins.PluginCallback;
@ -348,7 +351,7 @@ public final class PluginProcessingContext implements PluginContext {
throw new IllegalStateException("Not Implemented!");
}
} else {
callback.onSuccess(this, ValidationResult.ok());
callback.onSuccess(this, ValidationResult.ok(null));
}
}
@ -366,7 +369,7 @@ public final class PluginProcessingContext implements PluginContext {
} else if (ctx.isCustomerUser() && !device.getCustomerId().equals(ctx.getCustomerId())) {
return ValidationResult.accessDenied("Device doesn't belong to the current Customer!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(null);
}
}
}));
@ -387,7 +390,7 @@ public final class PluginProcessingContext implements PluginContext {
} else if (ctx.isCustomerUser() && !asset.getCustomerId().equals(ctx.getCustomerId())) {
return ValidationResult.accessDenied("Asset doesn't belong to the current Customer!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(null);
}
}
}));
@ -408,7 +411,7 @@ public final class PluginProcessingContext implements PluginContext {
} else if (ctx.isSystemAdmin() && !rule.getTenantId().isNullUid()) {
return ValidationResult.accessDenied("Rule is not in system scope!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(null);
}
}
}));
@ -429,7 +432,7 @@ public final class PluginProcessingContext implements PluginContext {
} else if (ctx.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) {
return ValidationResult.accessDenied("Rule chain is not in system scope!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(null);
}
}
}));
@ -451,7 +454,7 @@ public final class PluginProcessingContext implements PluginContext {
} else if (ctx.isSystemAdmin() && !plugin.getTenantId().isNullUid()) {
return ValidationResult.accessDenied("Plugin is not in system scope!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(null);
}
}
}));
@ -472,7 +475,7 @@ public final class PluginProcessingContext implements PluginContext {
} else if (ctx.isCustomerUser() && !customer.getId().equals(ctx.getCustomerId())) {
return ValidationResult.accessDenied("Customer doesn't relate to the currently authorized customer user!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(null);
}
}
}));
@ -483,7 +486,7 @@ public final class PluginProcessingContext implements PluginContext {
if (ctx.isCustomerUser()) {
callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else if (ctx.isSystemAdmin()) {
callback.onSuccess(this, ValidationResult.ok());
callback.onSuccess(this, ValidationResult.ok(null));
} else {
ListenableFuture<Tenant> tenantFuture = pluginCtx.tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
Futures.addCallback(tenantFuture, getCallback(callback, tenant -> {
@ -492,7 +495,7 @@ public final class PluginProcessingContext implements PluginContext {
} else if (!tenant.getId().equals(ctx.getTenantId())) {
return ValidationResult.accessDenied("Tenant doesn't relate to the currently authorized user!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(null);
}
}));
}

13
application/src/main/java/org/thingsboard/server/actors/plugin/SharedPluginProcessingContext.java

@ -18,13 +18,13 @@ package org.thingsboard.server.actors.plugin;
import akka.actor.ActorRef;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.common.msg.timeout.TimeoutMsg;
import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint;
import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.audit.AuditLogService;
@ -37,9 +37,6 @@ import org.thingsboard.server.dao.rule.RuleService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
import scala.concurrent.duration.Duration;
@ -108,8 +105,8 @@ public final class SharedPluginProcessingContext {
public void sendRpcRequest(ToDeviceRpcRequest msg) {
log.trace("[{}] Forwarding msg {} to device actor!", pluginId, msg);
ToDeviceRpcRequestPluginMsg rpcMsg = new ToDeviceRpcRequestPluginMsg(pluginId, tenantId, msg);
forward(msg.getDeviceId(), rpcMsg, rpcService::tell);
// ToDeviceRpcRequestPluginMsg rpcMsg = new ToDeviceRpcRequestPluginMsg(pluginId, tenantId, msg);
// forward(msg.getDeviceId(), rpcMsg, rpcService::tell);
}
private <T> void forward(DeviceId deviceId, T msg, BiConsumer<ServerAddress, T> rpcFunction) {

23
application/src/main/java/org/thingsboard/server/actors/plugin/ValidationResult.java

@ -20,29 +20,30 @@ import lombok.Data;
@Data
@AllArgsConstructor
public class ValidationResult {
public class ValidationResult<V> {
private final ValidationResultCode resultCode;
private final String message;
private final V v;
public static ValidationResult ok() {
return new ValidationResult(ValidationResultCode.OK, "Ok");
public static <V> ValidationResult<V> ok(V v) {
return new ValidationResult<>(ValidationResultCode.OK, "Ok", v);
}
public static ValidationResult accessDenied(String message) {
return new ValidationResult(ValidationResultCode.ACCESS_DENIED, message);
public static <V> ValidationResult<V> accessDenied(String message) {
return new ValidationResult<>(ValidationResultCode.ACCESS_DENIED, message, null);
}
public static ValidationResult entityNotFound(String message) {
return new ValidationResult(ValidationResultCode.ENTITY_NOT_FOUND, message);
public static <V> ValidationResult<V> entityNotFound(String message) {
return new ValidationResult<>(ValidationResultCode.ENTITY_NOT_FOUND, message, null);
}
public static ValidationResult unauthorized(String message) {
return new ValidationResult(ValidationResultCode.UNAUTHORIZED, message);
public static <V> ValidationResult<V> unauthorized(String message) {
return new ValidationResult<>(ValidationResultCode.UNAUTHORIZED, message, null);
}
public static ValidationResult internalError(String message) {
return new ValidationResult(ValidationResultCode.INTERNAL_ERROR, message);
public static <V> ValidationResult<V> internalError(String message) {
return new ValidationResult<>(ValidationResultCode.INTERNAL_ERROR, message, null);
}
}

23
application/src/main/java/org/thingsboard/server/actors/rpc/BasicRpcSessionListener.java

@ -24,10 +24,12 @@ import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.*;
import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
@ -35,6 +37,7 @@ import org.thingsboard.server.extensions.api.plugins.rpc.RpcMsg;
import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
import org.thingsboard.server.service.cluster.rpc.GrpcSession;
import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener;
import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg;
import java.io.Serializable;
import java.util.UUID;
@ -83,7 +86,7 @@ public class BasicRpcSessionListener implements GrpcSessionListener {
@Override
public void onToDeviceActorRpcMsg(GrpcSession session, ClusterAPIProtos.ToDeviceActorRpcMessage msg) {
log.trace("{} session [{}] received device actor msg {}", getType(session), session.getRemoteServer(), msg);
service.onMsg((ToDeviceActorMsg) deserialize(msg.getData().toByteArray()));
service.onMsg((DeviceToDeviceActorMsg) deserialize(msg.getData().toByteArray()));
}
@Override
@ -139,28 +142,20 @@ public class BasicRpcSessionListener implements GrpcSessionListener {
return new UUID(uid.getPluginUuidMsb(), uid.getPluginUuidLsb());
}
private static ToDeviceRpcRequestPluginMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) {
ClusterAPIProtos.PluginAddress address = msg.getAddress();
TenantId pluginTenantId = new TenantId(toUUID(address.getTenantId()));
PluginId pluginId = new PluginId(toUUID(address.getPluginId()));
private static ToDeviceRpcRequestMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) {
TenantId deviceTenantId = new TenantId(toUUID(msg.getDeviceTenantId()));
DeviceId deviceId = new DeviceId(toUUID(msg.getDeviceId()));
ToDeviceRpcRequestBody requestBody = new ToDeviceRpcRequestBody(msg.getMethod(), msg.getParams());
ToDeviceRpcRequest request = new ToDeviceRpcRequest(toUUID(msg.getMsgId()), null, deviceTenantId, deviceId, msg.getOneway(), msg.getExpTime(), requestBody);
ToDeviceRpcRequest request = new ToDeviceRpcRequest(toUUID(msg.getMsgId()), deviceTenantId, deviceId, msg.getOneway(), msg.getExpTime(), requestBody);
return new ToDeviceRpcRequestPluginMsg(serverAddress, pluginId, pluginTenantId, request);
return new ToDeviceRpcRequestMsg(serverAddress, request);
}
private static ToPluginRpcResponseDeviceMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToPluginRpcResponseRpcMessage msg) {
ClusterAPIProtos.PluginAddress address = msg.getAddress();
TenantId pluginTenantId = new TenantId(toUUID(address.getTenantId()));
PluginId pluginId = new PluginId(toUUID(address.getPluginId()));
RpcError error = !StringUtils.isEmpty(msg.getError()) ? RpcError.valueOf(msg.getError()) : null;
FromDeviceRpcResponse response = new FromDeviceRpcResponse(toUUID(msg.getMsgId()), msg.getResponse(), error);
return new ToPluginRpcResponseDeviceMsg(pluginId, pluginTenantId, response);
return new ToPluginRpcResponseDeviceMsg(null, null, response);
}
@SuppressWarnings("unchecked")

4
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java

@ -18,6 +18,7 @@ package org.thingsboard.server.actors.ruleChain;
import akka.actor.OneForOneStrategy;
import akka.actor.SupervisorStrategy;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;
import org.thingsboard.server.actors.service.ComponentActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.common.data.id.RuleChainId;
@ -44,6 +45,9 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
case SERVICE_TO_RULE_ENGINE_MSG:
processor.onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
break;
case DEVICE_ACTOR_TO_RULE_ENGINE_MSG:
processor.onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg);
break;
case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG:
processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg);
break;

32
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java

@ -20,6 +20,8 @@ import akka.actor.ActorRef;
import akka.actor.Props;
import akka.event.LoggingAdapter;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;
import org.thingsboard.server.actors.device.RuleEngineQueuePutAckMsg;
import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
import org.thingsboard.server.common.data.EntityType;
@ -58,6 +60,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
private RuleNodeId firstId;
private RuleNodeCtx firstNode;
private boolean started;
RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext
, LoggingAdapter logger, ActorRef parent, ActorRef self) {
@ -71,14 +74,19 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
@Override
public void start(ActorContext context) throws Exception {
RuleChain ruleChain = service.findRuleChainById(entityId);
List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId);
// Creating and starting the actors;
for (RuleNode ruleNode : ruleNodeList) {
ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
if (!started) {
RuleChain ruleChain = service.findRuleChainById(entityId);
List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId);
// Creating and starting the actors;
for (RuleNode ruleNode : ruleNodeList) {
ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
}
initRoutes(ruleChain, ruleNodeList);
started = true;
} else {
onUpdate(context);
}
initRoutes(ruleChain, ruleNodeList);
}
@Override
@ -113,6 +121,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
nodeActors.clear();
nodeRoutes.clear();
context.stop(self);
started = false;
}
@Override
@ -157,6 +166,14 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
pushMsgToNode(firstNode, tbMsg);
}
public void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) {
checkActive();
TbMsg tbMsg = envelope.getTbMsg();
//TODO: push to queue and act on ack in async way
pushMsgToNode(firstNode, tbMsg);
envelope.getCallbackRef().tell(new RuleEngineQueuePutAckMsg(tbMsg.getId()), self);
}
void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) {
checkActive();
RuleNodeId originator = envelope.getOriginator();
@ -191,5 +208,4 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self);
}
}
}

10
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java

@ -31,31 +31,29 @@ import org.thingsboard.server.dao.rule.RuleChainService;
public abstract class RuleChainManagerActor extends ContextAwareActor {
protected final RuleChainManager ruleChainManager;
protected final PluginManager pluginManager;
protected final RuleChainService ruleChainService;
public RuleChainManagerActor(ActorSystemContext systemContext, RuleChainManager ruleChainManager, PluginManager pluginManager) {
super(systemContext);
this.ruleChainManager = ruleChainManager;
this.pluginManager = pluginManager;
this.ruleChainService = systemContext.getRuleChainService();
}
protected void initRuleChains() {
pluginManager.init(this.context());
ruleChainManager.init(this.context());
}
protected ActorRef getEntityActorRef(EntityId entityId) {
ActorRef target = null;
switch (entityId.getEntityType()) {
case PLUGIN:
target = pluginManager.getOrCreateActor(this.context(), (PluginId) entityId);
break;
case RULE_CHAIN:
target = ruleChainManager.getOrCreateActor(this.context(), (RuleChainId) entityId);
break;
}
return target;
}
protected void broadcast(Object msg) {
ruleChainManager.broadcast(msg);
}
}

4
application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java

@ -39,7 +39,7 @@ import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
@ -156,7 +156,7 @@ public class DefaultActorService implements ActorService {
}
@Override
public void onMsg(ToDeviceActorMsg msg) {
public void onMsg(DeviceToDeviceActorMsg msg) {
log.trace("Processing device rpc msg: {}", msg);
appActor.tell(msg, ActorRef.noSender());
}

11
application/src/main/java/org/thingsboard/server/actors/session/ASyncMsgProcessor.java

@ -22,12 +22,11 @@ import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.core.*;
import org.thingsboard.server.common.msg.core.SessionCloseMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.session.*;
import akka.actor.ActorContext;
import akka.event.LoggingAdapter;
import org.thingsboard.server.common.msg.session.ctrl.*;
import org.thingsboard.server.common.msg.session.ex.SessionException;
import java.util.HashMap;
@ -37,7 +36,7 @@ import java.util.Optional;
class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor {
private boolean firstMsg = true;
private Map<Integer, ToDeviceActorMsg> pendingMap = new HashMap<>();
private Map<Integer, DeviceToDeviceActorMsg> pendingMap = new HashMap<>();
private Optional<ServerAddress> currentTargetServer;
private boolean subscribedToAttributeUpdates;
private boolean subscribedToRpcCommands;
@ -53,7 +52,7 @@ class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor {
toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m));
firstMsg = false;
}
ToDeviceActorMsg pendingMsg = toDeviceMsg(msg);
DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg);
FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload();
switch (fromDeviceMsg.getMsgType()) {
case POST_TELEMETRY_REQUEST:
@ -86,8 +85,8 @@ class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor {
@Override
public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) {
try {
if (msg.getMsgType() != MsgType.SESSION_CLOSE) {
switch (msg.getMsgType()) {
if (msg.getSessionMsgType() != SessionMsgType.SESSION_CLOSE) {
switch (msg.getSessionMsgType()) {
case STATUS_CODE_RESPONSE:
case GET_ATTRIBUTES_RESPONSE:
ResponseMsg responseMsg = (ResponseMsg) msg;

26
application/src/main/java/org/thingsboard/server/actors/session/AbstractSessionActorMsgProcessor.java

@ -22,8 +22,8 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.device.BasicToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.BasicDeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.session.*;
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg;
@ -37,7 +37,7 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP
protected final SessionId sessionId;
protected SessionContext sessionCtx;
protected ToDeviceActorMsg toDeviceActorMsgPrototype;
protected DeviceToDeviceActorMsg deviceToDeviceActorMsgPrototype;
protected AbstractSessionActorMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) {
super(ctx, logger);
@ -64,29 +64,29 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP
protected void updateSessionCtx(ToDeviceActorSessionMsg msg, SessionType type) {
sessionCtx = msg.getSessionMsg().getSessionContext();
toDeviceActorMsgPrototype = new BasicToDeviceActorMsg(msg, type);
deviceToDeviceActorMsgPrototype = new BasicDeviceToDeviceActorMsg(msg, type);
}
protected ToDeviceActorMsg toDeviceMsg(ToDeviceActorSessionMsg msg) {
protected DeviceToDeviceActorMsg toDeviceMsg(ToDeviceActorSessionMsg msg) {
AdaptorToSessionActorMsg adaptorMsg = msg.getSessionMsg();
return new BasicToDeviceActorMsg(toDeviceActorMsgPrototype, adaptorMsg.getMsg());
return new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, adaptorMsg.getMsg());
}
protected Optional<ToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) {
if (toDeviceActorMsgPrototype != null) {
return Optional.of(new BasicToDeviceActorMsg(toDeviceActorMsgPrototype, msg));
protected Optional<DeviceToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) {
if (deviceToDeviceActorMsgPrototype != null) {
return Optional.of(new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, msg));
} else {
return Optional.empty();
}
}
protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, ToDeviceActorMsg toForward) {
protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward) {
Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(toForward.getDeviceId());
forwardToAppActor(ctx, toForward, address);
return address;
}
protected Optional<ServerAddress> forwardToAppActorIfAdressChanged(ActorContext ctx, ToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) {
protected Optional<ServerAddress> forwardToAppActorIfAdressChanged(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) {
Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolveById(toForward.getDeviceId());
if (!newAddress.equals(oldAddress)) {
if (newAddress.isPresent()) {
@ -99,7 +99,7 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP
return newAddress;
}
protected void forwardToAppActor(ActorContext ctx, ToDeviceActorMsg toForward, Optional<ServerAddress> address) {
protected void forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> address) {
if (address.isPresent()) {
systemContext.getRpcService().tell(address.get(),
toForward.toOtherAddress(systemContext.getRoutingService().getCurrentServer()));
@ -114,6 +114,6 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP
}
public DeviceId getDeviceId() {
return toDeviceActorMsgPrototype.getDeviceId();
return deviceToDeviceActorMsgPrototype.getDeviceId();
}
}

4
application/src/main/java/org/thingsboard/server/actors/session/SyncMsgProcessor.java

@ -20,7 +20,7 @@ import org.thingsboard.server.actors.shared.SessionTimeoutMsg;
import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.session.*;
import org.thingsboard.server.common.msg.session.ToDeviceActorSessionMsg;
import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg;
@ -32,7 +32,7 @@ import akka.event.LoggingAdapter;
import java.util.Optional;
class SyncMsgProcessor extends AbstractSessionActorMsgProcessor {
private ToDeviceActorMsg pendingMsg;
private DeviceToDeviceActorMsg pendingMsg;
private Optional<ServerAddress> currentTargetServer;
private boolean pendingResponse;

71
application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java

@ -17,10 +17,9 @@ package org.thingsboard.server.actors.tenant;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.device.DeviceActor;
import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg;
import org.thingsboard.server.actors.plugin.PluginTerminationMsg;
import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
@ -30,7 +29,8 @@ import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
@ -64,63 +64,47 @@ public class TenantActor extends RuleChainManagerActor {
@Override
protected boolean process(TbActorMsg msg) {
switch (msg.getMsgType()) {
case CLUSTER_EVENT_MSG:
broadcast(msg);
break;
case COMPONENT_LIFE_CYCLE_MSG:
onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
break;
case SERVICE_TO_RULE_ENGINE_MSG:
onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
break;
case DEVICE_ACTOR_TO_RULE_ENGINE_MSG:
onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg);
break;
case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG:
case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
onToDeviceActorMsg((DeviceAwareMsg) msg);
break;
default:
return false;
}
return true;
}
private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) {
ruleChainManager.getRootChainActor().tell(msg, self());
}
// @Override
// public void onReceive(Object msg) throws Exception {
// logger.debug("[{}] Received message: {}", tenantId, msg);
// if (msg instanceof ToDeviceActorMsg) {
// onToDeviceActorMsg((ToDeviceActorMsg) msg);
// } else if (msg instanceof ToPluginActorMsg) {
// onToPluginMsg((ToPluginActorMsg) msg);
// } else if (msg instanceof ToDeviceActorNotificationMsg) {
// onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg);
// } else if (msg instanceof ClusterEventMsg) {
// broadcast(msg);
// } else if (msg instanceof ComponentLifecycleMsg) {
// onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
// } else if (msg instanceof PluginTerminationMsg) {
// onPluginTerminated((PluginTerminationMsg) msg);
// } else {
// logger.warning("[{}] Unknown message: {}!", tenantId, msg);
// }
// }
private void broadcast(Object msg) {
pluginManager.broadcast(msg);
@Override
protected void broadcast(Object msg) {
super.broadcast(msg);
deviceActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
}
private void onToDeviceActorMsg(ToDeviceActorMsg msg) {
getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender());
private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) {
ruleChainManager.getRootChainActor().tell(msg, self());
}
private void onToDeviceActorMsg(ToDeviceActorNotificationMsg msg) {
getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender());
private void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg msg) {
ruleChainManager.getRootChainActor().tell(msg, self());
}
private void onToPluginMsg(ToPluginActorMsg msg) {
if (msg.getPluginTenantId().equals(tenantId)) {
ActorRef pluginActor = pluginManager.getOrCreateActor(this.context(), msg.getPluginId());
pluginActor.tell(msg, ActorRef.noSender());
} else {
context().parent().tell(msg, ActorRef.noSender());
}
private void onToDeviceActorMsg(DeviceAwareMsg msg) {
getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender());
}
private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
@ -132,11 +116,6 @@ public class TenantActor extends RuleChainManagerActor {
}
}
private void onPluginTerminated(PluginTerminationMsg msg) {
pluginManager.remove(msg.getId());
}
private ActorRef getOrCreateDeviceActor(DeviceId deviceId) {
return deviceActors.computeIfAbsent(deviceId, k -> context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId))
.withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), deviceId.toString()));

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

@ -606,7 +606,7 @@ public abstract class BaseController {
auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo);
}
protected static Exception toException(Throwable error) {
public static Exception toException(Throwable error) {
return Exception.class.isInstance(error) ? (Exception) error : new Exception(error);
}

149
application/src/main/java/org/thingsboard/server/controller/RpcController.java

@ -0,0 +1,149 @@
/**
* Copyright © 2016-2018 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.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.FutureCallback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.actors.plugin.ValidationResult;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.extensions.api.exception.ToErrorResponseEntity;
import org.thingsboard.server.extensions.api.plugins.PluginConstants;
import org.thingsboard.server.common.data.rpc.RpcRequest;
import org.thingsboard.server.service.rpc.LocalRequestMetaData;
import org.thingsboard.server.service.rpc.DeviceRpcService;
import org.thingsboard.server.service.security.AccessValidator;
import org.thingsboard.server.service.security.model.SecurityUser;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by ashvayka on 22.03.18.
*/
@RestController
@RequestMapping(PluginConstants.RPC_URL_PREFIX)
@Slf4j
public class RpcController extends BaseController {
public static final int DEFAULT_TIMEOUT = 10000;
protected final ObjectMapper jsonMapper = new ObjectMapper();
@Autowired
private DeviceRpcService deviceRpcService;
@Autowired
private AccessValidator accessValidator;
private ExecutorService executor;
@PostConstruct
public void initExecutor() {
executor = Executors.newSingleThreadExecutor();
}
@PreDestroy
public void shutdownExecutor() {
if (executor != null) {
executor.shutdownNow();
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody);
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST)
@ResponseBody
public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException {
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody);
}
private DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody) throws ThingsboardException {
try {
JsonNode rpcRequestBody = jsonMapper.readTree(requestBody);
RpcRequest cmd = new RpcRequest(rpcRequestBody.get("method").asText(),
jsonMapper.writeValueAsString(rpcRequestBody.get("params")));
if (rpcRequestBody.has("timeout")) {
cmd.setTimeout(rpcRequestBody.get("timeout").asLong());
}
SecurityUser currentUser = getCurrentUser();
TenantId tenantId = currentUser.getTenantId();
final DeferredResult<ResponseEntity> response = new DeferredResult<>();
long timeout = System.currentTimeMillis() + (cmd.getTimeout() != null ? cmd.getTimeout() : DEFAULT_TIMEOUT);
ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(cmd.getMethodName(), cmd.getRequestData());
accessValidator.validate(currentUser, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() {
@Override
public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {
ToDeviceRpcRequest rpcRequest = new ToDeviceRpcRequest(UUID.randomUUID(),
tenantId,
deviceId,
oneWay,
timeout,
body
);
deviceRpcService.process(rpcRequest, new LocalRequestMetaData(rpcRequest, currentUser, result));
}
@Override
public void onFailure(Throwable e) {
ResponseEntity entity;
if (e instanceof ToErrorResponseEntity) {
entity = ((ToErrorResponseEntity) e).toErrorResponseEntity();
} else {
entity = new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
deviceRpcService.logRpcCall(currentUser, deviceId, body, oneWay, Optional.empty(), e);
response.setResult(entity);
}
}));
return response;
} catch (IOException ioe) {
throw new ThingsboardException("Invalid request body", ioe, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
}
}

32
application/src/main/java/org/thingsboard/server/controller/TenantController.java

@ -15,21 +15,34 @@
*/
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.install.InstallScripts;
@RestController
@RequestMapping("/api")
@Slf4j
public class TenantController extends BaseController {
@Autowired
private InstallScripts installScripts;
@Autowired
private TenantService tenantService;
@ -49,10 +62,15 @@ public class TenantController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant", method = RequestMethod.POST)
@ResponseBody
@ResponseBody
public Tenant saveTenant(@RequestBody Tenant tenant) throws ThingsboardException {
try {
return checkNotNull(tenantService.saveTenant(tenant));
boolean newTenant = tenant.getId() == null;
tenant = checkNotNull(tenantService.saveTenant(tenant));
if (newTenant) {
installScripts.createDefaultRuleChains(tenant.getId());
}
return tenant;
} catch (Exception e) {
throw handleException(e);
}
@ -72,7 +90,7 @@ public class TenantController extends BaseController {
}
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenants", params = { "limit" }, method = RequestMethod.GET)
@RequestMapping(value = "/tenants", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody
public TextPageData<Tenant> getTenants(@RequestParam int limit,
@RequestParam(required = false) String textSearch,
@ -85,5 +103,5 @@ public class TenantController extends BaseController {
throw handleException(e);
}
}
}

4
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -131,8 +131,8 @@ public class ThingsboardInstallService {
systemDataLoaderService.createSysAdmin();
systemDataLoaderService.createAdminSettings();
systemDataLoaderService.loadSystemWidgets();
systemDataLoaderService.loadSystemPlugins();
systemDataLoaderService.loadSystemRules();
// systemDataLoaderService.loadSystemPlugins();
// systemDataLoaderService.loadSystemRules();
if (loadDemo) {
log.info("Loading demo data...");

30
application/src/main/java/org/thingsboard/server/service/cluster/rpc/ClusterGrpcService.java

@ -19,7 +19,6 @@ import com.google.protobuf.ByteString;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -27,29 +26,24 @@ import org.springframework.util.SerializationUtils;
import org.thingsboard.server.actors.rpc.RpcBroadcastMsg;
import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg;
import org.thingsboard.server.actors.rpc.RpcSessionTellMsg;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg;
import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc;
import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
import org.thingsboard.server.service.cluster.discovery.ServerInstance;
import org.thingsboard.server.service.cluster.discovery.ServerInstanceService;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -124,7 +118,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI
}
@Override
public void tell(ServerAddress serverAddress, ToDeviceActorMsg toForward) {
public void tell(ServerAddress serverAddress, DeviceToDeviceActorMsg toForward) {
ClusterAPIProtos.ToRpcServerMessage msg = ClusterAPIProtos.ToRpcServerMessage.newBuilder()
.setToDeviceActorRpcMsg(toProtoMsg(toForward)).build();
tell(serverAddress, msg);
@ -138,7 +132,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI
}
@Override
public void tell(ServerAddress serverAddress, ToDeviceRpcRequestPluginMsg toForward) {
public void tell(ServerAddress serverAddress, ToDeviceRpcRequestMsg toForward) {
ClusterAPIProtos.ToRpcServerMessage msg = ClusterAPIProtos.ToRpcServerMessage.newBuilder()
.setToDeviceRpcRequestRpcMsg(toProtoMsg(toForward)).build();
tell(serverAddress, msg);
@ -190,7 +184,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI
}
}
private static ClusterAPIProtos.ToDeviceActorRpcMessage toProtoMsg(ToDeviceActorMsg msg) {
private static ClusterAPIProtos.ToDeviceActorRpcMessage toProtoMsg(DeviceToDeviceActorMsg msg) {
return ClusterAPIProtos.ToDeviceActorRpcMessage.newBuilder().setData(
ByteString.copyFrom(SerializationUtils.serialize(msg))
).build();
@ -202,15 +196,10 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI
).build();
}
private static ClusterAPIProtos.ToDeviceRpcRequestRpcMessage toProtoMsg(ToDeviceRpcRequestPluginMsg msg) {
private static ClusterAPIProtos.ToDeviceRpcRequestRpcMessage toProtoMsg(ToDeviceRpcRequestMsg msg) {
ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.Builder builder = ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.newBuilder();
ToDeviceRpcRequest request = msg.getMsg();
builder.setAddress(ClusterAPIProtos.PluginAddress.newBuilder()
.setTenantId(toUid(msg.getPluginTenantId().getId()))
.setPluginId(toUid(msg.getPluginId().getId()))
.build());
builder.setDeviceTenantId(toUid(msg.getTenantId()));
builder.setDeviceId(toUid(msg.getDeviceId()));
@ -227,11 +216,6 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI
ClusterAPIProtos.ToPluginRpcResponseRpcMessage.Builder builder = ClusterAPIProtos.ToPluginRpcResponseRpcMessage.newBuilder();
FromDeviceRpcResponse request = msg.getResponse();
builder.setAddress(ClusterAPIProtos.PluginAddress.newBuilder()
.setTenantId(toUid(msg.getPluginTenantId().getId()))
.setPluginId(toUid(msg.getPluginId().getId()))
.build());
builder.setMsgId(toUid(request.getId()));
request.getResponse().ifPresent(builder::setResponse);
request.getError().ifPresent(e -> builder.setError(e.name()));

9
application/src/main/java/org/thingsboard/server/service/cluster/rpc/ClusterRpcService.java

@ -19,12 +19,12 @@ import io.grpc.stub.StreamObserver;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg;
import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg;
import java.util.UUID;
@ -35,13 +35,13 @@ public interface ClusterRpcService {
void init(RpcMsgListener listener);
void tell(ServerAddress serverAddress, ToDeviceActorMsg toForward);
void tell(ServerAddress serverAddress, DeviceToDeviceActorMsg toForward);
void tell(ServerAddress serverAddress, ToDeviceSessionActorMsg toForward);
void tell(ServerAddress serverAddress, ToDeviceActorNotificationMsg toForward);
void tell(ServerAddress serverAddress, ToDeviceRpcRequestPluginMsg toForward);
void tell(ServerAddress serverAddress, ToDeviceRpcRequestMsg toForward);
void tell(ServerAddress serverAddress, ToPluginRpcResponseDeviceMsg toForward);
@ -50,4 +50,5 @@ public interface ClusterRpcService {
void broadcast(ToAllNodesMsg msg);
void onSessionCreated(UUID msgUid, StreamObserver<ClusterAPIProtos.ToRpcServerMessage> inputStream);
}

6
application/src/main/java/org/thingsboard/server/service/cluster/rpc/RpcMsgListener.java

@ -20,18 +20,16 @@ import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg;
import org.thingsboard.server.actors.rpc.RpcSessionTellMsg;
import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg;
import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg;
import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
/**
* @author Andrew Shvayka
*/
public interface RpcMsgListener {
void onMsg(ToDeviceActorMsg msg);
void onMsg(DeviceToDeviceActorMsg msg);
void onMsg(ToDeviceActorNotificationMsg msg);

147
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java

@ -60,21 +60,12 @@ import java.nio.file.Paths;
@Slf4j
public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
private static final String JSON_DIR = "json";
private static final String SYSTEM_DIR = "system";
private static final String DEMO_DIR = "demo";
private static final String WIDGET_BUNDLES_DIR = "widget_bundles";
private static final String PLUGINS_DIR = "plugins";
private static final String RULES_DIR = "rules";
private static final String DASHBOARDS_DIR = "dashboards";
private static final ObjectMapper objectMapper = new ObjectMapper();
public static final String JSON_EXT = ".json";
public static final String CUSTOMER_CRED = "customer";
public static final String DEFAULT_DEVICE_TYPE = "default";
@Value("${install.data_dir}")
private String dataDir;
@Autowired
private InstallScripts installScripts;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
@ -88,15 +79,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
@Autowired
private WidgetsBundleService widgetsBundleService;
@Autowired
private WidgetTypeService widgetTypeService;
@Autowired
private PluginService pluginService;
@Autowired
private RuleService ruleService;
@Autowired
private TenantService tenantService;
@ -109,9 +91,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
@Autowired
private DeviceCredentialsService deviceCredentialsService;
@Autowired
private DashboardService dashboardService;
@Bean
protected BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
@ -146,56 +125,13 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
adminSettingsService.saveAdminSettings(mailSettings);
}
@Override
public void loadSystemWidgets() throws Exception {
Path widgetBundlesDir = Paths.get(dataDir, JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) {
dirStream.forEach(
path -> {
try {
JsonNode widgetsBundleDescriptorJson = objectMapper.readTree(path.toFile());
JsonNode widgetsBundleJson = widgetsBundleDescriptorJson.get("widgetsBundle");
WidgetsBundle widgetsBundle = objectMapper.treeToValue(widgetsBundleJson, WidgetsBundle.class);
WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle);
JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes");
widgetTypesArrayJson.forEach(
widgetTypeJson -> {
try {
WidgetType widgetType = objectMapper.treeToValue(widgetTypeJson, WidgetType.class);
widgetType.setBundleAlias(savedWidgetsBundle.getAlias());
widgetTypeService.saveWidgetType(widgetType);
} catch (Exception e) {
log.error("Unable to load widget type from json: [{}]", path.toString());
throw new RuntimeException("Unable to load widget type from json", e);
}
}
);
} catch (Exception e) {
log.error("Unable to load widgets bundle from json: [{}]", path.toString());
throw new RuntimeException("Unable to load widgets bundle from json", e);
}
}
);
}
}
@Override
public void loadSystemPlugins() throws Exception {
loadPlugins(Paths.get(dataDir, JSON_DIR, SYSTEM_DIR, PLUGINS_DIR), null);
}
@Override
public void loadSystemRules() throws Exception {
// loadRules(Paths.get(dataDir, JSON_DIR, SYSTEM_DIR, RULES_DIR), null);
}
@Override
public void loadDemoData() throws Exception {
Tenant demoTenant = new Tenant();
demoTenant.setRegion("Global");
demoTenant.setTitle("Tenant");
demoTenant = tenantService.saveTenant(demoTenant);
installScripts.createDefaultRuleChains(demoTenant.getId());
createUser(Authority.TENANT_ADMIN, demoTenant.getId(), null, "tenant@thingsboard.org", "tenant");
Customer customerA = new Customer();
@ -227,9 +163,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
createDevice(demoTenant.getId(), null, DEFAULT_DEVICE_TYPE, "Raspberry Pi Demo Device", "RASPBERRY_PI_DEMO_TOKEN", "Demo device that is used in " +
"Raspberry Pi GPIO control sample application");
loadPlugins(Paths.get(dataDir, JSON_DIR, DEMO_DIR, PLUGINS_DIR), demoTenant.getId());
// loadRules(Paths.get(dataDir, JSON_DIR, DEMO_DIR, RULES_DIR), demoTenant.getId());
loadDashboards(Paths.get(dataDir, JSON_DIR, DEMO_DIR, DASHBOARDS_DIR), demoTenant.getId(), null);
installScripts.loadDashboards(demoTenant.getId(), null);
}
@Override
@ -240,6 +174,11 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
}
}
@Override
public void loadSystemWidgets() throws Exception {
installScripts.loadSystemWidgets();
}
private User createUser(Authority authority,
TenantId tenantId,
CustomerId customerId,
@ -282,72 +221,4 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
return device;
}
private void loadPlugins(Path pluginsDir, TenantId tenantId) throws Exception{
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(pluginsDir, path -> path.toString().endsWith(JSON_EXT))) {
dirStream.forEach(
path -> {
try {
JsonNode pluginJson = objectMapper.readTree(path.toFile());
PluginMetaData plugin = objectMapper.treeToValue(pluginJson, PluginMetaData.class);
plugin.setTenantId(tenantId);
if (plugin.getState() == ComponentLifecycleState.ACTIVE) {
plugin.setState(ComponentLifecycleState.SUSPENDED);
PluginMetaData savedPlugin = pluginService.savePlugin(plugin);
pluginService.activatePluginById(savedPlugin.getId());
} else {
pluginService.savePlugin(plugin);
}
} catch (Exception e) {
log.error("Unable to load plugin from json: [{}]", path.toString());
throw new RuntimeException("Unable to load plugin from json", e);
}
}
);
}
}
private void loadRules(Path rulesDir, TenantId tenantId) throws Exception {
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(rulesDir, path -> path.toString().endsWith(JSON_EXT))) {
dirStream.forEach(
path -> {
try {
JsonNode ruleJson = objectMapper.readTree(path.toFile());
RuleMetaData rule = objectMapper.treeToValue(ruleJson, RuleMetaData.class);
rule.setTenantId(tenantId);
if (rule.getState() == ComponentLifecycleState.ACTIVE) {
rule.setState(ComponentLifecycleState.SUSPENDED);
RuleMetaData savedRule = ruleService.saveRule(rule);
ruleService.activateRuleById(savedRule.getId());
} else {
ruleService.saveRule(rule);
}
} catch (Exception e) {
log.error("Unable to load rule from json: [{}]", path.toString());
throw new RuntimeException("Unable to load rule from json", e);
}
}
);
}
}
private void loadDashboards(Path dashboardsDir, TenantId tenantId, CustomerId customerId) throws Exception {
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) {
dirStream.forEach(
path -> {
try {
JsonNode dashboardJson = objectMapper.readTree(path.toFile());
Dashboard dashboard = objectMapper.treeToValue(dashboardJson, Dashboard.class);
dashboard.setTenantId(tenantId);
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard);
if (customerId != null && !customerId.isNullUid()) {
dashboardService.assignDashboardToCustomer(savedDashboard.getId(), customerId);
}
} catch (Exception e) {
log.error("Unable to load dashboard from json: [{}]", path.toString());
throw new RuntimeException("Unable to load dashboard from json", e);
}
}
);
}
}
}

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

@ -0,0 +1,182 @@
/**
* Copyright © 2016-2018 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.install;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper;
/**
* Created by ashvayka on 18.04.18.
*/
@Component
@Slf4j
public class InstallScripts {
public static final String APP_DIR = "application";
public static final String SRC_DIR = "src";
public static final String MAIN_DIR = "main";
public static final String DATA_DIR = "data";
public static final String JSON_DIR = "json";
public static final String SYSTEM_DIR = "system";
public static final String TENANT_DIR = "tenant";
public static final String DEMO_DIR = "demo";
public static final String RULE_CHAINS_DIR = "rule_chains";
public static final String WIDGET_BUNDLES_DIR = "widget_bundles";
public static final String DASHBOARDS_DIR = "dashboards";
public static final String JSON_EXT = ".json";
@Value("${install.data_dir:}")
private String dataDir;
@Autowired
private RuleChainService ruleChainService;
@Autowired
private DashboardService dashboardService;
@Autowired
private WidgetTypeService widgetTypeService;
@Autowired
private WidgetsBundleService widgetsBundleService;
public Path getTenantRuleChainsDir() {
return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
}
public String getDataDir() {
if (!StringUtils.isEmpty(dataDir)) {
return dataDir;
} else {
String workDir = System.getProperty("user.dir");
if (workDir.endsWith("application")) {
return Paths.get(workDir, SRC_DIR, MAIN_DIR, DATA_DIR).toString();
} else {
Path dataDirPath = Paths.get(workDir, APP_DIR, SRC_DIR, MAIN_DIR, DATA_DIR);
if (Files.exists(dataDirPath)) {
return dataDirPath.toString();
} else {
throw new RuntimeException("Not valid working directory: " + workDir + ". Please use either root project directory, application module directory or specify valid \"install.data_dir\" ENV variable to avoid automatic data directory lookup!");
}
}
}
}
public void createDefaultRuleChains(TenantId tenantId) throws IOException {
Path tenantChainsDir = getTenantRuleChainsDir();
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(tenantChainsDir, path -> path.toString().endsWith(InstallScripts.JSON_EXT))) {
dirStream.forEach(
path -> {
try {
JsonNode ruleChainJson = objectMapper.readTree(path.toFile());
RuleChain ruleChain = objectMapper.treeToValue(ruleChainJson.get("ruleChain"), RuleChain.class);
RuleChainMetaData ruleChainMetaData = objectMapper.treeToValue(ruleChainJson.get("metadata"), RuleChainMetaData.class);
ruleChain.setTenantId(tenantId);
ruleChain = ruleChainService.saveRuleChain(ruleChain);
ruleChainMetaData.setRuleChainId(ruleChain.getId());
ruleChainService.saveRuleChainMetaData(ruleChainMetaData);
} catch (Exception e) {
log.error("Unable to load rule chain from json: [{}]", path.toString());
throw new RuntimeException("Unable to load rule chain from json", e);
}
}
);
}
}
public void loadSystemWidgets() throws Exception {
Path widgetBundlesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) {
dirStream.forEach(
path -> {
try {
JsonNode widgetsBundleDescriptorJson = objectMapper.readTree(path.toFile());
JsonNode widgetsBundleJson = widgetsBundleDescriptorJson.get("widgetsBundle");
WidgetsBundle widgetsBundle = objectMapper.treeToValue(widgetsBundleJson, WidgetsBundle.class);
WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle);
JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes");
widgetTypesArrayJson.forEach(
widgetTypeJson -> {
try {
WidgetType widgetType = objectMapper.treeToValue(widgetTypeJson, WidgetType.class);
widgetType.setBundleAlias(savedWidgetsBundle.getAlias());
widgetTypeService.saveWidgetType(widgetType);
} catch (Exception e) {
log.error("Unable to load widget type from json: [{}]", path.toString());
throw new RuntimeException("Unable to load widget type from json", e);
}
}
);
} catch (Exception e) {
log.error("Unable to load widgets bundle from json: [{}]", path.toString());
throw new RuntimeException("Unable to load widgets bundle from json", e);
}
}
);
}
}
public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception {
Path dashboardsDir = Paths.get(getDataDir(), JSON_DIR, DEMO_DIR, DASHBOARDS_DIR);
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) {
dirStream.forEach(
path -> {
try {
JsonNode dashboardJson = objectMapper.readTree(path.toFile());
Dashboard dashboard = objectMapper.treeToValue(dashboardJson, Dashboard.class);
dashboard.setTenantId(tenantId);
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard);
if (customerId != null && !customerId.isNullUid()) {
dashboardService.assignDashboardToCustomer(savedDashboard.getId(), customerId);
}
} catch (Exception e) {
log.error("Unable to load dashboard from json: [{}]", path.toString());
throw new RuntimeException("Unable to load dashboard from json", e);
}
}
);
}
}
}

4
application/src/main/java/org/thingsboard/server/service/install/SystemDataLoaderService.java

@ -23,10 +23,6 @@ public interface SystemDataLoaderService {
void loadSystemWidgets() throws Exception;
void loadSystemPlugins() throws Exception;
void loadSystemRules() throws Exception;
void loadDemoData() throws Exception;
void deleteSystemWidgetBundle(String bundleAlias) throws Exception;

215
application/src/main/java/org/thingsboard/server/service/rpc/DefaultDeviceRpcService.java

@ -0,0 +1,215 @@
/**
* Copyright © 2016-2018 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.rpc;
import akka.actor.ActorRef;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.controller.BaseController;
import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
import org.thingsboard.server.service.security.model.SecurityUser;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
/**
* Created by ashvayka on 27.03.18.
*/
@Service
@Slf4j
public class DefaultDeviceRpcService implements DeviceRpcService {
private static final ObjectMapper jsonMapper = new ObjectMapper();
@Autowired
private ClusterRoutingService routingService;
@Autowired
private ClusterRpcService rpcService;
@Autowired
private ActorService actorService;
@Autowired
private AuditLogService auditLogService;
private ScheduledExecutorService rpcCallBackExecutor;
private final ConcurrentMap<UUID, LocalRequestMetaData> localRpcRequests = new ConcurrentHashMap<>();
@PostConstruct
public void initExecutor() {
rpcCallBackExecutor = Executors.newSingleThreadScheduledExecutor();
}
@PreDestroy
public void shutdownExecutor() {
if (rpcCallBackExecutor != null) {
rpcCallBackExecutor.shutdownNow();
}
}
@Override
public void process(ToDeviceRpcRequest request, LocalRequestMetaData metaData) {
log.trace("[{}] Processing local rpc call for device [{}]", request.getTenantId(), request.getDeviceId());
sendRpcRequest(request);
UUID requestId = request.getId();
localRpcRequests.put(requestId, metaData);
long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis());
log.error("[{}] processing the request: [{}]", this.hashCode(), requestId);
rpcCallBackExecutor.schedule(() -> {
log.error("[{}] timeout the request: [{}]", this.hashCode(), requestId);
LocalRequestMetaData localMetaData = localRpcRequests.remove(requestId);
if (localMetaData != null) {
reply(localMetaData, new FromDeviceRpcResponse(requestId, null, RpcError.TIMEOUT));
}
}, timeout, TimeUnit.MILLISECONDS);
}
@Override
public void process(ToDeviceRpcRequest request, ServerAddress originator) {
// if (pluginServerAddress.isPresent()) {
// systemContext.getRpcService().tell(pluginServerAddress.get(), responsePluginMsg);
// logger.debug("[{}] Rpc command response sent to remote plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId());
// } else {
// context.parent().tell(responsePluginMsg, ActorRef.noSender());
// logger.debug("[{}] Rpc command response sent to local plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId());
// }
}
@Override
public void process(FromDeviceRpcResponse response) {
log.error("[{}] response the request: [{}]", this.hashCode(), response.getId());
//TODO: send to another server if needed.
UUID requestId = response.getId();
LocalRequestMetaData md = localRpcRequests.remove(requestId);
if (md != null) {
log.trace("[{}] Processing local rpc response from device [{}]", requestId, md.getRequest().getDeviceId());
reply(md, response);
} else {
log.trace("[{}] Unknown or stale rpc response received [{}]", requestId, response);
}
}
public void reply(LocalRequestMetaData rpcRequest, FromDeviceRpcResponse response) {
Optional<RpcError> rpcError = response.getError();
DeferredResult<ResponseEntity> responseWriter = rpcRequest.getResponseWriter();
if (rpcError.isPresent()) {
logRpcCall(rpcRequest, rpcError, null);
RpcError error = rpcError.get();
switch (error) {
case TIMEOUT:
responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));
break;
case NO_ACTIVE_CONNECTION:
responseWriter.setResult(new ResponseEntity<>(HttpStatus.CONFLICT));
break;
default:
responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT));
break;
}
} else {
Optional<String> responseData = response.getResponse();
if (responseData.isPresent() && !StringUtils.isEmpty(responseData.get())) {
String data = responseData.get();
try {
logRpcCall(rpcRequest, rpcError, null);
responseWriter.setResult(new ResponseEntity<>(jsonMapper.readTree(data), HttpStatus.OK));
} catch (IOException e) {
log.debug("Failed to decode device response: {}", data, e);
logRpcCall(rpcRequest, rpcError, e);
responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE));
}
} else {
logRpcCall(rpcRequest, rpcError, null);
responseWriter.setResult(new ResponseEntity<>(HttpStatus.OK));
}
}
}
private void sendRpcRequest(ToDeviceRpcRequest msg) {
log.trace("[{}] Forwarding msg {} to device actor!", msg.getDeviceId(), msg);
ToDeviceRpcRequestMsg rpcMsg = new ToDeviceRpcRequestMsg(msg);
forward(msg.getDeviceId(), rpcMsg, rpcService::tell);
}
private void forward(DeviceId deviceId, ToDeviceRpcRequestMsg msg, BiConsumer<ServerAddress, ToDeviceRpcRequestMsg> rpcFunction) {
Optional<ServerAddress> instance = routingService.resolveById(deviceId);
if (instance.isPresent()) {
log.trace("[{}] Forwarding msg {} to remote device actor!", msg.getTenantId(), msg);
rpcFunction.accept(instance.get(), msg);
} else {
log.trace("[{}] Forwarding msg {} to local device actor!", msg.getTenantId(), msg);
actorService.onMsg(msg);
}
}
private void logRpcCall(LocalRequestMetaData rpcRequest, Optional<RpcError> rpcError, Throwable e) {
logRpcCall(rpcRequest.getUser(), rpcRequest.getRequest().getDeviceId(), rpcRequest.getRequest().getBody(), rpcRequest.getRequest().isOneway(), rpcError, null);
}
@Override
public void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e) {
String rpcErrorStr = "";
if (rpcError.isPresent()) {
rpcErrorStr = "RPC Error: " + rpcError.get().name();
}
String method = body.getMethod();
String params = body.getParams();
auditLogService.logEntityAction(
user.getTenantId(),
user.getCustomerId(),
user.getId(),
user.getName(),
(UUIDBased & EntityId) entityId,
null,
ActionType.RPC_CALL,
BaseController.toException(e),
rpcErrorStr,
oneWay,
method,
params);
}
}

40
application/src/main/java/org/thingsboard/server/service/rpc/DeviceRpcService.java

@ -0,0 +1,40 @@
/**
* Copyright © 2016-2018 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.rpc;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.Optional;
/**
* Created by ashvayka on 16.04.18.
*/
public interface DeviceRpcService {
void process(ToDeviceRpcRequest request, LocalRequestMetaData metaData);
void process(ToDeviceRpcRequest request, ServerAddress originator);
void process(FromDeviceRpcResponse response);
void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e);
}

8
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/rpc/LocalRequestMetaData.java → application/src/main/java/org/thingsboard/server/service/rpc/LocalRequestMetaData.java

@ -13,18 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.extensions.core.plugin.rpc;
package org.thingsboard.server.service.rpc;
import lombok.Data;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.service.security.model.SecurityUser;
/**
* @author Andrew Shvayka
* Created by ashvayka on 16.04.18.
*/
@Data
public class LocalRequestMetaData {
private final ToDeviceRpcRequest request;
private final SecurityUser user;
private final DeferredResult<ResponseEntity> responseWriter;
}

23
extensions-api/src/main/java/org/thingsboard/server/extensions/api/plugins/msg/ToDeviceRpcRequestPluginMsg.java → application/src/main/java/org/thingsboard/server/service/rpc/ToDeviceRpcRequestMsg.java

@ -13,36 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.extensions.api.plugins.msg;
package org.thingsboard.server.service.rpc;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import java.util.Optional;
/**
* @author Andrew Shvayka
* Created by ashvayka on 16.04.18.
*/
@ToString
@RequiredArgsConstructor
public class ToDeviceRpcRequestPluginMsg implements ToDeviceActorNotificationMsg {
public class ToDeviceRpcRequestMsg implements ToDeviceActorNotificationMsg {
private final ServerAddress serverAddress;
@Getter
private final PluginId pluginId;
@Getter
private final TenantId pluginTenantId;
@Getter
private final ToDeviceRpcRequest msg;
public ToDeviceRpcRequestPluginMsg(PluginId pluginId, TenantId pluginTenantId, ToDeviceRpcRequest msg) {
this(null, pluginId, pluginTenantId, msg);
public ToDeviceRpcRequestMsg(ToDeviceRpcRequest msg) {
this(null, msg);
}
public Optional<ServerAddress> getServerAddress() {
@ -58,5 +55,9 @@ public class ToDeviceRpcRequestPluginMsg implements ToDeviceActorNotificationMsg
public TenantId getTenantId() {
return msg.getTenantId();
}
}
@Override
public MsgType getMsgType() {
return MsgType.DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG;
}
}

54
application/src/main/java/org/thingsboard/server/service/security/AccessValidator.java

@ -25,6 +25,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
import org.thingsboard.server.actors.plugin.ValidationResult;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Tenant;
@ -35,8 +36,10 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.controller.HttpValidationCallback;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService;
@ -140,7 +143,7 @@ public class AccessValidator {
return response;
}
public <T> void validate(SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
public void validate(SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
switch (entityId.getEntityType()) {
case DEVICE:
validateDevice(currentUser, entityId, callback);
@ -177,14 +180,14 @@ public class AccessValidator {
} else if (currentUser.isCustomerUser() && !device.getCustomerId().equals(currentUser.getCustomerId())) {
return ValidationResult.accessDenied("Device doesn't belong to the current Customer!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(device);
}
}
}), executor);
}
}
private <T> void validateAsset(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
private void validateAsset(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
@ -198,15 +201,14 @@ public class AccessValidator {
} else if (currentUser.isCustomerUser() && !asset.getCustomerId().equals(currentUser.getCustomerId())) {
return ValidationResult.accessDenied("Asset doesn't belong to the current Customer!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(asset);
}
}
}), executor);
}
}
private <T> void validateRuleChain(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
private void validateRuleChain(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isCustomerUser()) {
callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
@ -220,14 +222,40 @@ public class AccessValidator {
} else if (currentUser.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) {
return ValidationResult.accessDenied("Rule chain is not in system scope!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(ruleChain);
}
}
}), executor);
}
}
private void validateRule(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isCustomerUser()) {
callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
ListenableFuture<RuleNode> ruleNodeFuture = ruleChainService.findRuleNodeByIdAsync(new RuleNodeId(entityId.getId()));
Futures.addCallback(ruleNodeFuture, getCallback(callback, ruleNodeTmp -> {
RuleNode ruleNode = ruleNodeTmp;
if (ruleNode == null) {
return ValidationResult.entityNotFound("Rule node with requested id wasn't found!");
} else if (ruleNode.getRuleChainId() == null) {
return ValidationResult.entityNotFound("Rule chain with requested node id wasn't found!");
} else {
//TODO: make async
RuleChain ruleChain = ruleChainService.findRuleChainById(ruleNode.getRuleChainId());
if (currentUser.isTenantAdmin() && !ruleChain.getTenantId().equals(currentUser.getTenantId())) {
return ValidationResult.accessDenied("Rule chain doesn't belong to the current Tenant!");
} else if (currentUser.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) {
return ValidationResult.accessDenied("Rule chain is not in system scope!");
} else {
return ValidationResult.ok(ruleNode);
}
}
}), executor);
}
}
private <T> void validateCustomer(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
private void validateCustomer(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else {
@ -241,18 +269,18 @@ public class AccessValidator {
} else if (currentUser.isCustomerUser() && !customer.getId().equals(currentUser.getCustomerId())) {
return ValidationResult.accessDenied("Customer doesn't relate to the currently authorized customer user!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(customer);
}
}
}), executor);
}
}
private <T> void validateTenant(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
private void validateTenant(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) {
if (currentUser.isCustomerUser()) {
callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
} else if (currentUser.isSystemAdmin()) {
callback.onSuccess(ValidationResult.ok());
callback.onSuccess(ValidationResult.ok(null));
} else {
ListenableFuture<Tenant> tenantFuture = tenantService.findTenantByIdAsync(new TenantId(entityId.getId()));
Futures.addCallback(tenantFuture, getCallback(callback, tenant -> {
@ -261,13 +289,13 @@ public class AccessValidator {
} else if (!tenant.getId().equals(currentUser.getTenantId())) {
return ValidationResult.accessDenied("Tenant doesn't relate to the currently authorized user!");
} else {
return ValidationResult.ok();
return ValidationResult.ok(tenant);
}
}), executor);
}
}
private <T> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult> transformer) {
private <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) {
return new FutureCallback<T>() {
@Override
public void onSuccess(@Nullable T result) {

3
application/src/main/proto/cluster.proto

@ -61,7 +61,6 @@ message ConnectRpcMessage {
}
message ToDeviceRpcRequestRpcMessage {
PluginAddress address = 1;
Uid deviceTenantId = 2;
Uid deviceId = 3;
@ -73,8 +72,6 @@ message ToDeviceRpcRequestRpcMessage {
}
message ToPluginRpcResponseRpcMessage {
PluginAddress address = 1;
Uid msgId = 2;
string response = 3;
string error = 4;

16
application/src/main/resources/thingsboard.yml

@ -207,18 +207,7 @@ actors:
sync:
# Default timeout for processing request using synchronous session (HTTP, CoAP) in milliseconds
timeout: "${ACTORS_SESSION_SYNC_TIMEOUT:10000}"
plugin:
# Default timeout for termination of the plugin actor after it is stopped
termination.delay: "${ACTORS_PLUGIN_TERMINATION_DELAY:60000}"
# Default timeout for processing of particular message by particular plugin
processing.timeout: "${ACTORS_PLUGIN_TIMEOUT:60000}"
# Errors for particular actor are persisted once per specified amount of milliseconds
error_persist_frequency: "${ACTORS_PLUGIN_ERROR_FREQUENCY:3000}"
rule:
# Default timeout for termination of the rule actor after it is stopped
termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}"
# Errors for particular actor are persisted once per specified amount of milliseconds
error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}"
# Specify thread pool size for database request callbacks executor service
db_callback_thread_pool_size: "${ACTORS_RULE_DB_CALLBACK_THREAD_POOL_SIZE:1}"
# Specify thread pool size for javascript executor service
@ -235,6 +224,11 @@ actors:
# Enable/disable actor statistics
enabled: "${ACTORS_STATISTICS_ENABLED:true}"
persist_frequency: "${ACTORS_STATISTICS_PERSIST_FREQUENCY:3600000}"
queue:
# Enable/disable persistence of un-processed messages to the queue
enabled: "${ACTORS_QUEUE_ENABLED:true}"
# Maximum allowed timeout for persistence into the queue
timeout: "${ACTORS_QUEUE_PERSISTENCE_TIMEOUT:30000}"
cache:
# caffeine or redis

27
application/src/test/java/org/thingsboard/server/actors/ActorsTestSuite.java

@ -1,27 +0,0 @@
/**
* Copyright © 2016-2018 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.actors;
import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith;
/**
* @author Andrew Shvayka
*/
@RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.actors.*Test"})
public class ActorsTestSuite {
}

245
application/src/test/java/org/thingsboard/server/actors/DefaultActorServiceTest.java

@ -1,245 +0,0 @@
/**
* Copyright © 2016-2018 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.actors;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.*;
import com.google.common.util.concurrent.Futures;
import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.session.*;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.gen.discovery.ServerInstanceProtos;
import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
import org.thingsboard.server.service.cluster.discovery.ServerInstance;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.common.transport.auth.DeviceAuthResult;
import org.thingsboard.server.common.transport.auth.DeviceAuthService;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.rule.RuleMetaData;
import org.thingsboard.server.common.data.security.DeviceCredentialsFilter;
import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
import org.thingsboard.server.common.msg.core.BasicTelemetryUploadRequest;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.plugin.PluginService;
import org.thingsboard.server.dao.rule.RuleService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
import org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.test.util.ReflectionTestUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class DefaultActorServiceTest {
private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
private static final String PLUGIN_ID = "9fb2e951-e298-4acb-913a-db69af8a15f4";
private static final String FILTERS_CONFIGURATION =
"[{\"clazz\":\"org.thingsboard.server.extensions.core.filter.MsgTypeFilter\", \"name\":\"TelemetryFilter\", \"configuration\": {\"messageTypes\":[\"POST_TELEMETRY\",\"POST_ATTRIBUTES\",\"GET_ATTRIBUTES\"]}}]";
private static final String ACTION_CONFIGURATION = "{\"pluginToken\":\"telemetry\", \"clazz\":\"org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction\", \"name\":\"TelemetryMsgConverterAction\", \"configuration\":{}}";
private static final String PLUGIN_CONFIGURATION = "{}";
private DefaultActorService actorService;
private ActorSystemContext actorContext;
private PluginService pluginService;
private RuleService ruleService;
private DeviceAuthService deviceAuthService;
private DeviceService deviceService;
private TimeseriesService tsService;
private TenantService tenantService;
private ClusterRpcService rpcService;
private DiscoveryService discoveryService;
private ClusterRoutingService routingService;
private AttributesService attributesService;
private ComponentDiscoveryService componentService;
private EventService eventService;
private ServerInstance serverInstance;
private RuleMetaData ruleMock;
private PluginMetaData pluginMock;
private RuleId ruleId = new RuleId(UUID.randomUUID());
private PluginId pluginId = new PluginId(UUID.fromString(PLUGIN_ID));
private TenantId tenantId = new TenantId(UUID.randomUUID());
@Before
public void before() throws Exception {
actorService = new DefaultActorService();
actorContext = new ActorSystemContext();
tenantService = mock(TenantService.class);
pluginService = mock(PluginService.class);
ruleService = mock(RuleService.class);
deviceAuthService = mock(DeviceAuthService.class);
deviceService = mock(DeviceService.class);
tsService = mock(TimeseriesService.class);
rpcService = mock(ClusterRpcService.class);
discoveryService = mock(DiscoveryService.class);
routingService = mock(ClusterRoutingService.class);
attributesService = mock(AttributesService.class);
componentService = mock(ComponentDiscoveryService.class);
eventService = mock(EventService.class);
serverInstance = new ServerInstance(ServerInstanceProtos.ServerInfo.newBuilder().setHost("localhost").setPort(8080).build());
ReflectionTestUtils.setField(actorService, "actorContext", actorContext);
ReflectionTestUtils.setField(actorService, "rpcService", rpcService);
ReflectionTestUtils.setField(actorService, "discoveryService", discoveryService);
ReflectionTestUtils.setField(actorContext, "syncSessionTimeout", 10000L);
ReflectionTestUtils.setField(actorContext, "pluginActorTerminationDelay", 10000L);
ReflectionTestUtils.setField(actorContext, "pluginErrorPersistFrequency", 10000L);
ReflectionTestUtils.setField(actorContext, "ruleActorTerminationDelay", 10000L);
ReflectionTestUtils.setField(actorContext, "ruleErrorPersistFrequency", 10000L);
ReflectionTestUtils.setField(actorContext, "pluginProcessingTimeout", 60000L);
ReflectionTestUtils.setField(actorContext, "tenantService", tenantService);
ReflectionTestUtils.setField(actorContext, "pluginService", pluginService);
ReflectionTestUtils.setField(actorContext, "ruleService", ruleService);
ReflectionTestUtils.setField(actorContext, "deviceAuthService", deviceAuthService);
ReflectionTestUtils.setField(actorContext, "deviceService", deviceService);
ReflectionTestUtils.setField(actorContext, "tsService", tsService);
ReflectionTestUtils.setField(actorContext, "rpcService", rpcService);
ReflectionTestUtils.setField(actorContext, "discoveryService", discoveryService);
ReflectionTestUtils.setField(actorContext, "tsService", tsService);
ReflectionTestUtils.setField(actorContext, "routingService", routingService);
ReflectionTestUtils.setField(actorContext, "attributesService", attributesService);
ReflectionTestUtils.setField(actorContext, "componentService", componentService);
ReflectionTestUtils.setField(actorContext, "eventService", eventService);
when(routingService.resolveById((EntityId) any())).thenReturn(Optional.empty());
when(discoveryService.getCurrentServer()).thenReturn(serverInstance);
ruleMock = mock(RuleMetaData.class);
when(ruleMock.getId()).thenReturn(ruleId);
when(ruleMock.getState()).thenReturn(ComponentLifecycleState.ACTIVE);
when(ruleMock.getPluginToken()).thenReturn("telemetry");
TextPageData<RuleMetaData> systemRules = new TextPageData<>(Collections.emptyList(), null, false);
TextPageData<RuleMetaData> tenantRules = new TextPageData<>(Collections.singletonList(ruleMock), null, false);
when(ruleService.findSystemRules(any())).thenReturn(systemRules);
when(ruleService.findTenantRules(any(), any())).thenReturn(tenantRules);
when(ruleService.findRuleById(ruleId)).thenReturn(ruleMock);
pluginMock = mock(PluginMetaData.class);
when(pluginMock.getTenantId()).thenReturn(SYSTEM_TENANT);
when(pluginMock.getId()).thenReturn(pluginId);
when(pluginMock.getState()).thenReturn(ComponentLifecycleState.ACTIVE);
TextPageData<PluginMetaData> systemPlugins = new TextPageData<>(Collections.singletonList(pluginMock), null, false);
TextPageData<PluginMetaData> tenantPlugins = new TextPageData<>(Collections.emptyList(), null, false);
when(pluginService.findSystemPlugins(any())).thenReturn(systemPlugins);
when(pluginService.findTenantPlugins(any(), any())).thenReturn(tenantPlugins);
when(pluginService.findPluginByApiToken("telemetry")).thenReturn(pluginMock);
when(pluginService.findPluginById(pluginId)).thenReturn(pluginMock);
TextPageData<Tenant> tenants = new TextPageData<>(Collections.emptyList(), null, false);
when(tenantService.findTenants(any())).thenReturn(tenants);
}
private void initActorSystem() {
actorService.initActorSystem();
}
@After
public void after() {
actorService.stopActorSystem();
}
@Test
public void testBasicPostWithSyncSession() throws Exception {
SessionContext ssnCtx = mock(SessionContext.class);
KvEntry entry1 = new StringDataEntry("key1", "value1");
KvEntry entry2 = new StringDataEntry("key2", "value2");
BasicTelemetryUploadRequest telemetry = new BasicTelemetryUploadRequest();
long ts = 42;
telemetry.add(ts, entry1);
telemetry.add(ts, entry2);
BasicAdaptorToSessionActorMsg msg = new BasicAdaptorToSessionActorMsg(ssnCtx, telemetry);
DeviceId deviceId = new DeviceId(UUID.randomUUID());
DeviceCredentialsFilter filter = new DeviceTokenCredentials("token1");
Device device = mock(Device.class);
when(device.getId()).thenReturn(deviceId);
when(device.getTenantId()).thenReturn(tenantId);
when(ssnCtx.getSessionId()).thenReturn(new DummySessionID("session1"));
when(ssnCtx.getSessionType()).thenReturn(SessionType.SYNC);
when(deviceAuthService.process(filter)).thenReturn(DeviceAuthResult.of(deviceId));
when(deviceService.findDeviceById(deviceId)).thenReturn(device);
ObjectMapper ruleMapper = new ObjectMapper();
when(ruleMock.getFilters()).thenReturn(ruleMapper.readTree(FILTERS_CONFIGURATION));
when(ruleMock.getAction()).thenReturn(ruleMapper.readTree(ACTION_CONFIGURATION));
ComponentDescriptor filterComp = new ComponentDescriptor();
filterComp.setClazz("org.thingsboard.server.extensions.core.filter.MsgTypeFilter");
filterComp.setType(ComponentType.FILTER);
when(componentService.getComponent("org.thingsboard.server.extensions.core.filter.MsgTypeFilter"))
.thenReturn(Optional.of(filterComp));
ComponentDescriptor actionComp = new ComponentDescriptor();
actionComp.setClazz("org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction");
actionComp.setType(ComponentType.ACTION);
when(componentService.getComponent("org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction"))
.thenReturn(Optional.of(actionComp));
ObjectMapper pluginMapper = new ObjectMapper();
JsonNode pluginAdditionalInfo = pluginMapper.readTree(PLUGIN_CONFIGURATION);
when(pluginMock.getConfiguration()).thenReturn(pluginAdditionalInfo);
when(pluginMock.getClazz()).thenReturn(TelemetryStoragePlugin.class.getName());
when(attributesService.findAll(deviceId, DataConstants.CLIENT_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList()));
when(attributesService.findAll(deviceId, DataConstants.SHARED_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList()));
when(attributesService.findAll(deviceId, DataConstants.SERVER_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList()));
initActorSystem();
Thread.sleep(1000);
actorService.process(new BasicToDeviceActorSessionMsg(device, msg));
// Check that device data was saved to DB;
List<TsKvEntry> expected = new ArrayList<>();
expected.add(new BasicTsKvEntry(ts, entry1));
expected.add(new BasicTsKvEntry(ts, entry2));
verify(tsService, Mockito.timeout(5000)).save(deviceId, expected, 0L);
}
}

63
application/src/test/java/org/thingsboard/server/actors/DummySessionID.java

@ -1,63 +0,0 @@
/**
* Copyright © 2016-2018 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.actors;
import org.thingsboard.server.common.data.id.SessionId;
public class DummySessionID implements SessionId {
@Override
public String toString() {
return id;
}
private final String id;
public DummySessionID(String id) {
this.id = id;
}
@Override
public String toUidStr() {
return id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DummySessionID other = (DummySessionID) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}

17
application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java

@ -16,6 +16,8 @@
package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.id.EntityId;
@ -25,12 +27,18 @@ 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.rule.RuleChainService;
import java.io.IOException;
/**
* Created by ashvayka on 20.03.18.
*/
public class AbstractRuleEngineControllerTest extends AbstractControllerTest {
@Autowired
protected RuleChainService ruleChainService;
protected RuleChain saveRuleChain(RuleChain ruleChain) throws Exception {
return doPost("/api/ruleChain", ruleChain, RuleChain.class);
}
@ -53,4 +61,13 @@ public class AbstractRuleEngineControllerTest extends AbstractControllerTest {
new TypeReference<TimePageData<Event>>() {
}, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG_RULE_NODE, tenantId.getId());
}
protected JsonNode getMetadata(Event outEvent) {
String metaDataStr = outEvent.getBody().get("metadata").asText();
try {
return mapper.readTree(metaDataStr);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

21
application/src/test/java/org/thingsboard/server/controller/BaseComponentDescriptorControllerTest.java

@ -20,6 +20,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.rule.engine.filter.TbJsFilterNode;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
@ -35,7 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public abstract class BaseComponentDescriptorControllerTest extends AbstractControllerTest {
private static final int AMOUNT_OF_DEFAULT_PLUGINS_DESCRIPTORS = 5;
private static final int AMOUNT_OF_DEFAULT_FILTER_NODES = 3;
private Tenant savedTenant;
private User tenantAdmin;
@ -69,38 +70,28 @@ public abstract class BaseComponentDescriptorControllerTest extends AbstractCont
@Test
public void testGetByClazz() throws Exception {
ComponentDescriptor descriptor =
doGet("/api/component/" + TelemetryStoragePlugin.class.getName(), ComponentDescriptor.class);
doGet("/api/component/" + TbJsFilterNode.class.getName(), ComponentDescriptor.class);
Assert.assertNotNull(descriptor);
Assert.assertNotNull(descriptor.getId());
Assert.assertNotNull(descriptor.getName());
Assert.assertEquals(ComponentScope.TENANT, descriptor.getScope());
Assert.assertEquals(ComponentType.PLUGIN, descriptor.getType());
Assert.assertEquals(ComponentType.FILTER, descriptor.getType());
Assert.assertEquals(descriptor.getClazz(), descriptor.getClazz());
}
@Test
public void testGetByType() throws Exception {
List<ComponentDescriptor> descriptors = readResponse(
doGet("/api/components/" + ComponentType.PLUGIN).andExpect(status().isOk()), new TypeReference<List<ComponentDescriptor>>() {
doGet("/api/components/" + ComponentType.FILTER).andExpect(status().isOk()), new TypeReference<List<ComponentDescriptor>>() {
});
Assert.assertNotNull(descriptors);
Assert.assertEquals(AMOUNT_OF_DEFAULT_PLUGINS_DESCRIPTORS, descriptors.size());
Assert.assertEquals(AMOUNT_OF_DEFAULT_FILTER_NODES, descriptors.size());
for (ComponentType type : ComponentType.values()) {
doGet("/api/components/" + type).andExpect(status().isOk());
}
}
@Test
public void testGetActionsByType() throws Exception {
List<ComponentDescriptor> descriptors = readResponse(
doGet("/api/components/actions/" + TelemetryStoragePlugin.class.getName()).andExpect(status().isOk()), new TypeReference<List<ComponentDescriptor>>() {
});
Assert.assertNotNull(descriptors);
Assert.assertEquals(1, descriptors.size());
Assert.assertEquals(TelemetryPluginAction.class.getName(), descriptors.get(0).getClazz());
}
}

232
application/src/test/java/org/thingsboard/server/controller/BasePluginControllerTest.java

@ -1,232 +0,0 @@
/**
* Copyright © 2016-2018 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.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.rule.RuleMetaData;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BasePluginControllerTest extends AbstractControllerTest {
private IdComparator<PluginMetaData> idComparator = new IdComparator<>();
private final ObjectMapper mapper = new ObjectMapper();
private Tenant savedTenant;
private User tenantAdmin;
@Before
public void beforeTest() throws Exception {
loginSysAdmin();
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
}
@After
public void afterTest() throws Exception {
loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk());
}
@Test
public void testSavePlugin() throws Exception {
PluginMetaData plugin = new PluginMetaData();
doPost("/api/plugin", plugin).andExpect(status().isBadRequest());
plugin.setName("My plugin");
doPost("/api/plugin", plugin).andExpect(status().isBadRequest());
plugin.setApiToken("myplugin");
doPost("/api/plugin", plugin).andExpect(status().isBadRequest());
plugin.setConfiguration(mapper.readTree("{}"));
doPost("/api/plugin", plugin).andExpect(status().isBadRequest());
plugin.setClazz(TelemetryStoragePlugin.class.getName());
PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class);
Assert.assertNotNull(savedPlugin);
Assert.assertNotNull(savedPlugin.getId());
Assert.assertTrue(savedPlugin.getCreatedTime() > 0);
Assert.assertEquals(savedTenant.getId(), savedPlugin.getTenantId());
}
@Test
public void testFindPluginById() throws Exception {
PluginMetaData plugin = new PluginMetaData();
plugin.setName("My plugin");
plugin.setApiToken("myplugin");
plugin.setConfiguration(mapper.readTree("{}"));
plugin.setClazz(TelemetryStoragePlugin.class.getName());
PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class);
PluginMetaData foundPlugin = doGet("/api/plugin/" + savedPlugin.getId().getId().toString(), PluginMetaData.class);
Assert.assertNotNull(foundPlugin);
Assert.assertEquals(savedPlugin, foundPlugin);
}
@Test
public void testActivatePlugin() throws Exception {
PluginMetaData plugin = new PluginMetaData();
plugin.setName("My plugin");
plugin.setApiToken("myplugin");
plugin.setConfiguration(mapper.readTree("{}"));
plugin.setClazz(TelemetryStoragePlugin.class.getName());
PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class);
doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk());
}
@Test
public void testSuspendPlugin() throws Exception {
PluginMetaData plugin = new PluginMetaData();
plugin.setName("My plugin");
plugin.setApiToken("myplugin");
plugin.setConfiguration(mapper.readTree("{}"));
plugin.setClazz(TelemetryStoragePlugin.class.getName());
PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class);
doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk());
RuleMetaData rule = BaseRuleControllerTest.createRuleMetaData(savedPlugin);
RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class);
doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isOk());
doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/suspend").andExpect(status().isBadRequest());
doPost("/api/rule/" + savedRule.getId().getId().toString() + "/suspend").andExpect(status().isOk());
doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/suspend").andExpect(status().isOk());
}
@Test
public void testDeletePluginById() throws Exception {
PluginMetaData plugin = new PluginMetaData();
plugin.setName("My plugin");
plugin.setApiToken("myplugin");
plugin.setConfiguration(mapper.readTree("{}"));
plugin.setClazz(TelemetryStoragePlugin.class.getName());
PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class);
RuleMetaData rule = BaseRuleControllerTest.createRuleMetaData(savedPlugin);
RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class);
doDelete("/api/plugin/" + savedPlugin.getId().getId()).andExpect(status().isBadRequest());
doDelete("/api/rule/" + savedRule.getId().getId()).andExpect(status().isOk());
doDelete("/api/plugin/" + savedPlugin.getId().getId()).andExpect(status().isOk());
doGet("/api/plugin/" + savedPlugin.getId().getId().toString()).andExpect(status().isNotFound());
}
@Test
public void testFindPluginByToken() throws Exception {
PluginMetaData plugin = new PluginMetaData();
plugin.setName("My plugin");
plugin.setApiToken("myplugin");
plugin.setConfiguration(mapper.readTree("{}"));
plugin.setClazz(TelemetryStoragePlugin.class.getName());
PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class);
PluginMetaData foundPlugin = doGet("/api/plugin/token/" + "myplugin", PluginMetaData.class);
Assert.assertNotNull(foundPlugin);
Assert.assertEquals(savedPlugin, foundPlugin);
}
@Test
public void testFindCurrentTenantPlugins() throws Exception {
List<PluginMetaData> plugins = testPluginsCreation("/api/plugin");
for (PluginMetaData plugin : plugins) {
doDelete("/api/plugin/" + plugin.getId().getId()).andExpect(status().isOk());
}
}
@Test
public void testFindSystemPlugins() throws Exception {
loginSysAdmin();
List<PluginMetaData> plugins = testPluginsCreation("/api/plugin/system");
for (PluginMetaData plugin : plugins) {
doDelete("/api/plugin/" + plugin.getId().getId()).andExpect(status().isOk());
}
}
private List<PluginMetaData> testPluginsCreation(String url) throws Exception {
List<PluginMetaData> plugins = new ArrayList<>();
for (int i = 0; i < 111; i++) {
PluginMetaData plugin = new PluginMetaData();
plugin.setName("My plugin");
plugin.setApiToken("myplugin" + i);
plugin.setConfiguration(mapper.readTree("{}"));
plugin.setClazz(TelemetryStoragePlugin.class.getName());
plugins.add(doPost("/api/plugin", plugin, PluginMetaData.class));
}
List<PluginMetaData> loadedPlugins = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(23);
TextPageData<PluginMetaData> pageData;
do {
pageData = doGetTypedWithPageLink(url + "?",
new TypeReference<TextPageData<PluginMetaData>>() {
}, pageLink);
loadedPlugins.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
loadedPlugins = loadedPlugins.stream()
.filter(p -> !p.getName().equals("System Telemetry Plugin"))
.filter(p -> !p.getName().equals("Mail Sender Plugin"))
.filter(p -> !p.getName().equals("System RPC Plugin"))
.collect(Collectors.toList());
Collections.sort(plugins, idComparator);
Collections.sort(loadedPlugins, idComparator);
Assert.assertEquals(plugins, loadedPlugins);
return loadedPlugins;
}
}

247
application/src/test/java/org/thingsboard/server/controller/BaseRuleControllerTest.java

@ -1,247 +0,0 @@
/**
* Copyright © 2016-2018 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.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.rule.RuleMetaData;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseRuleControllerTest extends AbstractControllerTest {
private IdComparator<RuleMetaData> idComparator = new IdComparator<>();
private static final ObjectMapper mapper = new ObjectMapper();
private Tenant savedTenant;
private User tenantAdmin;
private PluginMetaData sysPlugin;
private PluginMetaData tenantPlugin;
@Before
public void beforeTest() throws Exception {
loginSysAdmin();
sysPlugin = new PluginMetaData();
sysPlugin.setName("Sys plugin");
sysPlugin.setApiToken("sysplugin");
sysPlugin.setConfiguration(mapper.readTree("{}"));
sysPlugin.setClazz(TelemetryStoragePlugin.class.getName());
sysPlugin = doPost("/api/plugin", sysPlugin, PluginMetaData.class);
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
tenantPlugin = new PluginMetaData();
tenantPlugin.setName("My plugin");
tenantPlugin.setApiToken("myplugin");
tenantPlugin.setConfiguration(mapper.readTree("{}"));
tenantPlugin.setClazz(TelemetryStoragePlugin.class.getName());
tenantPlugin = doPost("/api/plugin", tenantPlugin, PluginMetaData.class);
}
@After
public void afterTest() throws Exception {
loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk());
doDelete("/api/plugin/" + sysPlugin.getId().getId()).andExpect(status().isOk());
}
@Test
public void testSaveRule() throws Exception {
RuleMetaData rule = new RuleMetaData();
doPost("/api/rule", rule).andExpect(status().isBadRequest());
rule.setName("My Rule");
doPost("/api/rule", rule).andExpect(status().isBadRequest());
rule.setPluginToken(tenantPlugin.getApiToken());
doPost("/api/rule", rule).andExpect(status().isBadRequest());
rule.setFilters(mapper.readTree("[{\"clazz\":\"org.thingsboard.server.extensions.core.filter.MsgTypeFilter\", " +
"\"name\":\"TelemetryFilter\", " +
"\"configuration\": {\"messageTypes\":[\"POST_TELEMETRY\",\"POST_ATTRIBUTES\",\"GET_ATTRIBUTES\"]}}]"));
doPost("/api/rule", rule).andExpect(status().isBadRequest());
rule.setAction(mapper.readTree("{\"clazz\":\"org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction\", \"name\":\"TelemetryMsgConverterAction\", \"configuration\":{\"timeUnit\":\"DAYS\", \"ttlValue\":1}}"));
RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class);
Assert.assertNotNull(savedRule);
Assert.assertNotNull(savedRule.getId());
Assert.assertTrue(savedRule.getCreatedTime() > 0);
Assert.assertEquals(savedTenant.getId(), savedRule.getTenantId());
}
@Test
public void testFindRuleById() throws Exception {
RuleMetaData rule = createRuleMetaData(tenantPlugin);
RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class);
RuleMetaData foundRule = doGet("/api/rule/" + savedRule.getId().getId().toString(), RuleMetaData.class);
Assert.assertNotNull(foundRule);
Assert.assertEquals(savedRule, foundRule);
}
@Test
public void testFindRuleByPluginToken() throws Exception {
RuleMetaData rule = createRuleMetaData(tenantPlugin);
RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class);
List<RuleMetaData> foundRules = doGetTyped("/api/rule/token/" + savedRule.getPluginToken(),
new TypeReference<List<RuleMetaData>>() {
});
Assert.assertNotNull(foundRules);
Assert.assertEquals(1, foundRules.size());
Assert.assertEquals(savedRule, foundRules.get(0));
}
@Test
public void testActivateRule() throws Exception {
RuleMetaData rule = createRuleMetaData(tenantPlugin);
RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class);
doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isBadRequest());
doPost("/api/plugin/" + tenantPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk());
doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isOk());
}
@Test
public void testSuspendRule() throws Exception {
RuleMetaData rule = createRuleMetaData(tenantPlugin);
RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class);
doPost("/api/plugin/" + tenantPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk());
doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isOk());
doPost("/api/rule/" + savedRule.getId().getId().toString() + "/suspend").andExpect(status().isOk());
}
@Test
public void testFindSystemRules() throws Exception {
loginSysAdmin();
List<RuleMetaData> rules = testRulesCreation("/api/rule/system", sysPlugin);
for (RuleMetaData rule : rules) {
doDelete("/api/rule/" + rule.getId().getId()).andExpect(status().isOk());
}
loginTenantAdmin();
}
@Test
public void testFindCurrentTenantPlugins() throws Exception {
List<RuleMetaData> rules = testRulesCreation("/api/rule", tenantPlugin);
for (RuleMetaData rule : rules) {
doDelete("/api/rule/" + rule.getId().getId()).andExpect(status().isOk());
}
}
@Test
public void testFindTenantPlugins() throws Exception {
List<RuleMetaData> rules = testRulesCreation("/api/rule", tenantPlugin);
loginSysAdmin();
List<RuleMetaData> loadedRules = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(3);
TextPageData<RuleMetaData> pageData;
do {
pageData = doGetTypedWithPageLink("/api/rule/tenant/" + savedTenant.getId().getId().toString() + "?",
new TypeReference<TextPageData<RuleMetaData>>() {
}, pageLink);
loadedRules.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
Collections.sort(rules, idComparator);
Collections.sort(loadedRules, idComparator);
Assert.assertEquals(rules, loadedRules);
for (RuleMetaData rule : rules) {
doDelete("/api/rule/" + rule.getId().getId()).andExpect(status().isOk());
}
}
private List<RuleMetaData> testRulesCreation(String url, PluginMetaData plugin) throws Exception {
List<RuleMetaData> rules = new ArrayList<>();
for (int i = 0; i < 6; i++) {
RuleMetaData rule = createRuleMetaData(plugin);
rule.setPluginToken(plugin.getApiToken());
rule.setName(rule.getName() + i);
rules.add(doPost("/api/rule", rule, RuleMetaData.class));
}
List<RuleMetaData> loadedRules = new ArrayList<>();
TextPageLink pageLink = new TextPageLink(3);
TextPageData<RuleMetaData> pageData;
do {
pageData = doGetTypedWithPageLink(url + "?",
new TypeReference<TextPageData<RuleMetaData>>() {
}, pageLink);
loadedRules.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageData.getNextPageLink();
}
} while (pageData.hasNext());
loadedRules = loadedRules.stream().filter(p -> !p.getName().equals("System Telemetry Rule")).collect(Collectors.toList());
Collections.sort(rules, idComparator);
Collections.sort(loadedRules, idComparator);
Assert.assertEquals(rules, loadedRules);
return loadedRules;
}
public static RuleMetaData createRuleMetaData(PluginMetaData plugin) throws IOException {
RuleMetaData rule = new RuleMetaData();
rule.setName("My Rule");
rule.setPluginToken(plugin.getApiToken());
rule.setFilters(mapper.readTree("[{\"clazz\":\"org.thingsboard.server.extensions.core.filter.MsgTypeFilter\", " +
"\"name\":\"TelemetryFilter\", " +
"\"configuration\": {\"messageTypes\":[\"POST_TELEMETRY\",\"POST_ATTRIBUTES\",\"GET_ATTRIBUTES\"]}}]"));
rule.setAction(mapper.readTree("{\"clazz\":\"org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction\", \"name\":\"TelemetryMsgConverterAction\", " +
"\"configuration\":{\"timeUnit\":\"DAYS\", \"ttlValue\":1}}"));
return rule;
}
}

26
application/src/test/java/org/thingsboard/server/controller/nosql/PluginControllerNoSqlTest.java

@ -1,26 +0,0 @@
/**
* Copyright © 2016-2018 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.controller.nosql;
import org.thingsboard.server.controller.BasePluginControllerTest;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
/**
* Created by Valerii Sosliuk on 6/28/2017.
*/
@DaoNoSqlTest
public class PluginControllerNoSqlTest extends BasePluginControllerTest {
}

26
application/src/test/java/org/thingsboard/server/controller/nosql/RuleControllerNoSqlTest.java

@ -1,26 +0,0 @@
/**
* Copyright © 2016-2018 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.controller.nosql;
import org.thingsboard.server.controller.BaseRuleControllerTest;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
/**
* Created by Valerii Sosliuk on 6/28/2017.
*/
@DaoNoSqlTest
public class RuleControllerNoSqlTest extends BaseRuleControllerTest {
}

26
application/src/test/java/org/thingsboard/server/controller/sql/PluginControllerSqlTest.java

@ -1,26 +0,0 @@
/**
* Copyright © 2016-2018 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.controller.sql;
import org.thingsboard.server.controller.BasePluginControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
/**
* Created by Valerii Sosliuk on 6/28/2017.
*/
@DaoSqlTest
public class PluginControllerSqlTest extends BasePluginControllerTest {
}

26
application/src/test/java/org/thingsboard/server/controller/sql/RuleControllerSqlTest.java

@ -1,26 +0,0 @@
/**
* Copyright © 2016-2018 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.controller.sql;
import org.thingsboard.server.controller.BaseRuleControllerTest;
import org.thingsboard.server.dao.service.DaoSqlTest;
/**
* Created by Valerii Sosliuk on 6/28/2017.
*/
@DaoSqlTest
public class RuleControllerSqlTest extends BaseRuleControllerTest {
}

2
application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java

@ -80,6 +80,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
}
}
@Ignore
@Test
public void testServerMqttOneWayRpc() throws Exception {
Device device = new Device();
@ -106,6 +107,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
Assert.assertTrue(StringUtils.isEmpty(result));
}
@Ignore
@Test
public void testServerMqttOneWayRpcDeviceOffline() throws Exception {
Device device = new Device();

3
application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java

@ -24,7 +24,8 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({
"org.thingsboard.server.rules.flow.*Test"})
"org.thingsboard.server.rules.flow.*Test",
"org.thingsboard.server.rules.lifecycle.*Test"})
public class RuleEngineSqlTestSuite {
@ClassRule

13
application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java

@ -16,6 +16,7 @@
package org.thingsboard.server.rules.flow;
import com.datastax.driver.core.utils.UUIDs;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
@ -28,6 +29,7 @@ import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
@ -40,6 +42,7 @@ import org.thingsboard.server.controller.AbstractRuleEngineControllerTest;
import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.rule.RuleChainService;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
@ -60,9 +63,6 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
@Autowired
protected AttributesService attributesService;
@Autowired
protected RuleChainService ruleChainService;
@Before
public void beforeTest() throws Exception {
loginSysAdmin();
@ -71,6 +71,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
ruleChainService.deleteRuleChainsByTenantId(savedTenant.getId());
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
@ -166,7 +167,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
Assert.assertEquals(ruleChain.getFirstRuleNodeId(), outEvent.getEntityId());
Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText());
Assert.assertEquals("serverAttributeValue1", outEvent.getBody().get("metadata").get("ss.serverAttributeKey1").asText());
Assert.assertEquals("serverAttributeValue1", getMetadata(outEvent).get("ss_serverAttributeKey1").asText());
RuleChain finalRuleChain = ruleChain;
RuleNode lastRuleNode = metaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get();
@ -183,8 +184,8 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
Assert.assertEquals(lastRuleNode.getId(), outEvent.getEntityId());
Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText());
Assert.assertEquals("serverAttributeValue1", outEvent.getBody().get("metadata").get("ss.serverAttributeKey1").asText());
Assert.assertEquals("serverAttributeValue2", outEvent.getBody().get("metadata").get("ss.serverAttributeKey2").asText());
Assert.assertEquals("serverAttributeValue1", getMetadata(outEvent).get("ss_serverAttributeKey1").asText());
Assert.assertEquals("serverAttributeValue2", getMetadata(outEvent).get("ss_serverAttributeKey2").asText());
}
}

5
application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java

@ -16,6 +16,7 @@
package org.thingsboard.server.rules.lifecycle;
import com.datastax.driver.core.utils.UUIDs;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Assert;
@ -42,6 +43,7 @@ import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.controller.AbstractRuleEngineControllerTest;
import org.thingsboard.server.dao.attributes.AttributesService;
import java.io.IOException;
import java.util.Collections;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -69,6 +71,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
ruleChainService.deleteRuleChainsByTenantId(savedTenant.getId());
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
@ -152,7 +155,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
Assert.assertEquals(ruleChain.getFirstRuleNodeId(), outEvent.getEntityId());
Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText());
Assert.assertEquals("serverAttributeValue", outEvent.getBody().get("metadata").get("ss.serverAttributeKey").asText());
Assert.assertEquals("serverAttributeValue", getMetadata(outEvent).get("ss_serverAttributeKey").asText());
}
}

1
application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java

@ -35,5 +35,4 @@ public class SystemSqlTestSuite {
"sql/drop-all-tables.sql",
"sql-test.properties");
}

2
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/rpc/cmd/RpcRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/rpc/RpcRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.extensions.core.plugin.rpc.cmd;
package org.thingsboard.server.common.data.rpc;
import lombok.Data;

2
extensions-api/src/main/java/org/thingsboard/server/extensions/api/plugins/msg/ToDeviceRpcRequestBody.java → common/data/src/main/java/org/thingsboard/server/common/data/rpc/ToDeviceRpcRequestBody.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.extensions.api.plugins.msg;
package org.thingsboard.server.common.data.rpc;
import lombok.Data;

4
common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java

@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
@ -32,6 +33,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
private static final long serialVersionUID = -5656679015121235465L;
private RuleChainId ruleChainId;
private String type;
private String name;
private boolean debugMode;
@ -49,8 +51,10 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
public RuleNode(RuleNode ruleNode) {
super(ruleNode);
this.ruleChainId = ruleNode.getRuleChainId();
this.type = ruleNode.getType();
this.name = ruleNode.getName();
this.debugMode = ruleNode.isDebugMode();
this.setConfiguration(ruleNode.getConfiguration());
}

44
common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java

@ -18,27 +18,30 @@ package org.thingsboard.server.common.msg;
/**
* Created by ashvayka on 15.03.18.
*/
//TODO: add all "See" references
public enum MsgType {
/**
* ADDED/UPDATED/DELETED events for server nodes.
*
* See {@link org.thingsboard.server.common.msg.cluster.ClusterEventMsg}
*/
CLUSTER_EVENT_MSG,
/**
* ADDED/UPDATED/DELETED events for main entities.
*
* @See {@link org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg}
* See {@link org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg}
*/
COMPONENT_LIFE_CYCLE_MSG,
/**
* Misc messages from the REST API/SERVICE layer to the new rule engine.
*
* @See {@link org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg}
* See {@link org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg}
*/
SERVICE_TO_RULE_ENGINE_MSG,
SESSION_TO_DEVICE_ACTOR_MSG,
DEVICE_ACTOR_TO_SESSION_MSG,
/**
* Message that is sent by RuleChainActor to RuleActor with command to process TbMsg.
*/
@ -59,4 +62,31 @@ public enum MsgType {
*/
RULE_TO_SELF_MSG,
/**
* Message that is sent by Session Actor to Device Actor. Represents messages from the device itself.
*/
DEVICE_SESSION_TO_DEVICE_ACTOR_MSG,
DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG,
DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG,
DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG,
DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG,
DEVICE_ACTOR_RPC_TIMEOUT_MSG,
DEVICE_ACTOR_QUEUE_TIMEOUT_MSG,
/**
* Message that is sent from the Device Actor to Rule Engine. Requires acknowledgement
*/
DEVICE_ACTOR_TO_RULE_ENGINE_MSG,
/**
* Message that is sent from Rule Engine to the Device Actor when message is successfully pushed to queue.
*/
RULE_ENGINE_QUEUE_PUT_ACK_MSG;
}

4
common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java

@ -31,10 +31,10 @@ import java.util.concurrent.ConcurrentHashMap;
@NoArgsConstructor
public final class TbMsgMetaData implements Serializable {
private Map<String, String> data = new ConcurrentHashMap<>();
private final Map<String, String> data = new ConcurrentHashMap<>();
public TbMsgMetaData(Map<String, String> data) {
this.data = data;
this.data.putAll(data);
}
public String getValue(String key) {

8
common/message/src/main/java/org/thingsboard/server/common/msg/cluster/ClusterEventMsg.java

@ -16,14 +16,20 @@
package org.thingsboard.server.common.msg.cluster;
import lombok.Data;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.TbActorMsg;
/**
* @author Andrew Shvayka
*/
@Data
public final class ClusterEventMsg {
public final class ClusterEventMsg implements TbActorMsg {
private final ServerAddress serverAddress;
private final boolean added;
@Override
public MsgType getMsgType() {
return MsgType.CLUSTER_EVENT_MSG;
}
}

6
common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesSubscribeMsg.java

@ -16,14 +16,14 @@
package org.thingsboard.server.common.msg.core;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
*/
public class AttributesSubscribeMsg implements FromDeviceMsg {
@Override
public MsgType getMsgType() {
return MsgType.SUBSCRIBE_ATTRIBUTES_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST;
}
}

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesUnsubscribeMsg.java

@ -16,14 +16,15 @@
package org.thingsboard.server.common.msg.core;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
*/
public class AttributesUnsubscribeMsg implements FromDeviceMsg {
@Override
public MsgType getMsgType() {
return MsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST;
}
}

8
common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesUpdateNotification.java

@ -17,7 +17,8 @@ package org.thingsboard.server.common.msg.core;
import lombok.ToString;
import org.thingsboard.server.common.msg.kv.AttributesKVMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
@ToString
@ -36,9 +37,8 @@ public class AttributesUpdateNotification implements ToDeviceMsg {
return true;
}
@Override
public MsgType getMsgType() {
return MsgType.ATTRIBUTES_UPDATE_NOTIFICATION;
public SessionMsgType getSessionMsgType() {
return SessionMsgType.ATTRIBUTES_UPDATE_NOTIFICATION;
}
public AttributesKVMsg getData() {

2
common/message/src/main/java/org/thingsboard/server/common/msg/core/UpdateAttributesRequest.java → common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesUpdateRequest.java

@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg;
public interface UpdateAttributesRequest extends FromDeviceRequestMsg {
public interface AttributesUpdateRequest extends FromDeviceRequestMsg {
Set<AttributeKvEntry> getAttributes();

14
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicUpdateAttributesRequest.java → common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicAttributesUpdateRequest.java

@ -20,19 +20,19 @@ import java.util.LinkedHashSet;
import java.util.Set;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
public class BasicUpdateAttributesRequest extends BasicRequest implements UpdateAttributesRequest {
public class BasicAttributesUpdateRequest extends BasicRequest implements AttributesUpdateRequest {
private static final long serialVersionUID = 1L;
private final Set<AttributeKvEntry> data;
public BasicUpdateAttributesRequest() {
public BasicAttributesUpdateRequest() {
this(DEFAULT_REQUEST_ID);
}
public BasicUpdateAttributesRequest(Integer requestId) {
public BasicAttributesUpdateRequest(Integer requestId) {
super(requestId);
this.data = new LinkedHashSet<>();
}
@ -46,8 +46,8 @@ public class BasicUpdateAttributesRequest extends BasicRequest implements Update
}
@Override
public MsgType getMsgType() {
return MsgType.POST_ATTRIBUTES_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.POST_ATTRIBUTES_REQUEST;
}
@Override
@ -57,7 +57,7 @@ public class BasicUpdateAttributesRequest extends BasicRequest implements Update
@Override
public String toString() {
return "BasicUpdateAttributesRequest [data=" + data + "]";
return "BasicAttributesUpdateRequest [data=" + data + "]";
}
}

13
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicCommandAckResponse.java

@ -15,26 +15,27 @@
*/
package org.thingsboard.server.common.msg.core;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
public class BasicCommandAckResponse extends BasicResponseMsg<Integer> implements StatusCodeResponse {
private static final long serialVersionUID = 1L;
public static BasicCommandAckResponse onSuccess(MsgType requestMsgType, Integer requestId) {
public static BasicCommandAckResponse onSuccess(SessionMsgType requestMsgType, Integer requestId) {
return BasicCommandAckResponse.onSuccess(requestMsgType, requestId, 200);
}
public static BasicCommandAckResponse onSuccess(MsgType requestMsgType, Integer requestId, Integer code) {
public static BasicCommandAckResponse onSuccess(SessionMsgType requestMsgType, Integer requestId, Integer code) {
return new BasicCommandAckResponse(requestMsgType, requestId, true, null, code);
}
public static BasicCommandAckResponse onError(MsgType requestMsgType, Integer requestId, Exception error) {
public static BasicCommandAckResponse onError(SessionMsgType requestMsgType, Integer requestId, Exception error) {
return new BasicCommandAckResponse(requestMsgType, requestId, false, error, null);
}
private BasicCommandAckResponse(MsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) {
super(requestMsgType, requestId, MsgType.TO_DEVICE_RPC_RESPONSE_ACK, success, error, code);
private BasicCommandAckResponse(SessionMsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) {
super(requestMsgType, requestId, SessionMsgType.TO_DEVICE_RPC_RESPONSE_ACK, success, error, code);
}
@Override

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicGetAttributesRequest.java

@ -16,7 +16,8 @@
package org.thingsboard.server.common.msg.core;
import lombok.ToString;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import java.util.Collections;
import java.util.Optional;
@ -41,8 +42,8 @@ public class BasicGetAttributesRequest extends BasicRequest implements GetAttrib
}
@Override
public MsgType getMsgType() {
return MsgType.GET_ATTRIBUTES_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.GET_ATTRIBUTES_REQUEST;
}
@Override

11
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicGetAttributesResponse.java

@ -17,23 +17,24 @@ package org.thingsboard.server.common.msg.core;
import lombok.ToString;
import org.thingsboard.server.common.msg.kv.AttributesKVMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@ToString
public class BasicGetAttributesResponse extends BasicResponseMsg<AttributesKVMsg> implements GetAttributesResponse {
private static final long serialVersionUID = 1L;
public static BasicGetAttributesResponse onSuccess(MsgType requestMsgType, int requestId, AttributesKVMsg code) {
public static BasicGetAttributesResponse onSuccess(SessionMsgType requestMsgType, int requestId, AttributesKVMsg code) {
return new BasicGetAttributesResponse(requestMsgType, requestId, true, null, code);
}
public static BasicGetAttributesResponse onError(MsgType requestMsgType, int requestId, Exception error) {
public static BasicGetAttributesResponse onError(SessionMsgType requestMsgType, int requestId, Exception error) {
return new BasicGetAttributesResponse(requestMsgType, requestId, false, error, null);
}
private BasicGetAttributesResponse(MsgType requestMsgType, int requestId, boolean success, Exception error, AttributesKVMsg code) {
super(requestMsgType, requestId, MsgType.GET_ATTRIBUTES_RESPONSE, success, error, code);
private BasicGetAttributesResponse(SessionMsgType requestMsgType, int requestId, boolean success, Exception error, AttributesKVMsg code) {
super(requestMsgType, requestId, SessionMsgType.GET_ATTRIBUTES_RESPONSE, success, error, code);
}
}

18
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicResponseMsg.java

@ -18,32 +18,33 @@ package org.thingsboard.server.common.msg.core;
import java.io.Serializable;
import java.util.Optional;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
public class BasicResponseMsg<T extends Serializable> implements ResponseMsg<T> {
private static final long serialVersionUID = 1L;
private final MsgType requestMsgType;
private final SessionMsgType requestMsgType;
private final Integer requestId;
private final MsgType msgType;
private final SessionMsgType sessionMsgType;
private final boolean success;
private final T data;
private final Exception error;
protected BasicResponseMsg(MsgType requestMsgType, Integer requestId, MsgType msgType, boolean success, Exception error, T data) {
protected BasicResponseMsg(SessionMsgType requestMsgType, Integer requestId, SessionMsgType sessionMsgType, boolean success, Exception error, T data) {
super();
this.requestMsgType = requestMsgType;
this.requestId = requestId;
this.msgType = msgType;
this.sessionMsgType = sessionMsgType;
this.success = success;
this.error = error;
this.data = data;
}
@Override
public MsgType getRequestMsgType() {
public SessionMsgType getRequestMsgType() {
return requestMsgType;
}
@ -72,8 +73,7 @@ public class BasicResponseMsg<T extends Serializable> implements ResponseMsg<T>
return "BasicResponseMsg [success=" + success + ", data=" + data + ", error=" + error + "]";
}
@Override
public MsgType getMsgType() {
return msgType;
public SessionMsgType getSessionMsgType() {
return sessionMsgType;
}
}

13
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicStatusCodeResponse.java

@ -16,26 +16,27 @@
package org.thingsboard.server.common.msg.core;
import lombok.ToString;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@ToString
public class BasicStatusCodeResponse extends BasicResponseMsg<Integer> implements StatusCodeResponse {
private static final long serialVersionUID = 1L;
public static BasicStatusCodeResponse onSuccess(MsgType requestMsgType, Integer requestId) {
public static BasicStatusCodeResponse onSuccess(SessionMsgType requestMsgType, Integer requestId) {
return BasicStatusCodeResponse.onSuccess(requestMsgType, requestId, 0);
}
public static BasicStatusCodeResponse onSuccess(MsgType requestMsgType, Integer requestId, Integer code) {
public static BasicStatusCodeResponse onSuccess(SessionMsgType requestMsgType, Integer requestId, Integer code) {
return new BasicStatusCodeResponse(requestMsgType, requestId, true, null, code);
}
public static BasicStatusCodeResponse onError(MsgType requestMsgType, Integer requestId, Exception error) {
public static BasicStatusCodeResponse onError(SessionMsgType requestMsgType, Integer requestId, Exception error) {
return new BasicStatusCodeResponse(requestMsgType, requestId, false, error, null);
}
private BasicStatusCodeResponse(MsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) {
super(requestMsgType, requestId, MsgType.STATUS_CODE_RESPONSE, success, error, code);
private BasicStatusCodeResponse(SessionMsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) {
super(requestMsgType, requestId, SessionMsgType.STATUS_CODE_RESPONSE, success, error, code);
}
}

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicTelemetryUploadRequest.java

@ -21,7 +21,8 @@ import java.util.List;
import java.util.Map;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
public class BasicTelemetryUploadRequest extends BasicRequest implements TelemetryUploadRequest {
@ -48,8 +49,8 @@ public class BasicTelemetryUploadRequest extends BasicRequest implements Telemet
}
@Override
public MsgType getMsgType() {
return MsgType.POST_TELEMETRY_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.POST_TELEMETRY_REQUEST;
}
@Override

4
common/message/src/main/java/org/thingsboard/server/common/msg/core/ResponseMsg.java

@ -18,12 +18,12 @@ package org.thingsboard.server.common.msg.core;
import java.io.Serializable;
import java.util.Optional;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
public interface ResponseMsg<T extends Serializable> extends ToDeviceMsg {
MsgType getRequestMsgType();
SessionMsgType getRequestMsgType();
Integer getRequestId();

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/RpcSubscribeMsg.java

@ -16,14 +16,15 @@
package org.thingsboard.server.common.msg.core;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
*/
public class RpcSubscribeMsg implements FromDeviceMsg {
@Override
public MsgType getMsgType() {
return MsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST;
}
}

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/RpcUnsubscribeMsg.java

@ -16,14 +16,15 @@
package org.thingsboard.server.common.msg.core;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
*/
public class RpcUnsubscribeMsg implements FromDeviceMsg {
@Override
public MsgType getMsgType() {
return MsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST;
}
}

2
common/message/src/main/java/org/thingsboard/server/common/msg/core/RuleEngineError.java

@ -21,7 +21,7 @@ package org.thingsboard.server.common.msg.core;
public enum RuleEngineError {
NO_RULES, NO_ACTIVE_RULES, NO_FILTERS_MATCHED, NO_REQUEST_FROM_ACTIONS, NO_TWO_WAY_ACTIONS, NO_RESPONSE_FROM_ACTIONS, PLUGIN_TIMEOUT(true);
QUEUE_PUT_TIMEOUT(true), SERVER_ERROR(true);
private final boolean critical;

28
common/message/src/main/java/org/thingsboard/server/common/msg/core/RuleEngineErrorMsg.java

@ -16,7 +16,8 @@
package org.thingsboard.server.common.msg.core;
import lombok.Data;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
/**
@ -25,7 +26,7 @@ import org.thingsboard.server.common.msg.session.ToDeviceMsg;
@Data
public class RuleEngineErrorMsg implements ToDeviceMsg {
private final MsgType inMsgType;
private final SessionMsgType inSessionMsgType;
private final RuleEngineError error;
@Override
@ -33,27 +34,16 @@ public class RuleEngineErrorMsg implements ToDeviceMsg {
return false;
}
@Override
public MsgType getMsgType() {
return MsgType.RULE_ENGINE_ERROR;
public SessionMsgType getSessionMsgType() {
return SessionMsgType.RULE_ENGINE_ERROR;
}
public String getErrorMsg() {
switch (error) {
case NO_RULES:
return "No rules configured!";
case NO_ACTIVE_RULES:
return "No active rules!";
case NO_FILTERS_MATCHED:
return "No rules that match current message!";
case NO_REQUEST_FROM_ACTIONS:
return "Rule filters match, but no plugin message produced by rule action!";
case NO_TWO_WAY_ACTIONS:
return "Rule filters match, but no rule with two-way action configured!";
case NO_RESPONSE_FROM_ACTIONS:
return "Rule filters match, message processed by plugin, but no response produced by rule action!";
case PLUGIN_TIMEOUT:
return "Timeout during processing of message by plugin!";
case QUEUE_PUT_TIMEOUT:
return "Timeout during persistence of the message to the queue!";
case SERVER_ERROR:
return "Error during processing of message by the server!";
default:
throw new RuntimeException("Error " + error + " is not supported!");
}

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/SessionCloseMsg.java

@ -16,14 +16,15 @@
package org.thingsboard.server.common.msg.core;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
*/
public class SessionCloseMsg implements FromDeviceMsg {
@Override
public MsgType getMsgType() {
return MsgType.SESSION_CLOSE;
public SessionMsgType getMsgType() {
return SessionMsgType.SESSION_CLOSE;
}
}

8
common/message/src/main/java/org/thingsboard/server/common/msg/core/SessionCloseNotification.java

@ -17,7 +17,8 @@ package org.thingsboard.server.common.msg.core;
import lombok.ToString;
import org.thingsboard.server.common.msg.kv.AttributesKVMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
@ToString
@ -30,9 +31,8 @@ public class SessionCloseNotification implements ToDeviceMsg {
return true;
}
@Override
public MsgType getMsgType() {
return MsgType.SESSION_CLOSE;
public SessionMsgType getSessionMsgType() {
return SessionMsgType.SESSION_CLOSE;
}
}

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/SessionOpenMsg.java

@ -16,14 +16,15 @@
package org.thingsboard.server.common.msg.core;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
*/
public class SessionOpenMsg implements FromDeviceMsg {
@Override
public MsgType getMsgType() {
return MsgType.SESSION_OPEN;
public SessionMsgType getMsgType() {
return SessionMsgType.SESSION_OPEN;
}
}

8
common/message/src/main/java/org/thingsboard/server/common/msg/core/ToDeviceRpcRequestMsg.java

@ -16,7 +16,8 @@
package org.thingsboard.server.common.msg.core;
import lombok.Data;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
/**
@ -29,9 +30,8 @@ public class ToDeviceRpcRequestMsg implements ToDeviceMsg {
private final String method;
private final String params;
@Override
public MsgType getMsgType() {
return MsgType.TO_DEVICE_RPC_REQUEST;
public SessionMsgType getSessionMsgType() {
return SessionMsgType.TO_DEVICE_RPC_REQUEST;
}
@Override

7
common/message/src/main/java/org/thingsboard/server/common/msg/core/ToDeviceRpcResponseMsg.java

@ -17,7 +17,8 @@ package org.thingsboard.server.common.msg.core;
import lombok.Data;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
@ -29,7 +30,7 @@ public class ToDeviceRpcResponseMsg implements FromDeviceMsg {
private final String data;
@Override
public MsgType getMsgType() {
return MsgType.TO_DEVICE_RPC_RESPONSE;
public SessionMsgType getMsgType() {
return SessionMsgType.TO_DEVICE_RPC_RESPONSE;
}
}

6
common/message/src/main/java/org/thingsboard/server/common/msg/core/ToServerRpcRequestMsg.java

@ -17,7 +17,7 @@ package org.thingsboard.server.common.msg.core;
import lombok.Data;
import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
/**
* @author Andrew Shvayka
@ -30,7 +30,7 @@ public class ToServerRpcRequestMsg implements FromDeviceRequestMsg {
private final String params;
@Override
public MsgType getMsgType() {
return MsgType.TO_SERVER_RPC_REQUEST;
public SessionMsgType getMsgType() {
return SessionMsgType.TO_SERVER_RPC_REQUEST;
}
}

8
common/message/src/main/java/org/thingsboard/server/common/msg/core/ToServerRpcResponseMsg.java

@ -17,7 +17,8 @@ package org.thingsboard.server.common.msg.core;
import lombok.Data;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
/**
@ -29,9 +30,8 @@ public class ToServerRpcResponseMsg implements ToDeviceMsg {
private final int requestId;
private final String data;
@Override
public MsgType getMsgType() {
return MsgType.TO_SERVER_RPC_RESPONSE;
public SessionMsgType getSessionMsgType() {
return SessionMsgType.TO_SERVER_RPC_RESPONSE;
}
@Override

20
common/message/src/main/java/org/thingsboard/server/common/msg/device/BasicToDeviceActorMsg.java → common/message/src/main/java/org/thingsboard/server/common/msg/device/BasicDeviceToDeviceActorMsg.java

@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.MsgType;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.SessionType;
@ -28,7 +29,7 @@ import org.thingsboard.server.common.msg.session.ToDeviceActorSessionMsg;
import java.util.Optional;
@ToString
public class BasicToDeviceActorMsg implements ToDeviceActorMsg {
public class BasicDeviceToDeviceActorMsg implements DeviceToDeviceActorMsg {
private static final long serialVersionUID = -1866795134993115408L;
@ -40,16 +41,16 @@ public class BasicToDeviceActorMsg implements ToDeviceActorMsg {
private final ServerAddress serverAddress;
private final FromDeviceMsg msg;
public BasicToDeviceActorMsg(ToDeviceActorMsg other, FromDeviceMsg msg) {
public BasicDeviceToDeviceActorMsg(DeviceToDeviceActorMsg other, FromDeviceMsg msg) {
this(null, other.getTenantId(), other.getCustomerId(), other.getDeviceId(), other.getSessionId(), other.getSessionType(), msg);
}
public BasicToDeviceActorMsg(ToDeviceActorSessionMsg msg, SessionType sessionType) {
public BasicDeviceToDeviceActorMsg(ToDeviceActorSessionMsg msg, SessionType sessionType) {
this(null, msg.getTenantId(), msg.getCustomerId(), msg.getDeviceId(), msg.getSessionId(), sessionType, msg.getSessionMsg().getMsg());
}
private BasicToDeviceActorMsg(ServerAddress serverAddress, TenantId tenantId, CustomerId customerId, DeviceId deviceId, SessionId sessionId, SessionType sessionType,
FromDeviceMsg msg) {
private BasicDeviceToDeviceActorMsg(ServerAddress serverAddress, TenantId tenantId, CustomerId customerId, DeviceId deviceId, SessionId sessionId, SessionType sessionType,
FromDeviceMsg msg) {
super();
this.serverAddress = serverAddress;
this.tenantId = tenantId;
@ -95,7 +96,12 @@ public class BasicToDeviceActorMsg implements ToDeviceActorMsg {
}
@Override
public ToDeviceActorMsg toOtherAddress(ServerAddress otherAddress) {
return new BasicToDeviceActorMsg(otherAddress, tenantId, customerId, deviceId, sessionId, sessionType, msg);
public DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress) {
return new BasicDeviceToDeviceActorMsg(otherAddress, tenantId, customerId, deviceId, sessionId, sessionType, msg);
}
@Override
public MsgType getMsgType() {
return MsgType.DEVICE_SESSION_TO_DEVICE_ACTOR_MSG;
}
}

5
common/message/src/main/java/org/thingsboard/server/common/msg/device/ToDeviceActorMsg.java → common/message/src/main/java/org/thingsboard/server/common/msg/device/DeviceToDeviceActorMsg.java

@ -19,6 +19,7 @@ import java.io.Serializable;
import java.util.Optional;
import org.thingsboard.server.common.data.id.SessionId;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.aware.CustomerAwareMsg;
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
@ -26,7 +27,7 @@ import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.SessionType;
public interface ToDeviceActorMsg extends DeviceAwareMsg, CustomerAwareMsg, TenantAwareMsg, Serializable {
public interface DeviceToDeviceActorMsg extends TbActorMsg, DeviceAwareMsg, CustomerAwareMsg, TenantAwareMsg, Serializable {
SessionId getSessionId();
@ -36,5 +37,5 @@ public interface ToDeviceActorMsg extends DeviceAwareMsg, CustomerAwareMsg, Tena
FromDeviceMsg getPayload();
ToDeviceActorMsg toOtherAddress(ServerAddress otherAddress);
DeviceToDeviceActorMsg toOtherAddress(ServerAddress otherAddress);
}

5
extensions-api/src/main/java/org/thingsboard/server/extensions/api/plugins/msg/ToDeviceRpcRequest.java → common/message/src/main/java/org/thingsboard/server/common/msg/rpc/ToDeviceRpcRequest.java

@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.extensions.api.plugins.msg;
package org.thingsboard.server.common.msg.rpc;
import lombok.Data;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext;
import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
import java.io.Serializable;
import java.util.UUID;
@ -29,7 +29,6 @@ import java.util.UUID;
@Data
public class ToDeviceRpcRequest implements Serializable {
private final UUID id;
private final PluginApiCallSecurityContext securityCtx;
private final TenantId tenantId;
private final DeviceId deviceId;
private final boolean oneway;

2
common/message/src/main/java/org/thingsboard/server/common/msg/session/FromDeviceMsg.java

@ -19,6 +19,6 @@ import java.io.Serializable;
public interface FromDeviceMsg extends Serializable {
MsgType getMsgType();
SessionMsgType getMsgType();
}

6
common/message/src/main/java/org/thingsboard/server/common/msg/session/MsgType.java → common/message/src/main/java/org/thingsboard/server/common/msg/session/SessionMsgType.java

@ -15,7 +15,7 @@
*/
package org.thingsboard.server.common.msg.session;
public enum MsgType {
public enum SessionMsgType {
GET_ATTRIBUTES_REQUEST(true), POST_ATTRIBUTES_REQUEST(true), GET_ATTRIBUTES_RESPONSE,
SUBSCRIBE_ATTRIBUTES_REQUEST, UNSUBSCRIBE_ATTRIBUTES_REQUEST, ATTRIBUTES_UPDATE_NOTIFICATION,
@ -32,11 +32,11 @@ public enum MsgType {
private final boolean requiresRulesProcessing;
MsgType() {
SessionMsgType() {
this(false);
}
MsgType(boolean requiresRulesProcessing) {
SessionMsgType(boolean requiresRulesProcessing) {
this.requiresRulesProcessing = requiresRulesProcessing;
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save