Commit 9fce3e068e448d4da34b3f6307432a363ae0fd8d
Committed by
GitHub
Merge pull request #794 from thingsboard/develop/2.0
TB 2.0 merged to master
Showing
43 changed files
with
1386 additions
and
2741 deletions
Too many changes to show.
To preserve performance only 43 of 931 files are displayed.
@@ -20,10 +20,9 @@ | @@ -20,10 +20,9 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>1.4.1-SNAPSHOT</version> | 23 | + <version>2.0.0-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | - <groupId>org.thingsboard</groupId> | ||
27 | <artifactId>application</artifactId> | 26 | <artifactId>application</artifactId> |
28 | <packaging>jar</packaging> | 27 | <packaging>jar</packaging> |
29 | 28 | ||
@@ -50,12 +49,12 @@ | @@ -50,12 +49,12 @@ | ||
50 | <classifier>linux-x86_64</classifier> | 49 | <classifier>linux-x86_64</classifier> |
51 | </dependency> | 50 | </dependency> |
52 | <dependency> | 51 | <dependency> |
53 | - <groupId>org.thingsboard</groupId> | ||
54 | - <artifactId>extensions-api</artifactId> | 52 | + <groupId>org.thingsboard.rule-engine</groupId> |
53 | + <artifactId>rule-engine-api</artifactId> | ||
55 | </dependency> | 54 | </dependency> |
56 | <dependency> | 55 | <dependency> |
57 | - <groupId>org.thingsboard</groupId> | ||
58 | - <artifactId>extensions-core</artifactId> | 56 | + <groupId>org.thingsboard.rule-engine</groupId> |
57 | + <artifactId>rule-engine-components</artifactId> | ||
59 | </dependency> | 58 | </dependency> |
60 | <dependency> | 59 | <dependency> |
61 | <groupId>org.thingsboard.common</groupId> | 60 | <groupId>org.thingsboard.common</groupId> |
@@ -257,6 +256,10 @@ | @@ -257,6 +256,10 @@ | ||
257 | <groupId>org.hsqldb</groupId> | 256 | <groupId>org.hsqldb</groupId> |
258 | <artifactId>hsqldb</artifactId> | 257 | <artifactId>hsqldb</artifactId> |
259 | </dependency> | 258 | </dependency> |
259 | + <dependency> | ||
260 | + <groupId>org.javadelight</groupId> | ||
261 | + <artifactId>delight-nashorn-sandbox</artifactId> | ||
262 | + </dependency> | ||
260 | </dependencies> | 263 | </dependencies> |
261 | 264 | ||
262 | <build> | 265 | <build> |
@@ -464,48 +467,6 @@ | @@ -464,48 +467,6 @@ | ||
464 | <artifactId>maven-dependency-plugin</artifactId> | 467 | <artifactId>maven-dependency-plugin</artifactId> |
465 | <executions> | 468 | <executions> |
466 | <execution> | 469 | <execution> |
467 | - <id>copy-extensions</id> | ||
468 | - <phase>package</phase> | ||
469 | - <goals> | ||
470 | - <goal>copy</goal> | ||
471 | - </goals> | ||
472 | - <configuration> | ||
473 | - <outputDirectory>${project.build.directory}/extensions</outputDirectory> | ||
474 | - <artifactItems> | ||
475 | - <artifactItem> | ||
476 | - <groupId>org.thingsboard.extensions</groupId> | ||
477 | - <artifactId>extension-rabbitmq</artifactId> | ||
478 | - <classifier>extension</classifier> | ||
479 | - </artifactItem> | ||
480 | - <artifactItem> | ||
481 | - <groupId>org.thingsboard.extensions</groupId> | ||
482 | - <artifactId>extension-rest-api-call</artifactId> | ||
483 | - <classifier>extension</classifier> | ||
484 | - </artifactItem> | ||
485 | - <artifactItem> | ||
486 | - <groupId>org.thingsboard.extensions</groupId> | ||
487 | - <artifactId>extension-kafka</artifactId> | ||
488 | - <classifier>extension</classifier> | ||
489 | - </artifactItem> | ||
490 | - <artifactItem> | ||
491 | - <groupId>org.thingsboard.extensions</groupId> | ||
492 | - <artifactId>extension-mqtt</artifactId> | ||
493 | - <classifier>extension</classifier> | ||
494 | - </artifactItem> | ||
495 | - <artifactItem> | ||
496 | - <groupId>org.thingsboard.extensions</groupId> | ||
497 | - <artifactId>extension-sqs</artifactId> | ||
498 | - <classifier>extension</classifier> | ||
499 | - </artifactItem> | ||
500 | - <artifactItem> | ||
501 | - <groupId>org.thingsboard.extensions</groupId> | ||
502 | - <artifactId>extension-sns</artifactId> | ||
503 | - <classifier>extension</classifier> | ||
504 | - </artifactItem> | ||
505 | - </artifactItems> | ||
506 | - </configuration> | ||
507 | - </execution> | ||
508 | - <execution> | ||
509 | <id>copy-winsw-service</id> | 470 | <id>copy-winsw-service</id> |
510 | <phase>package</phase> | 471 | <phase>package</phase> |
511 | <goals> | 472 | <goals> |
@@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
14 | # limitations under the License. | 14 | # limitations under the License. |
15 | # | 15 | # |
16 | 16 | ||
17 | -export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@" | 17 | +export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@ -Dinstall.data_dir=@pkg.installFolder@" |
18 | export LOG_FILENAME=${pkg.name}.out | 18 | export LOG_FILENAME=${pkg.name}.out |
19 | export LOADER_PATH=${pkg.installFolder}/conf,${pkg.installFolder}/extensions | 19 | export LOADER_PATH=${pkg.installFolder}/conf,${pkg.installFolder}/extensions |
20 | export SQL_DATA_FOLDER=${pkg.installFolder}/data/sql | 20 | export SQL_DATA_FOLDER=${pkg.installFolder}/data/sql |
application/src/main/data/json/demo/plugins/demo_device_messaging_rpc_plugin.json
deleted
100644 → 0
1 | -{ | ||
2 | - "apiToken": "messaging", | ||
3 | - "name": "Demo Device Messaging RPC Plugin", | ||
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.messaging.DeviceMessagingPlugin", | ||
5 | - "publicAccess": false, | ||
6 | - "state": "ACTIVE", | ||
7 | - "configuration": { | ||
8 | - "maxDeviceCountPerCustomer": 1024, | ||
9 | - "defaultTimeout": 20000, | ||
10 | - "maxTimeout": 60000 | ||
11 | - }, | ||
12 | - "additionalInfo": null | ||
13 | -} |
application/src/main/data/json/demo/plugins/demo_email_plugin.json
deleted
100644 → 0
1 | -{ | ||
2 | - "apiToken": "mail", | ||
3 | - "name": "Demo Email Plugin", | ||
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.mail.MailPlugin", | ||
5 | - "publicAccess": true, | ||
6 | - "state": "ACTIVE", | ||
7 | - "configuration": { | ||
8 | - "host": "smtp.sendgrid.net", | ||
9 | - "port": 2525, | ||
10 | - "username": "apikey", | ||
11 | - "password": "your_api_key", | ||
12 | - "otherProperties": [ | ||
13 | - { | ||
14 | - "key": "mail.smtp.auth", | ||
15 | - "value": "true" | ||
16 | - }, | ||
17 | - { | ||
18 | - "key": "mail.smtp.timeout", | ||
19 | - "value": "10000" | ||
20 | - }, | ||
21 | - { | ||
22 | - "key": "mail.smtp.starttls.enable", | ||
23 | - "value": "true" | ||
24 | - } | ||
25 | - ] | ||
26 | - }, | ||
27 | - "additionalInfo": null | ||
28 | -} |
application/src/main/data/json/demo/plugins/demo_time_rpc_plugin.json
deleted
100644 → 0
1 | -{ | ||
2 | - "apiToken": "time", | ||
3 | - "name": "Demo Time RPC Plugin", | ||
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.time.TimePlugin", | ||
5 | - "publicAccess": false, | ||
6 | - "state": "ACTIVE", | ||
7 | - "configuration": { | ||
8 | - "timeFormat": "yyyy MM dd HH:mm:ss.SSS" | ||
9 | - }, | ||
10 | - "additionalInfo": null | ||
11 | -} |
application/src/main/data/json/demo/rules/demo_alarm_rule.json
deleted
100644 → 0
1 | -{ | ||
2 | - "name": "Demo Alarm Rule", | ||
3 | - "state": "ACTIVE", | ||
4 | - "weight": 0, | ||
5 | - "pluginToken": "mail", | ||
6 | - "filters": [ | ||
7 | - { | ||
8 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter", | ||
9 | - "name": "MsgTypeFilter", | ||
10 | - "configuration": { | ||
11 | - "messageTypes": [ | ||
12 | - "POST_TELEMETRY", | ||
13 | - "POST_ATTRIBUTES", | ||
14 | - "GET_ATTRIBUTES" | ||
15 | - ] | ||
16 | - } | ||
17 | - }, | ||
18 | - { | ||
19 | - "clazz": "org.thingsboard.server.extensions.core.filter.DeviceTelemetryFilter", | ||
20 | - "name": "Temperature filter", | ||
21 | - "configuration": { | ||
22 | - "filter": "typeof temperature !== 'undefined' && temperature >= 100" | ||
23 | - } | ||
24 | - } | ||
25 | - ], | ||
26 | - "processor": { | ||
27 | - "clazz": "org.thingsboard.server.extensions.core.processor.AlarmDeduplicationProcessor", | ||
28 | - "name": "AlarmDeduplicationProcessor", | ||
29 | - "configuration": { | ||
30 | - "alarmIdTemplate": "[$date.get('yyyy-MM-dd HH:mm')] Device $cs.get('serialNumber')($cs.get('model')) temperature is high!", | ||
31 | - "alarmBodyTemplate": "[$date.get('yyyy-MM-dd HH:mm:ss')] Device $cs.get('serialNumber')($cs.get('model')) temperature is $temp.valueAsString!" | ||
32 | - } | ||
33 | - }, | ||
34 | - "action": { | ||
35 | - "clazz": "org.thingsboard.server.extensions.core.action.mail.SendMailAction", | ||
36 | - "name": "Send Mail Action", | ||
37 | - "configuration": { | ||
38 | - "sendFlag": "isNewAlarm", | ||
39 | - "fromTemplate": "thingsboard@gmail.com", | ||
40 | - "toTemplate": "thingsboard@gmail.com", | ||
41 | - "subjectTemplate": "$alarmId", | ||
42 | - "bodyTemplate": "$alarmBody" | ||
43 | - } | ||
44 | - }, | ||
45 | - "additionalInfo": null | ||
46 | -} |
application/src/main/data/json/demo/rules/demo_gettime_rpc_rule.json
deleted
100644 → 0
1 | -{ | ||
2 | - "name": "Demo getTime RPC Rule", | ||
3 | - "state": "ACTIVE", | ||
4 | - "weight": 0, | ||
5 | - "pluginToken": "time", | ||
6 | - "filters": [ | ||
7 | - { | ||
8 | - "configuration": { | ||
9 | - "messageTypes": [ | ||
10 | - "RPC_REQUEST" | ||
11 | - ] | ||
12 | - }, | ||
13 | - "name": "RPC Request Filter", | ||
14 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter" | ||
15 | - }, | ||
16 | - { | ||
17 | - "configuration": { | ||
18 | - "methodNames": [ | ||
19 | - { | ||
20 | - "name": "getTime" | ||
21 | - } | ||
22 | - ] | ||
23 | - }, | ||
24 | - "name": "getTime method filter", | ||
25 | - "clazz": "org.thingsboard.server.extensions.core.filter.MethodNameFilter" | ||
26 | - } | ||
27 | - ], | ||
28 | - "processor": null, | ||
29 | - "action": { | ||
30 | - "configuration": {}, | ||
31 | - "clazz": "org.thingsboard.server.extensions.core.action.rpc.RpcPluginAction", | ||
32 | - "name": "getTimeAction" | ||
33 | - }, | ||
34 | - "additionalInfo": null | ||
35 | -} |
application/src/main/data/json/demo/rules/demo_messaging_rpc_rule.json
deleted
100644 → 0
1 | -{ | ||
2 | - "name": "Demo Messaging RPC Rule", | ||
3 | - "state": "ACTIVE", | ||
4 | - "weight": 0, | ||
5 | - "pluginToken": "messaging", | ||
6 | - "filters": [ | ||
7 | - { | ||
8 | - "configuration": { | ||
9 | - "messageTypes": [ | ||
10 | - "RPC_REQUEST" | ||
11 | - ] | ||
12 | - }, | ||
13 | - "name": "RPC Request Filter", | ||
14 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter" | ||
15 | - }, | ||
16 | - { | ||
17 | - "configuration": { | ||
18 | - "methodNames": [ | ||
19 | - { | ||
20 | - "name": "getDevices" | ||
21 | - }, | ||
22 | - { | ||
23 | - "name": "sendMsg" | ||
24 | - } | ||
25 | - ] | ||
26 | - }, | ||
27 | - "name": "Messaging methods filter", | ||
28 | - "clazz": "org.thingsboard.server.extensions.core.filter.MethodNameFilter" | ||
29 | - } | ||
30 | - ], | ||
31 | - "processor": null, | ||
32 | - "action": { | ||
33 | - "configuration": {}, | ||
34 | - "clazz": "org.thingsboard.server.extensions.core.action.rpc.RpcPluginAction", | ||
35 | - "name": "Messaging RPC Action" | ||
36 | - }, | ||
37 | - "additionalInfo": null | ||
38 | -} |
application/src/main/data/json/system/plugins/system_rpc_plugin.json
deleted
100644 → 0
application/src/main/data/json/system/plugins/system_telemetry_plugin.json
deleted
100644 → 0
application/src/main/data/json/system/rules/system_telemetry_rule.json
deleted
100644 → 0
1 | -{ | ||
2 | - "name": "System Telemetry Rule", | ||
3 | - "state": "ACTIVE", | ||
4 | - "weight": 0, | ||
5 | - "pluginToken": "telemetry", | ||
6 | - "filters": [ | ||
7 | - { | ||
8 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter", | ||
9 | - "name": "TelemetryFilter", | ||
10 | - "configuration": { | ||
11 | - "messageTypes": [ | ||
12 | - "POST_TELEMETRY", | ||
13 | - "POST_ATTRIBUTES", | ||
14 | - "GET_ATTRIBUTES" | ||
15 | - ] | ||
16 | - } | ||
17 | - } | ||
18 | - ], | ||
19 | - "processor": null, | ||
20 | - "action": { | ||
21 | - "clazz": "org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction", | ||
22 | - "name": "TelemetryMsgConverterAction", | ||
23 | - "configuration": { | ||
24 | - "timeUnit": "DAYS", | ||
25 | - "ttlValue": 365 | ||
26 | - } | ||
27 | - }, | ||
28 | - "additionalInfo": null | ||
29 | -} |
1 | +{ | ||
2 | + "ruleChain": { | ||
3 | + "additionalInfo": null, | ||
4 | + "name": "Root Rule Chain", | ||
5 | + "firstRuleNodeId": null, | ||
6 | + "root": true, | ||
7 | + "debugMode": false, | ||
8 | + "configuration": null | ||
9 | + }, | ||
10 | + "metadata": { | ||
11 | + "firstNodeIndex": 2, | ||
12 | + "nodes": [ | ||
13 | + { | ||
14 | + "additionalInfo": { | ||
15 | + "layoutX": 824, | ||
16 | + "layoutY": 156 | ||
17 | + }, | ||
18 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", | ||
19 | + "name": "SaveTS", | ||
20 | + "debugMode": false, | ||
21 | + "configuration": { | ||
22 | + "defaultTTL": 0 | ||
23 | + } | ||
24 | + }, | ||
25 | + { | ||
26 | + "additionalInfo": { | ||
27 | + "layoutX": 825, | ||
28 | + "layoutY": 52 | ||
29 | + }, | ||
30 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", | ||
31 | + "name": "save client attributes", | ||
32 | + "debugMode": false, | ||
33 | + "configuration": { | ||
34 | + "scope": "CLIENT_SCOPE" | ||
35 | + } | ||
36 | + }, | ||
37 | + { | ||
38 | + "additionalInfo": { | ||
39 | + "layoutX": 347, | ||
40 | + "layoutY": 149 | ||
41 | + }, | ||
42 | + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", | ||
43 | + "name": "Message Type Switch", | ||
44 | + "debugMode": false, | ||
45 | + "configuration": { | ||
46 | + "version": 0 | ||
47 | + } | ||
48 | + }, | ||
49 | + { | ||
50 | + "additionalInfo": { | ||
51 | + "layoutX": 825, | ||
52 | + "layoutY": 266 | ||
53 | + }, | ||
54 | + "type": "org.thingsboard.rule.engine.action.TbLogNode", | ||
55 | + "name": "Log RPC", | ||
56 | + "debugMode": false, | ||
57 | + "configuration": { | ||
58 | + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" | ||
59 | + } | ||
60 | + }, | ||
61 | + { | ||
62 | + "additionalInfo": { | ||
63 | + "layoutX": 825, | ||
64 | + "layoutY": 379 | ||
65 | + }, | ||
66 | + "type": "org.thingsboard.rule.engine.action.TbLogNode", | ||
67 | + "name": "Log Other", | ||
68 | + "debugMode": false, | ||
69 | + "configuration": { | ||
70 | + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" | ||
71 | + } | ||
72 | + } | ||
73 | + ], | ||
74 | + "connections": [ | ||
75 | + { | ||
76 | + "fromIndex": 2, | ||
77 | + "toIndex": 4, | ||
78 | + "type": "Other" | ||
79 | + }, | ||
80 | + { | ||
81 | + "fromIndex": 2, | ||
82 | + "toIndex": 1, | ||
83 | + "type": "Post attributes" | ||
84 | + }, | ||
85 | + { | ||
86 | + "fromIndex": 2, | ||
87 | + "toIndex": 0, | ||
88 | + "type": "Post telemetry" | ||
89 | + }, | ||
90 | + { | ||
91 | + "fromIndex": 2, | ||
92 | + "toIndex": 3, | ||
93 | + "type": "RPC Request" | ||
94 | + } | ||
95 | + ], | ||
96 | + "ruleChainConnections": null | ||
97 | + } | ||
98 | +} |
1 | +-- | ||
2 | +-- Copyright © 2016-2018 The Thingsboard Authors | ||
3 | +-- | ||
4 | +-- Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +-- you may not use this file except in compliance with the License. | ||
6 | +-- You may obtain a copy of the License at | ||
7 | +-- | ||
8 | +-- http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +-- | ||
10 | +-- Unless required by applicable law or agreed to in writing, software | ||
11 | +-- distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +-- See the License for the specific language governing permissions and | ||
14 | +-- limitations under the License. | ||
15 | +-- | ||
16 | + | ||
17 | +CREATE TABLE IF NOT EXISTS thingsboard.msg_queue ( | ||
18 | + node_id timeuuid, | ||
19 | + cluster_partition bigint, | ||
20 | + ts_partition bigint, | ||
21 | + ts bigint, | ||
22 | + msg blob, | ||
23 | + PRIMARY KEY ((node_id, cluster_partition, ts_partition), ts)) | ||
24 | +WITH CLUSTERING ORDER BY (ts DESC) | ||
25 | +AND compaction = { | ||
26 | + 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', | ||
27 | + 'min_threshold': '5', | ||
28 | + 'base_time_seconds': '43200', | ||
29 | + 'max_window_size_seconds': '43200', | ||
30 | + 'tombstone_threshold': '0.9', | ||
31 | + 'unchecked_tombstone_compaction': 'true' | ||
32 | +}; | ||
33 | + | ||
34 | +CREATE TABLE IF NOT EXISTS thingsboard.msg_ack_queue ( | ||
35 | + node_id timeuuid, | ||
36 | + cluster_partition bigint, | ||
37 | + ts_partition bigint, | ||
38 | + msg_id timeuuid, | ||
39 | + PRIMARY KEY ((node_id, cluster_partition, ts_partition), msg_id)) | ||
40 | +WITH CLUSTERING ORDER BY (msg_id DESC) | ||
41 | +AND compaction = { | ||
42 | + 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', | ||
43 | + 'min_threshold': '5', | ||
44 | + 'base_time_seconds': '43200', | ||
45 | + 'max_window_size_seconds': '43200', | ||
46 | + 'tombstone_threshold': '0.9', | ||
47 | + 'unchecked_tombstone_compaction': 'true' | ||
48 | +}; | ||
49 | + | ||
50 | +CREATE TABLE IF NOT EXISTS thingsboard.processed_msg_partitions ( | ||
51 | + node_id timeuuid, | ||
52 | + cluster_partition bigint, | ||
53 | + ts_partition bigint, | ||
54 | + PRIMARY KEY ((node_id, cluster_partition), ts_partition)) | ||
55 | +WITH CLUSTERING ORDER BY (ts_partition DESC) | ||
56 | +AND compaction = { | ||
57 | + 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', | ||
58 | + 'min_threshold': '5', | ||
59 | + 'base_time_seconds': '43200', | ||
60 | + 'max_window_size_seconds': '43200', | ||
61 | + 'tombstone_threshold': '0.9', | ||
62 | + 'unchecked_tombstone_compaction': 'true' | ||
63 | +}; | ||
64 | + | ||
65 | +CREATE TABLE IF NOT EXISTS thingsboard.rule_chain ( | ||
66 | + id uuid, | ||
67 | + tenant_id uuid, | ||
68 | + name text, | ||
69 | + search_text text, | ||
70 | + first_rule_node_id uuid, | ||
71 | + root boolean, | ||
72 | + debug_mode boolean, | ||
73 | + configuration text, | ||
74 | + additional_info text, | ||
75 | + PRIMARY KEY (id, tenant_id) | ||
76 | +); | ||
77 | + | ||
78 | +CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.rule_chain_by_tenant_and_search_text AS | ||
79 | + SELECT * | ||
80 | + from thingsboard.rule_chain | ||
81 | + WHERE tenant_id IS NOT NULL AND search_text IS NOT NULL AND id IS NOT NULL | ||
82 | + PRIMARY KEY ( tenant_id, search_text, id ) | ||
83 | + WITH CLUSTERING ORDER BY ( search_text ASC, id DESC ); | ||
84 | + | ||
85 | +CREATE TABLE IF NOT EXISTS thingsboard.rule_node ( | ||
86 | + id uuid, | ||
87 | + rule_chain_id uuid, | ||
88 | + type text, | ||
89 | + name text, | ||
90 | + debug_mode boolean, | ||
91 | + search_text text, | ||
92 | + configuration text, | ||
93 | + additional_info text, | ||
94 | + PRIMARY KEY (id) | ||
95 | +); | ||
96 | + | ||
97 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.rule_by_plugin_token; | ||
98 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.rule_by_tenant_and_search_text; | ||
99 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.plugin_by_api_token; | ||
100 | +DROP MATERIALIZED VIEW IF EXISTS thingsboard.plugin_by_tenant_and_search_text; | ||
101 | + | ||
102 | +DROP TABLE IF EXISTS thingsboard.rule; | ||
103 | +DROP TABLE IF EXISTS thingsboard.plugin; |
1 | +-- | ||
2 | +-- Copyright © 2016-2018 The Thingsboard Authors | ||
3 | +-- | ||
4 | +-- Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +-- you may not use this file except in compliance with the License. | ||
6 | +-- You may obtain a copy of the License at | ||
7 | +-- | ||
8 | +-- http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +-- | ||
10 | +-- Unless required by applicable law or agreed to in writing, software | ||
11 | +-- distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +-- See the License for the specific language governing permissions and | ||
14 | +-- limitations under the License. | ||
15 | +-- | ||
16 | + | ||
17 | +CREATE TABLE IF NOT EXISTS rule_chain ( | ||
18 | + id varchar(31) NOT NULL CONSTRAINT rule_chain_pkey PRIMARY KEY, | ||
19 | + additional_info varchar, | ||
20 | + configuration varchar(10000000), | ||
21 | + name varchar(255), | ||
22 | + first_rule_node_id varchar(31), | ||
23 | + root boolean, | ||
24 | + debug_mode boolean, | ||
25 | + search_text varchar(255), | ||
26 | + tenant_id varchar(31) | ||
27 | +); | ||
28 | + | ||
29 | +CREATE TABLE IF NOT EXISTS rule_node ( | ||
30 | + id varchar(31) NOT NULL CONSTRAINT rule_node_pkey PRIMARY KEY, | ||
31 | + rule_chain_id varchar(31), | ||
32 | + additional_info varchar, | ||
33 | + configuration varchar(10000000), | ||
34 | + type varchar(255), | ||
35 | + name varchar(255), | ||
36 | + debug_mode boolean, | ||
37 | + search_text varchar(255) | ||
38 | +); | ||
39 | + | ||
40 | +DROP TABLE rule; | ||
41 | +DROP TABLE plugin; | ||
42 | + | ||
43 | +DELETE FROM alarm WHERE originator_type = 3 OR originator_type = 4; | ||
44 | +UPDATE alarm SET originator_type = (originator_type - 2) where originator_type > 2; |
@@ -21,22 +21,27 @@ import akka.actor.Scheduler; | @@ -21,22 +21,27 @@ import akka.actor.Scheduler; | ||
21 | import com.fasterxml.jackson.databind.JsonNode; | 21 | import com.fasterxml.jackson.databind.JsonNode; |
22 | import com.fasterxml.jackson.databind.ObjectMapper; | 22 | import com.fasterxml.jackson.databind.ObjectMapper; |
23 | import com.fasterxml.jackson.databind.node.ObjectNode; | 23 | import com.fasterxml.jackson.databind.node.ObjectNode; |
24 | +import com.google.common.util.concurrent.FutureCallback; | ||
25 | +import com.google.common.util.concurrent.Futures; | ||
26 | +import com.google.common.util.concurrent.ListenableFuture; | ||
24 | import com.typesafe.config.Config; | 27 | import com.typesafe.config.Config; |
25 | import com.typesafe.config.ConfigFactory; | 28 | import com.typesafe.config.ConfigFactory; |
26 | import lombok.Getter; | 29 | import lombok.Getter; |
27 | import lombok.Setter; | 30 | import lombok.Setter; |
31 | +import lombok.extern.slf4j.Slf4j; | ||
28 | import org.springframework.beans.factory.annotation.Autowired; | 32 | import org.springframework.beans.factory.annotation.Autowired; |
29 | import org.springframework.beans.factory.annotation.Value; | 33 | import org.springframework.beans.factory.annotation.Value; |
30 | import org.springframework.stereotype.Component; | 34 | import org.springframework.stereotype.Component; |
35 | +import org.thingsboard.rule.engine.api.MailService; | ||
31 | import org.thingsboard.server.actors.service.ActorService; | 36 | import org.thingsboard.server.actors.service.ActorService; |
32 | import org.thingsboard.server.common.data.DataConstants; | 37 | import org.thingsboard.server.common.data.DataConstants; |
33 | import org.thingsboard.server.common.data.Event; | 38 | import org.thingsboard.server.common.data.Event; |
34 | import org.thingsboard.server.common.data.id.EntityId; | 39 | import org.thingsboard.server.common.data.id.EntityId; |
35 | import org.thingsboard.server.common.data.id.TenantId; | 40 | import org.thingsboard.server.common.data.id.TenantId; |
36 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | 41 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
42 | +import org.thingsboard.server.common.msg.TbMsg; | ||
37 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 43 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
38 | import org.thingsboard.server.common.transport.auth.DeviceAuthService; | 44 | import org.thingsboard.server.common.transport.auth.DeviceAuthService; |
39 | -import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; | ||
40 | import org.thingsboard.server.dao.alarm.AlarmService; | 45 | import org.thingsboard.server.dao.alarm.AlarmService; |
41 | import org.thingsboard.server.dao.asset.AssetService; | 46 | import org.thingsboard.server.dao.asset.AssetService; |
42 | import org.thingsboard.server.dao.attributes.AttributesService; | 47 | import org.thingsboard.server.dao.attributes.AttributesService; |
@@ -44,118 +49,222 @@ import org.thingsboard.server.dao.audit.AuditLogService; | @@ -44,118 +49,222 @@ import org.thingsboard.server.dao.audit.AuditLogService; | ||
44 | import org.thingsboard.server.dao.customer.CustomerService; | 49 | import org.thingsboard.server.dao.customer.CustomerService; |
45 | import org.thingsboard.server.dao.device.DeviceService; | 50 | import org.thingsboard.server.dao.device.DeviceService; |
46 | import org.thingsboard.server.dao.event.EventService; | 51 | import org.thingsboard.server.dao.event.EventService; |
47 | -import org.thingsboard.server.dao.plugin.PluginService; | ||
48 | import org.thingsboard.server.dao.relation.RelationService; | 52 | import org.thingsboard.server.dao.relation.RelationService; |
49 | -import org.thingsboard.server.dao.rule.RuleService; | 53 | +import org.thingsboard.server.dao.rule.RuleChainService; |
50 | import org.thingsboard.server.dao.tenant.TenantService; | 54 | import org.thingsboard.server.dao.tenant.TenantService; |
51 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 55 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
56 | +import org.thingsboard.server.dao.user.UserService; | ||
52 | import org.thingsboard.server.service.cluster.discovery.DiscoveryService; | 57 | import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
53 | import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | 58 | import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; |
54 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | 59 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
55 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 60 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
56 | - | 61 | +import org.thingsboard.server.service.encoding.DataDecodingEncodingService; |
62 | +import org.thingsboard.server.service.executors.DbCallbackExecutorService; | ||
63 | +import org.thingsboard.server.service.executors.ExternalCallExecutorService; | ||
64 | +import org.thingsboard.server.service.mail.MailExecutorService; | ||
65 | +import org.thingsboard.server.service.queue.MsgQueueService; | ||
66 | +import org.thingsboard.server.service.rpc.DeviceRpcService; | ||
67 | +import org.thingsboard.server.service.script.JsExecutorService; | ||
68 | +import org.thingsboard.server.service.script.JsSandboxService; | ||
69 | +import org.thingsboard.server.service.state.DeviceStateService; | ||
70 | +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | ||
71 | + | ||
72 | +import javax.annotation.Nullable; | ||
73 | +import java.io.IOException; | ||
57 | import java.io.PrintWriter; | 74 | import java.io.PrintWriter; |
58 | import java.io.StringWriter; | 75 | import java.io.StringWriter; |
59 | import java.util.Optional; | 76 | import java.util.Optional; |
60 | 77 | ||
78 | +@Slf4j | ||
61 | @Component | 79 | @Component |
62 | public class ActorSystemContext { | 80 | public class ActorSystemContext { |
63 | private static final String AKKA_CONF_FILE_NAME = "actor-system.conf"; | 81 | private static final String AKKA_CONF_FILE_NAME = "actor-system.conf"; |
64 | 82 | ||
65 | protected final ObjectMapper mapper = new ObjectMapper(); | 83 | protected final ObjectMapper mapper = new ObjectMapper(); |
66 | 84 | ||
67 | - @Getter @Setter private ActorService actorService; | 85 | + @Getter |
86 | + @Setter | ||
87 | + private ActorService actorService; | ||
88 | + | ||
89 | + @Autowired | ||
90 | + @Getter | ||
91 | + private DiscoveryService discoveryService; | ||
92 | + | ||
93 | + @Autowired | ||
94 | + @Getter | ||
95 | + @Setter | ||
96 | + private ComponentDiscoveryService componentService; | ||
97 | + | ||
98 | + @Autowired | ||
99 | + @Getter | ||
100 | + private ClusterRoutingService routingService; | ||
101 | + | ||
102 | + @Autowired | ||
103 | + @Getter | ||
104 | + private ClusterRpcService rpcService; | ||
105 | + | ||
106 | + @Autowired | ||
107 | + @Getter | ||
108 | + private DataDecodingEncodingService encodingService; | ||
109 | + | ||
110 | + @Autowired | ||
111 | + @Getter | ||
112 | + private DeviceAuthService deviceAuthService; | ||
113 | + | ||
114 | + @Autowired | ||
115 | + @Getter | ||
116 | + private DeviceService deviceService; | ||
117 | + | ||
118 | + @Autowired | ||
119 | + @Getter | ||
120 | + private AssetService assetService; | ||
121 | + | ||
122 | + @Autowired | ||
123 | + @Getter | ||
124 | + private TenantService tenantService; | ||
125 | + | ||
126 | + @Autowired | ||
127 | + @Getter | ||
128 | + private CustomerService customerService; | ||
68 | 129 | ||
69 | @Autowired | 130 | @Autowired |
70 | - @Getter private DiscoveryService discoveryService; | 131 | + @Getter |
132 | + private UserService userService; | ||
71 | 133 | ||
72 | @Autowired | 134 | @Autowired |
73 | - @Getter @Setter private ComponentDiscoveryService componentService; | 135 | + @Getter |
136 | + private RuleChainService ruleChainService; | ||
74 | 137 | ||
75 | @Autowired | 138 | @Autowired |
76 | - @Getter private ClusterRoutingService routingService; | 139 | + @Getter |
140 | + private TimeseriesService tsService; | ||
77 | 141 | ||
78 | @Autowired | 142 | @Autowired |
79 | - @Getter private ClusterRpcService rpcService; | 143 | + @Getter |
144 | + private AttributesService attributesService; | ||
80 | 145 | ||
81 | @Autowired | 146 | @Autowired |
82 | - @Getter private DeviceAuthService deviceAuthService; | 147 | + @Getter |
148 | + private EventService eventService; | ||
83 | 149 | ||
84 | @Autowired | 150 | @Autowired |
85 | - @Getter private DeviceService deviceService; | 151 | + @Getter |
152 | + private AlarmService alarmService; | ||
86 | 153 | ||
87 | @Autowired | 154 | @Autowired |
88 | - @Getter private AssetService assetService; | 155 | + @Getter |
156 | + private RelationService relationService; | ||
89 | 157 | ||
90 | @Autowired | 158 | @Autowired |
91 | - @Getter private TenantService tenantService; | 159 | + @Getter |
160 | + private AuditLogService auditLogService; | ||
92 | 161 | ||
93 | @Autowired | 162 | @Autowired |
94 | - @Getter private CustomerService customerService; | 163 | + @Getter |
164 | + private TelemetrySubscriptionService tsSubService; | ||
95 | 165 | ||
96 | @Autowired | 166 | @Autowired |
97 | - @Getter private RuleService ruleService; | 167 | + @Getter |
168 | + private DeviceRpcService deviceRpcService; | ||
98 | 169 | ||
99 | @Autowired | 170 | @Autowired |
100 | - @Getter private PluginService pluginService; | 171 | + @Getter |
172 | + private JsSandboxService jsSandbox; | ||
101 | 173 | ||
102 | @Autowired | 174 | @Autowired |
103 | - @Getter private TimeseriesService tsService; | 175 | + @Getter |
176 | + private JsExecutorService jsExecutor; | ||
104 | 177 | ||
105 | @Autowired | 178 | @Autowired |
106 | - @Getter private AttributesService attributesService; | 179 | + @Getter |
180 | + private MailExecutorService mailExecutor; | ||
107 | 181 | ||
108 | @Autowired | 182 | @Autowired |
109 | - @Getter private EventService eventService; | 183 | + @Getter |
184 | + private DbCallbackExecutorService dbCallbackExecutor; | ||
110 | 185 | ||
111 | @Autowired | 186 | @Autowired |
112 | - @Getter private AlarmService alarmService; | 187 | + @Getter |
188 | + private ExternalCallExecutorService externalCallExecutorService; | ||
113 | 189 | ||
114 | @Autowired | 190 | @Autowired |
115 | - @Getter private RelationService relationService; | 191 | + @Getter |
192 | + private MailService mailService; | ||
116 | 193 | ||
117 | @Autowired | 194 | @Autowired |
118 | - @Getter private AuditLogService auditLogService; | 195 | + @Getter |
196 | + private MsgQueueService msgQueueService; | ||
119 | 197 | ||
120 | @Autowired | 198 | @Autowired |
121 | - @Getter @Setter private PluginWebSocketMsgEndpoint wsMsgEndpoint; | 199 | + @Getter |
200 | + private DeviceStateService deviceStateService; | ||
201 | + | ||
202 | + @Value("${cluster.partition_id}") | ||
203 | + @Getter | ||
204 | + private long queuePartitionId; | ||
205 | + | ||
206 | + @Value("${actors.session.max_concurrent_sessions_per_device:1}") | ||
207 | + @Getter | ||
208 | + private long maxConcurrentSessionsPerDevice; | ||
122 | 209 | ||
123 | @Value("${actors.session.sync.timeout}") | 210 | @Value("${actors.session.sync.timeout}") |
124 | - @Getter private long syncSessionTimeout; | 211 | + @Getter |
212 | + private long syncSessionTimeout; | ||
125 | 213 | ||
126 | - @Value("${actors.plugin.termination.delay}") | ||
127 | - @Getter private long pluginActorTerminationDelay; | 214 | + @Value("${actors.queue.enabled}") |
215 | + @Getter | ||
216 | + private boolean queuePersistenceEnabled; | ||
128 | 217 | ||
129 | - @Value("${actors.plugin.processing.timeout}") | ||
130 | - @Getter private long pluginProcessingTimeout; | 218 | + @Value("${actors.queue.timeout}") |
219 | + @Getter | ||
220 | + private long queuePersistenceTimeout; | ||
131 | 221 | ||
132 | - @Value("${actors.plugin.error_persist_frequency}") | ||
133 | - @Getter private long pluginErrorPersistFrequency; | 222 | + @Value("${actors.client_side_rpc.timeout}") |
223 | + @Getter | ||
224 | + private long clientSideRpcTimeout; | ||
134 | 225 | ||
135 | - @Value("${actors.rule.termination.delay}") | ||
136 | - @Getter private long ruleActorTerminationDelay; | 226 | + @Value("${actors.rule.chain.error_persist_frequency}") |
227 | + @Getter | ||
228 | + private long ruleChainErrorPersistFrequency; | ||
137 | 229 | ||
138 | - @Value("${actors.rule.error_persist_frequency}") | ||
139 | - @Getter private long ruleErrorPersistFrequency; | 230 | + @Value("${actors.rule.node.error_persist_frequency}") |
231 | + @Getter | ||
232 | + private long ruleNodeErrorPersistFrequency; | ||
140 | 233 | ||
141 | @Value("${actors.statistics.enabled}") | 234 | @Value("${actors.statistics.enabled}") |
142 | - @Getter private boolean statisticsEnabled; | 235 | + @Getter |
236 | + private boolean statisticsEnabled; | ||
143 | 237 | ||
144 | @Value("${actors.statistics.persist_frequency}") | 238 | @Value("${actors.statistics.persist_frequency}") |
145 | - @Getter private long statisticsPersistFrequency; | 239 | + @Getter |
240 | + private long statisticsPersistFrequency; | ||
146 | 241 | ||
147 | @Value("${actors.tenant.create_components_on_init}") | 242 | @Value("${actors.tenant.create_components_on_init}") |
148 | - @Getter private boolean tenantComponentsInitEnabled; | 243 | + @Getter |
244 | + private boolean tenantComponentsInitEnabled; | ||
149 | 245 | ||
150 | - @Getter @Setter private ActorSystem actorSystem; | 246 | + @Value("${actors.rule.allow_system_mail_service}") |
247 | + @Getter | ||
248 | + private boolean allowSystemMailService; | ||
151 | 249 | ||
152 | - @Getter @Setter private ActorRef appActor; | 250 | + @Getter |
251 | + @Setter | ||
252 | + private ActorSystem actorSystem; | ||
153 | 253 | ||
154 | - @Getter @Setter private ActorRef sessionManagerActor; | 254 | + @Getter |
255 | + @Setter | ||
256 | + private ActorRef appActor; | ||
155 | 257 | ||
156 | - @Getter @Setter private ActorRef statsActor; | 258 | + @Getter |
259 | + @Setter | ||
260 | + private ActorRef sessionManagerActor; | ||
157 | 261 | ||
158 | - @Getter private final Config config; | 262 | + @Getter |
263 | + @Setter | ||
264 | + private ActorRef statsActor; | ||
265 | + | ||
266 | + @Getter | ||
267 | + private final Config config; | ||
159 | 268 | ||
160 | public ActorSystemContext() { | 269 | public ActorSystemContext() { |
161 | config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); | 270 | config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); |
@@ -187,7 +296,7 @@ public class ActorSystemContext { | @@ -187,7 +296,7 @@ public class ActorSystemContext { | ||
187 | eventService.save(event); | 296 | eventService.save(event); |
188 | } | 297 | } |
189 | 298 | ||
190 | - private String toString(Exception e) { | 299 | + private String toString(Throwable e) { |
191 | StringWriter sw = new StringWriter(); | 300 | StringWriter sw = new StringWriter(); |
192 | e.printStackTrace(new PrintWriter(sw)); | 301 | e.printStackTrace(new PrintWriter(sw)); |
193 | return sw.toString(); | 302 | return sw.toString(); |
@@ -207,4 +316,72 @@ public class ActorSystemContext { | @@ -207,4 +316,72 @@ public class ActorSystemContext { | ||
207 | private JsonNode toBodyJson(ServerAddress server, String method, String body) { | 316 | private JsonNode toBodyJson(ServerAddress server, String method, String body) { |
208 | return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body); | 317 | return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body); |
209 | } | 318 | } |
319 | + | ||
320 | + public String getServerAddress() { | ||
321 | + return discoveryService.getCurrentServer().getServerAddress().toString(); | ||
322 | + } | ||
323 | + | ||
324 | + public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType) { | ||
325 | + persistDebugAsync(tenantId, entityId, "IN", tbMsg, relationType, null); | ||
326 | + } | ||
327 | + | ||
328 | + public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType, Throwable error) { | ||
329 | + persistDebugAsync(tenantId, entityId, "IN", tbMsg, relationType, error); | ||
330 | + } | ||
331 | + | ||
332 | + public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType, Throwable error) { | ||
333 | + persistDebugAsync(tenantId, entityId, "OUT", tbMsg, relationType, error); | ||
334 | + } | ||
335 | + | ||
336 | + public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, String relationType) { | ||
337 | + persistDebugAsync(tenantId, entityId, "OUT", tbMsg, relationType, null); | ||
338 | + } | ||
339 | + | ||
340 | + private void persistDebugAsync(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, String relationType, Throwable error) { | ||
341 | + try { | ||
342 | + Event event = new Event(); | ||
343 | + event.setTenantId(tenantId); | ||
344 | + event.setEntityId(entityId); | ||
345 | + event.setType(DataConstants.DEBUG_RULE_NODE); | ||
346 | + | ||
347 | + String metadata = mapper.writeValueAsString(tbMsg.getMetaData().getData()); | ||
348 | + | ||
349 | + ObjectNode node = mapper.createObjectNode() | ||
350 | + .put("type", type) | ||
351 | + .put("server", getServerAddress()) | ||
352 | + .put("entityId", tbMsg.getOriginator().getId().toString()) | ||
353 | + .put("entityName", tbMsg.getOriginator().getEntityType().name()) | ||
354 | + .put("msgId", tbMsg.getId().toString()) | ||
355 | + .put("msgType", tbMsg.getType()) | ||
356 | + .put("dataType", tbMsg.getDataType().name()) | ||
357 | + .put("relationType", relationType) | ||
358 | + .put("data", tbMsg.getData()) | ||
359 | + .put("metadata", metadata); | ||
360 | + | ||
361 | + if (error != null) { | ||
362 | + node = node.put("error", toString(error)); | ||
363 | + } | ||
364 | + | ||
365 | + event.setBody(node); | ||
366 | + ListenableFuture<Event> future = eventService.saveAsync(event); | ||
367 | + Futures.addCallback(future, new FutureCallback<Event>() { | ||
368 | + @Override | ||
369 | + public void onSuccess(@Nullable Event event) { | ||
370 | + | ||
371 | + } | ||
372 | + | ||
373 | + @Override | ||
374 | + public void onFailure(Throwable th) { | ||
375 | + log.error("Could not save debug Event for Node", th); | ||
376 | + } | ||
377 | + }); | ||
378 | + } catch (IOException ex) { | ||
379 | + log.warn("Failed to persist rule node debug message", ex); | ||
380 | + } | ||
381 | + } | ||
382 | + | ||
383 | + public static Exception toException(Throwable error) { | ||
384 | + return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); | ||
385 | + } | ||
386 | + | ||
210 | } | 387 | } |
@@ -15,55 +15,51 @@ | @@ -15,55 +15,51 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.actors.app; | 16 | package org.thingsboard.server.actors.app; |
17 | 17 | ||
18 | -import akka.actor.*; | 18 | +import akka.actor.ActorRef; |
19 | +import akka.actor.LocalActorRef; | ||
20 | +import akka.actor.OneForOneStrategy; | ||
21 | +import akka.actor.Props; | ||
22 | +import akka.actor.SupervisorStrategy; | ||
19 | import akka.actor.SupervisorStrategy.Directive; | 23 | import akka.actor.SupervisorStrategy.Directive; |
24 | +import akka.actor.Terminated; | ||
20 | import akka.event.Logging; | 25 | import akka.event.Logging; |
21 | import akka.event.LoggingAdapter; | 26 | import akka.event.LoggingAdapter; |
22 | import akka.japi.Function; | 27 | import akka.japi.Function; |
23 | import org.thingsboard.server.actors.ActorSystemContext; | 28 | import org.thingsboard.server.actors.ActorSystemContext; |
24 | -import org.thingsboard.server.actors.plugin.PluginTerminationMsg; | ||
25 | -import org.thingsboard.server.actors.service.ContextAwareActor; | 29 | +import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; |
26 | import org.thingsboard.server.actors.service.ContextBasedCreator; | 30 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
27 | import org.thingsboard.server.actors.service.DefaultActorService; | 31 | import org.thingsboard.server.actors.service.DefaultActorService; |
28 | -import org.thingsboard.server.actors.shared.plugin.PluginManager; | ||
29 | -import org.thingsboard.server.actors.shared.plugin.SystemPluginManager; | ||
30 | -import org.thingsboard.server.actors.shared.rule.RuleManager; | ||
31 | -import org.thingsboard.server.actors.shared.rule.SystemRuleManager; | ||
32 | -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg; | 32 | +import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager; |
33 | import org.thingsboard.server.actors.tenant.TenantActor; | 33 | import org.thingsboard.server.actors.tenant.TenantActor; |
34 | import org.thingsboard.server.common.data.Tenant; | 34 | import org.thingsboard.server.common.data.Tenant; |
35 | -import org.thingsboard.server.common.data.id.PluginId; | ||
36 | -import org.thingsboard.server.common.data.id.RuleId; | ||
37 | import org.thingsboard.server.common.data.id.TenantId; | 35 | import org.thingsboard.server.common.data.id.TenantId; |
38 | import org.thingsboard.server.common.data.page.PageDataIterable; | 36 | import org.thingsboard.server.common.data.page.PageDataIterable; |
39 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
40 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | 37 | +import org.thingsboard.server.common.msg.TbActorMsg; |
38 | +import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | ||
39 | +import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; | ||
40 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
41 | +import org.thingsboard.server.common.msg.core.BasicActorSystemToDeviceSessionActorMsg; | ||
42 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
41 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 43 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
44 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | ||
42 | import org.thingsboard.server.dao.model.ModelConstants; | 45 | import org.thingsboard.server.dao.model.ModelConstants; |
43 | import org.thingsboard.server.dao.tenant.TenantService; | 46 | import org.thingsboard.server.dao.tenant.TenantService; |
44 | -import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; | ||
45 | -import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg; | ||
46 | -import org.thingsboard.server.extensions.api.rules.ToRuleActorMsg; | ||
47 | import scala.concurrent.duration.Duration; | 47 | import scala.concurrent.duration.Duration; |
48 | 48 | ||
49 | import java.util.HashMap; | 49 | import java.util.HashMap; |
50 | import java.util.Map; | 50 | import java.util.Map; |
51 | import java.util.Optional; | 51 | import java.util.Optional; |
52 | 52 | ||
53 | -public class AppActor extends ContextAwareActor { | 53 | +public class AppActor extends RuleChainManagerActor { |
54 | 54 | ||
55 | private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | 55 | private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); |
56 | 56 | ||
57 | public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); | 57 | public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); |
58 | - private final RuleManager ruleManager; | ||
59 | - private final PluginManager pluginManager; | ||
60 | private final TenantService tenantService; | 58 | private final TenantService tenantService; |
61 | private final Map<TenantId, ActorRef> tenantActors; | 59 | private final Map<TenantId, ActorRef> tenantActors; |
62 | 60 | ||
63 | private AppActor(ActorSystemContext systemContext) { | 61 | private AppActor(ActorSystemContext systemContext) { |
64 | - super(systemContext); | ||
65 | - this.ruleManager = new SystemRuleManager(systemContext); | ||
66 | - this.pluginManager = new SystemPluginManager(systemContext); | 62 | + super(systemContext, new SystemRuleChainManager(systemContext)); |
67 | this.tenantService = systemContext.getTenantService(); | 63 | this.tenantService = systemContext.getTenantService(); |
68 | this.tenantActors = new HashMap<>(); | 64 | this.tenantActors = new HashMap<>(); |
69 | } | 65 | } |
@@ -77,8 +73,7 @@ public class AppActor extends ContextAwareActor { | @@ -77,8 +73,7 @@ public class AppActor extends ContextAwareActor { | ||
77 | public void preStart() { | 73 | public void preStart() { |
78 | logger.info("Starting main system actor."); | 74 | logger.info("Starting main system actor."); |
79 | try { | 75 | try { |
80 | - ruleManager.init(this.context()); | ||
81 | - pluginManager.init(this.context()); | 76 | + initRuleChains(); |
82 | 77 | ||
83 | if (systemContext.isTenantComponentsInitEnabled()) { | 78 | if (systemContext.isTenantComponentsInitEnabled()) { |
84 | PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); | 79 | PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); |
@@ -96,93 +91,89 @@ public class AppActor extends ContextAwareActor { | @@ -96,93 +91,89 @@ public class AppActor extends ContextAwareActor { | ||
96 | } | 91 | } |
97 | 92 | ||
98 | @Override | 93 | @Override |
99 | - public void onReceive(Object msg) throws Exception { | ||
100 | - logger.debug("Received message: {}", msg); | ||
101 | - if (msg instanceof ToDeviceActorMsg) { | ||
102 | - processDeviceMsg((ToDeviceActorMsg) msg); | ||
103 | - } else if (msg instanceof ToPluginActorMsg) { | ||
104 | - onToPluginMsg((ToPluginActorMsg) msg); | ||
105 | - } else if (msg instanceof ToRuleActorMsg) { | ||
106 | - onToRuleMsg((ToRuleActorMsg) msg); | ||
107 | - } else if (msg instanceof ToDeviceActorNotificationMsg) { | ||
108 | - onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg); | ||
109 | - } else if (msg instanceof Terminated) { | ||
110 | - processTermination((Terminated) msg); | ||
111 | - } else if (msg instanceof ClusterEventMsg) { | ||
112 | - broadcast(msg); | ||
113 | - } else if (msg instanceof ComponentLifecycleMsg) { | ||
114 | - onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | ||
115 | - } else if (msg instanceof PluginTerminationMsg) { | ||
116 | - onPluginTerminated((PluginTerminationMsg) msg); | ||
117 | - } else { | ||
118 | - logger.warning("Unknown message: {}!", msg); | 94 | + protected boolean process(TbActorMsg msg) { |
95 | + switch (msg.getMsgType()) { | ||
96 | + case SEND_TO_CLUSTER_MSG: | ||
97 | + onPossibleClusterMsg((SendToClusterMsg) msg); | ||
98 | + break; | ||
99 | + case CLUSTER_EVENT_MSG: | ||
100 | + broadcast(msg); | ||
101 | + break; | ||
102 | + case COMPONENT_LIFE_CYCLE_MSG: | ||
103 | + onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | ||
104 | + break; | ||
105 | + case SERVICE_TO_RULE_ENGINE_MSG: | ||
106 | + onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | ||
107 | + break; | ||
108 | + case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | ||
109 | + case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
110 | + case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
111 | + case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
112 | + case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | ||
113 | + case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | ||
114 | + onToDeviceActorMsg((TenantAwareMsg) msg); | ||
115 | + break; | ||
116 | + case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG: | ||
117 | + onToDeviceSessionMsg((BasicActorSystemToDeviceSessionActorMsg) msg); | ||
118 | + default: | ||
119 | + return false; | ||
119 | } | 120 | } |
121 | + return true; | ||
120 | } | 122 | } |
121 | 123 | ||
122 | - private void onPluginTerminated(PluginTerminationMsg msg) { | ||
123 | - pluginManager.remove(msg.getId()); | 124 | + private void onToDeviceSessionMsg(BasicActorSystemToDeviceSessionActorMsg msg) { |
125 | + systemContext.getSessionManagerActor().tell(msg, self()); | ||
124 | } | 126 | } |
125 | 127 | ||
126 | - private void broadcast(Object msg) { | ||
127 | - pluginManager.broadcast(msg); | ||
128 | - tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | 128 | + private void onPossibleClusterMsg(SendToClusterMsg msg) { |
129 | + Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId()); | ||
130 | + if (address.isPresent()) { | ||
131 | + systemContext.getRpcService().tell( | ||
132 | + systemContext.getEncodingService().convertToProtoDataMessage(address.get(), msg.getMsg())); | ||
133 | + } else { | ||
134 | + self().tell(msg.getMsg(), ActorRef.noSender()); | ||
135 | + } | ||
129 | } | 136 | } |
130 | 137 | ||
131 | - private void onToRuleMsg(ToRuleActorMsg msg) { | ||
132 | - ActorRef target; | 138 | + private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { |
133 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { | 139 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
134 | - target = ruleManager.getOrCreateRuleActor(this.context(), msg.getRuleId()); | 140 | + //TODO: ashvayka handle this. |
135 | } else { | 141 | } else { |
136 | - target = getOrCreateTenantActor(msg.getTenantId()); | 142 | + getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); |
137 | } | 143 | } |
138 | - target.tell(msg, ActorRef.noSender()); | ||
139 | } | 144 | } |
140 | 145 | ||
141 | - private void onToPluginMsg(ToPluginActorMsg msg) { | ||
142 | - ActorRef target; | ||
143 | - if (SYSTEM_TENANT.equals(msg.getPluginTenantId())) { | ||
144 | - target = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId()); | ||
145 | - } else { | ||
146 | - target = getOrCreateTenantActor(msg.getPluginTenantId()); | ||
147 | - } | ||
148 | - target.tell(msg, ActorRef.noSender()); | 146 | + @Override |
147 | + protected void broadcast(Object msg) { | ||
148 | + super.broadcast(msg); | ||
149 | + tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | ||
149 | } | 150 | } |
150 | 151 | ||
151 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { | 152 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
152 | - ActorRef target = null; | 153 | + ActorRef target; |
153 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { | 154 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
154 | - Optional<PluginId> pluginId = msg.getPluginId(); | ||
155 | - Optional<RuleId> ruleId = msg.getRuleId(); | ||
156 | - if (pluginId.isPresent()) { | ||
157 | - target = pluginManager.getOrCreatePluginActor(this.context(), pluginId.get()); | ||
158 | - } else if (ruleId.isPresent()) { | ||
159 | - Optional<ActorRef> ref = ruleManager.update(this.context(), ruleId.get(), msg.getEvent()); | ||
160 | - if (ref.isPresent()) { | ||
161 | - target = ref.get(); | ||
162 | - } else { | ||
163 | - logger.debug("Failed to find actor for rule: [{}]", ruleId); | ||
164 | - return; | ||
165 | - } | ||
166 | - } | 155 | + target = getEntityActorRef(msg.getEntityId()); |
167 | } else { | 156 | } else { |
168 | target = getOrCreateTenantActor(msg.getTenantId()); | 157 | target = getOrCreateTenantActor(msg.getTenantId()); |
169 | } | 158 | } |
170 | if (target != null) { | 159 | if (target != null) { |
171 | target.tell(msg, ActorRef.noSender()); | 160 | target.tell(msg, ActorRef.noSender()); |
161 | + } else { | ||
162 | + logger.debug("Invalid component lifecycle msg: {}", msg); | ||
172 | } | 163 | } |
173 | } | 164 | } |
174 | 165 | ||
175 | - private void onToDeviceActorMsg(ToDeviceActorNotificationMsg msg) { | 166 | + private void onToDeviceActorMsg(TenantAwareMsg msg) { |
176 | getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); | 167 | getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); |
177 | } | 168 | } |
178 | 169 | ||
179 | - private void processDeviceMsg(ToDeviceActorMsg toDeviceActorMsg) { | ||
180 | - TenantId tenantId = toDeviceActorMsg.getTenantId(); | 170 | + private void processDeviceMsg(DeviceToDeviceActorMsg deviceToDeviceActorMsg) { |
171 | + TenantId tenantId = deviceToDeviceActorMsg.getTenantId(); | ||
181 | ActorRef tenantActor = getOrCreateTenantActor(tenantId); | 172 | ActorRef tenantActor = getOrCreateTenantActor(tenantId); |
182 | - if (toDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { | ||
183 | - tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | 173 | + if (deviceToDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { |
174 | +// tenantActor.tell(new RuleChainDeviceMsg(deviceToDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | ||
184 | } else { | 175 | } else { |
185 | - tenantActor.tell(toDeviceActorMsg, context().self()); | 176 | + tenantActor.tell(deviceToDeviceActorMsg, context().self()); |
186 | } | 177 | } |
187 | } | 178 | } |
188 | 179 |
@@ -17,61 +17,73 @@ package org.thingsboard.server.actors.device; | @@ -17,61 +17,73 @@ package org.thingsboard.server.actors.device; | ||
17 | 17 | ||
18 | import akka.event.Logging; | 18 | import akka.event.Logging; |
19 | import akka.event.LoggingAdapter; | 19 | import akka.event.LoggingAdapter; |
20 | +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; | ||
21 | +import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | ||
20 | import org.thingsboard.server.actors.ActorSystemContext; | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | -import org.thingsboard.server.actors.rule.RulesProcessedMsg; | ||
22 | import org.thingsboard.server.actors.service.ContextAwareActor; | 23 | import org.thingsboard.server.actors.service.ContextAwareActor; |
23 | import org.thingsboard.server.actors.service.ContextBasedCreator; | 24 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
24 | -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg; | ||
25 | import org.thingsboard.server.common.data.id.DeviceId; | 25 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
27 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | 28 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
28 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | ||
29 | -import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; | ||
30 | -import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg; | ||
31 | -import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; | ||
32 | -import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; | ||
33 | -import org.thingsboard.server.extensions.api.plugins.msg.*; | 29 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; |
30 | +import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; | ||
31 | +import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | ||
32 | +import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | ||
33 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | ||
34 | +import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; | ||
34 | 35 | ||
35 | public class DeviceActor extends ContextAwareActor { | 36 | public class DeviceActor extends ContextAwareActor { |
36 | 37 | ||
37 | private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | 38 | private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); |
38 | 39 | ||
39 | - private final TenantId tenantId; | ||
40 | - private final DeviceId deviceId; | ||
41 | private final DeviceActorMessageProcessor processor; | 40 | private final DeviceActorMessageProcessor processor; |
42 | 41 | ||
43 | private DeviceActor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { | 42 | private DeviceActor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { |
44 | super(systemContext); | 43 | super(systemContext); |
45 | - this.tenantId = tenantId; | ||
46 | - this.deviceId = deviceId; | ||
47 | - this.processor = new DeviceActorMessageProcessor(systemContext, logger, deviceId); | 44 | + this.processor = new DeviceActorMessageProcessor(systemContext, logger, tenantId, deviceId); |
48 | } | 45 | } |
49 | 46 | ||
50 | @Override | 47 | @Override |
51 | - public void onReceive(Object msg) throws Exception { | ||
52 | - if (msg instanceof RuleChainDeviceMsg) { | ||
53 | - processor.process(context(), (RuleChainDeviceMsg) msg); | ||
54 | - } else if (msg instanceof RulesProcessedMsg) { | ||
55 | - processor.onRulesProcessedMsg(context(), (RulesProcessedMsg) msg); | ||
56 | - } else if (msg instanceof ToDeviceActorMsg) { | ||
57 | - processor.process(context(), (ToDeviceActorMsg) msg); | ||
58 | - } else if (msg instanceof ToDeviceActorNotificationMsg) { | ||
59 | - if (msg instanceof DeviceAttributesEventNotificationMsg) { | 48 | + protected boolean process(TbActorMsg msg) { |
49 | + switch (msg.getMsgType()) { | ||
50 | + case CLUSTER_EVENT_MSG: | ||
51 | + processor.processClusterEventMsg((ClusterEventMsg) msg); | ||
52 | + break; | ||
53 | + case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | ||
54 | + processor.process(context(), (DeviceToDeviceActorMsg) msg); | ||
55 | + break; | ||
56 | + case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
60 | processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); | 57 | processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); |
61 | - } else if (msg instanceof ToDeviceRpcRequestPluginMsg) { | ||
62 | - processor.processRpcRequest(context(), (ToDeviceRpcRequestPluginMsg) msg); | ||
63 | - } else if (msg instanceof DeviceCredentialsUpdateNotificationMsg){ | 58 | + break; |
59 | + case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
64 | processor.processCredentialsUpdate(); | 60 | processor.processCredentialsUpdate(); |
65 | - } else if (msg instanceof DeviceNameOrTypeUpdateMsg){ | 61 | + break; |
62 | + case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
66 | processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg); | 63 | processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg); |
67 | - } | ||
68 | - } else if (msg instanceof TimeoutMsg) { | ||
69 | - processor.processTimeout(context(), (TimeoutMsg) msg); | ||
70 | - } else if (msg instanceof ClusterEventMsg) { | ||
71 | - processor.processClusterEventMsg((ClusterEventMsg) msg); | ||
72 | - } else { | ||
73 | - logger.debug("[{}][{}] Unknown msg type.", tenantId, deviceId, msg.getClass().getName()); | 64 | + break; |
65 | + case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | ||
66 | + processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg); | ||
67 | + break; | ||
68 | + case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | ||
69 | + processor.processToServerRPCResponse(context(), (ToServerRpcResponseActorMsg) msg); | ||
70 | + break; | ||
71 | + case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: | ||
72 | + processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg); | ||
73 | + break; | ||
74 | + case DEVICE_ACTOR_CLIENT_SIDE_RPC_TIMEOUT_MSG: | ||
75 | + processor.processClientSideRpcTimeout(context(), (DeviceActorClientSideRpcTimeoutMsg) msg); | ||
76 | + break; | ||
77 | + case DEVICE_ACTOR_QUEUE_TIMEOUT_MSG: | ||
78 | + processor.processQueueTimeout(context(), (DeviceActorQueueTimeoutMsg) msg); | ||
79 | + break; | ||
80 | + case RULE_ENGINE_QUEUE_PUT_ACK_MSG: | ||
81 | + processor.processQueueAck(context(), (RuleEngineQueuePutAckMsg) msg); | ||
82 | + break; | ||
83 | + default: | ||
84 | + return false; | ||
74 | } | 85 | } |
86 | + return true; | ||
75 | } | 87 | } |
76 | 88 | ||
77 | public static class ActorCreator extends ContextBasedCreator<DeviceActor> { | 89 | public static class ActorCreator extends ContextBasedCreator<DeviceActor> { |
@@ -18,37 +18,75 @@ package org.thingsboard.server.actors.device; | @@ -18,37 +18,75 @@ package org.thingsboard.server.actors.device; | ||
18 | import akka.actor.ActorContext; | 18 | import akka.actor.ActorContext; |
19 | import akka.actor.ActorRef; | 19 | import akka.actor.ActorRef; |
20 | import akka.event.LoggingAdapter; | 20 | import akka.event.LoggingAdapter; |
21 | +import com.datastax.driver.core.utils.UUIDs; | ||
22 | +import com.google.common.util.concurrent.FutureCallback; | ||
23 | +import com.google.common.util.concurrent.Futures; | ||
24 | +import com.google.common.util.concurrent.ListenableFuture; | ||
25 | +import com.google.gson.Gson; | ||
26 | +import com.google.gson.JsonObject; | ||
27 | +import com.google.gson.JsonParser; | ||
28 | +import org.thingsboard.rule.engine.api.RpcError; | ||
29 | +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; | ||
30 | +import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | ||
21 | import org.thingsboard.server.actors.ActorSystemContext; | 31 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | -import org.thingsboard.server.actors.rule.*; | ||
23 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; | 32 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
24 | -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg; | ||
25 | import org.thingsboard.server.common.data.DataConstants; | 33 | import org.thingsboard.server.common.data.DataConstants; |
26 | import org.thingsboard.server.common.data.Device; | 34 | import org.thingsboard.server.common.data.Device; |
27 | import org.thingsboard.server.common.data.id.DeviceId; | 35 | import org.thingsboard.server.common.data.id.DeviceId; |
28 | import org.thingsboard.server.common.data.id.SessionId; | 36 | import org.thingsboard.server.common.data.id.SessionId; |
37 | +import org.thingsboard.server.common.data.id.TenantId; | ||
29 | import org.thingsboard.server.common.data.kv.AttributeKey; | 38 | import org.thingsboard.server.common.data.kv.AttributeKey; |
30 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 39 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
40 | +import org.thingsboard.server.common.data.kv.KvEntry; | ||
41 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | ||
42 | +import org.thingsboard.server.common.msg.TbMsg; | ||
43 | +import org.thingsboard.server.common.msg.TbMsgDataType; | ||
44 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
31 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | 45 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
32 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 46 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
33 | -import org.thingsboard.server.common.msg.core.*; | ||
34 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | 47 | +import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg; |
48 | +import org.thingsboard.server.common.msg.core.AttributesUpdateNotification; | ||
49 | +import org.thingsboard.server.common.msg.core.AttributesUpdateRequest; | ||
50 | +import org.thingsboard.server.common.msg.core.BasicActorSystemToDeviceSessionActorMsg; | ||
51 | +import org.thingsboard.server.common.msg.core.BasicCommandAckResponse; | ||
52 | +import org.thingsboard.server.common.msg.core.BasicGetAttributesResponse; | ||
53 | +import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; | ||
54 | +import org.thingsboard.server.common.msg.core.GetAttributesRequest; | ||
55 | +import org.thingsboard.server.common.msg.core.RuleEngineError; | ||
56 | +import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg; | ||
57 | +import org.thingsboard.server.common.msg.core.SessionCloseMsg; | ||
58 | +import org.thingsboard.server.common.msg.core.SessionCloseNotification; | ||
59 | +import org.thingsboard.server.common.msg.core.SessionOpenMsg; | ||
60 | +import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | ||
61 | +import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg; | ||
62 | +import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg; | ||
63 | +import org.thingsboard.server.common.msg.core.ToServerRpcRequestMsg; | ||
64 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | ||
35 | import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg; | 65 | import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg; |
66 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | ||
36 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; | 67 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
37 | -import org.thingsboard.server.common.msg.session.MsgType; | 68 | +import org.thingsboard.server.common.msg.session.SessionMsgType; |
38 | import org.thingsboard.server.common.msg.session.SessionType; | 69 | import org.thingsboard.server.common.msg.session.SessionType; |
39 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; | 70 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
40 | -import org.thingsboard.server.extensions.api.device.*; | ||
41 | -import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; | ||
42 | -import org.thingsboard.server.extensions.api.plugins.msg.RpcError; | ||
43 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutIntMsg; | ||
44 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | ||
45 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest; | ||
46 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestBody; | ||
47 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | ||
48 | -import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg; | ||
49 | - | ||
50 | -import java.util.*; | ||
51 | -import java.util.concurrent.ExecutionException; | 71 | +import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; |
72 | +import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | ||
73 | +import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | ||
74 | +import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | ||
75 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | ||
76 | +import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; | ||
77 | + | ||
78 | +import javax.annotation.Nullable; | ||
79 | +import java.util.ArrayList; | ||
80 | +import java.util.Arrays; | ||
81 | +import java.util.Collections; | ||
82 | +import java.util.HashMap; | ||
83 | +import java.util.HashSet; | ||
84 | +import java.util.LinkedHashMap; | ||
85 | +import java.util.List; | ||
86 | +import java.util.Map; | ||
87 | +import java.util.Optional; | ||
88 | +import java.util.Set; | ||
89 | +import java.util.UUID; | ||
52 | import java.util.concurrent.TimeoutException; | 90 | import java.util.concurrent.TimeoutException; |
53 | import java.util.function.Consumer; | 91 | import java.util.function.Consumer; |
54 | import java.util.function.Predicate; | 92 | import java.util.function.Predicate; |
@@ -59,46 +97,46 @@ import java.util.stream.Collectors; | @@ -59,46 +97,46 @@ import java.util.stream.Collectors; | ||
59 | */ | 97 | */ |
60 | public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | 98 | public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
61 | 99 | ||
100 | + private final TenantId tenantId; | ||
62 | private final DeviceId deviceId; | 101 | private final DeviceId deviceId; |
63 | private final Map<SessionId, SessionInfo> sessions; | 102 | private final Map<SessionId, SessionInfo> sessions; |
64 | private final Map<SessionId, SessionInfo> attributeSubscriptions; | 103 | private final Map<SessionId, SessionInfo> attributeSubscriptions; |
65 | private final Map<SessionId, SessionInfo> rpcSubscriptions; | 104 | private final Map<SessionId, SessionInfo> rpcSubscriptions; |
105 | + private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; | ||
106 | + private final Map<Integer, ToServerRpcRequestMetadata> toServerRpcPendingMap; | ||
107 | + private final Map<UUID, PendingSessionMsgData> pendingMsgs; | ||
66 | 108 | ||
67 | - private final Map<Integer, ToDeviceRpcRequestMetadata> rpcPendingMap; | 109 | + private final Gson gson = new Gson(); |
110 | + private final JsonParser jsonParser = new JsonParser(); | ||
68 | 111 | ||
69 | private int rpcSeq = 0; | 112 | private int rpcSeq = 0; |
70 | private String deviceName; | 113 | private String deviceName; |
71 | private String deviceType; | 114 | private String deviceType; |
72 | - private DeviceAttributes deviceAttributes; | 115 | + private TbMsgMetaData defaultMetaData; |
73 | 116 | ||
74 | - public DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, DeviceId deviceId) { | 117 | + public DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, DeviceId deviceId) { |
75 | super(systemContext, logger); | 118 | super(systemContext, logger); |
119 | + this.tenantId = tenantId; | ||
76 | this.deviceId = deviceId; | 120 | this.deviceId = deviceId; |
77 | - this.sessions = new HashMap<>(); | 121 | + this.sessions = new LinkedHashMap<>(); |
78 | this.attributeSubscriptions = new HashMap<>(); | 122 | this.attributeSubscriptions = new HashMap<>(); |
79 | this.rpcSubscriptions = new HashMap<>(); | 123 | this.rpcSubscriptions = new HashMap<>(); |
80 | - this.rpcPendingMap = new HashMap<>(); | 124 | + this.toDeviceRpcPendingMap = new HashMap<>(); |
125 | + this.toServerRpcPendingMap = new HashMap<>(); | ||
126 | + this.pendingMsgs = new HashMap<>(); | ||
81 | initAttributes(); | 127 | initAttributes(); |
82 | } | 128 | } |
83 | 129 | ||
84 | private void initAttributes() { | 130 | private void initAttributes() { |
85 | - //TODO: add invalidation of deviceType cache. | ||
86 | Device device = systemContext.getDeviceService().findDeviceById(deviceId); | 131 | Device device = systemContext.getDeviceService().findDeviceById(deviceId); |
87 | this.deviceName = device.getName(); | 132 | this.deviceName = device.getName(); |
88 | this.deviceType = device.getType(); | 133 | this.deviceType = device.getType(); |
89 | - this.deviceAttributes = new DeviceAttributes(fetchAttributes(DataConstants.CLIENT_SCOPE), | ||
90 | - fetchAttributes(DataConstants.SERVER_SCOPE), fetchAttributes(DataConstants.SHARED_SCOPE)); | 134 | + this.defaultMetaData = new TbMsgMetaData(); |
135 | + this.defaultMetaData.putValue("deviceName", deviceName); | ||
136 | + this.defaultMetaData.putValue("deviceType", deviceType); | ||
91 | } | 137 | } |
92 | 138 | ||
93 | - private void refreshAttributes(DeviceAttributesEventNotificationMsg msg) { | ||
94 | - if (msg.isDeleted()) { | ||
95 | - msg.getDeletedKeys().forEach(key -> deviceAttributes.remove(key)); | ||
96 | - } else { | ||
97 | - deviceAttributes.update(msg.getScope(), msg.getValues()); | ||
98 | - } | ||
99 | - } | ||
100 | - | ||
101 | - void processRpcRequest(ActorContext context, ToDeviceRpcRequestPluginMsg msg) { | 139 | + void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) { |
102 | ToDeviceRpcRequest request = msg.getMsg(); | 140 | ToDeviceRpcRequest request = msg.getMsg(); |
103 | ToDeviceRpcRequestBody body = request.getBody(); | 141 | ToDeviceRpcRequestBody body = request.getBody(); |
104 | ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( | 142 | ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( |
@@ -116,7 +154,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -116,7 +154,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
116 | boolean sent = rpcSubscriptions.size() > 0; | 154 | boolean sent = rpcSubscriptions.size() > 0; |
117 | Set<SessionId> syncSessionSet = new HashSet<>(); | 155 | Set<SessionId> syncSessionSet = new HashSet<>(); |
118 | rpcSubscriptions.entrySet().forEach(sub -> { | 156 | rpcSubscriptions.entrySet().forEach(sub -> { |
119 | - ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(rpcRequest, sub.getKey()); | 157 | + ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sub.getKey()); |
120 | sendMsgToSessionActor(response, sub.getValue().getServer()); | 158 | sendMsgToSessionActor(response, sub.getValue().getServer()); |
121 | if (SessionType.SYNC == sub.getValue().getType()) { | 159 | if (SessionType.SYNC == sub.getValue().getType()) { |
122 | syncSessionSet.add(sub.getKey()); | 160 | syncSessionSet.add(sub.getKey()); |
@@ -125,9 +163,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -125,9 +163,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
125 | syncSessionSet.forEach(rpcSubscriptions::remove); | 163 | syncSessionSet.forEach(rpcSubscriptions::remove); |
126 | 164 | ||
127 | if (request.isOneway() && sent) { | 165 | if (request.isOneway() && sent) { |
128 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(msg, (String) null); | ||
129 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | ||
130 | logger.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); | 166 | logger.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); |
167 | + systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(msg.getMsg().getId(), msg.getServerAddress(), null, null)); | ||
131 | } else { | 168 | } else { |
132 | registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); | 169 | registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); |
133 | } | 170 | } |
@@ -139,24 +176,46 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -139,24 +176,46 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
139 | 176 | ||
140 | } | 177 | } |
141 | 178 | ||
142 | - private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestPluginMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { | ||
143 | - rpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); | ||
144 | - TimeoutIntMsg timeoutMsg = new TimeoutIntMsg(rpcRequest.getRequestId(), timeout); | 179 | + private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { |
180 | + toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); | ||
181 | + DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); | ||
145 | scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout()); | 182 | scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout()); |
146 | } | 183 | } |
147 | 184 | ||
148 | - public void processTimeout(ActorContext context, TimeoutMsg msg) { | ||
149 | - ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(msg.getId()); | 185 | + void processServerSideRpcTimeout(ActorContext context, DeviceActorServerSideRpcTimeoutMsg msg) { |
186 | + ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); | ||
150 | if (requestMd != null) { | 187 | if (requestMd != null) { |
151 | logger.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); | 188 | logger.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); |
152 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(requestMd.getMsg(), requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION); | ||
153 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | 189 | + systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), |
190 | + requestMd.getMsg().getServerAddress(), null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); | ||
191 | + } | ||
192 | + } | ||
193 | + | ||
194 | + void processQueueTimeout(ActorContext context, DeviceActorQueueTimeoutMsg msg) { | ||
195 | + PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | ||
196 | + if (data != null) { | ||
197 | + logger.debug("[{}] Queue put [{}] timeout detected!", deviceId, msg.getId()); | ||
198 | + ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(data.getSessionMsgType(), RuleEngineError.QUEUE_PUT_TIMEOUT); | ||
199 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | ||
200 | + } | ||
201 | + } | ||
202 | + | ||
203 | + void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { | ||
204 | + PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | ||
205 | + if (data != null && data.isReplyOnQueueAck()) { | ||
206 | + int remainingAcks = data.getAckMsgCount() - 1; | ||
207 | + data.setAckMsgCount(remainingAcks); | ||
208 | + logger.debug("[{}] Queue put [{}] ack detected. Remaining acks: {}!", deviceId, msg.getId(), remainingAcks); | ||
209 | + if (remainingAcks == 0) { | ||
210 | + ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId()); | ||
211 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | ||
212 | + } | ||
154 | } | 213 | } |
155 | } | 214 | } |
156 | 215 | ||
157 | private void sendPendingRequests(ActorContext context, SessionId sessionId, SessionType type, Optional<ServerAddress> server) { | 216 | private void sendPendingRequests(ActorContext context, SessionId sessionId, SessionType type, Optional<ServerAddress> server) { |
158 | - if (!rpcPendingMap.isEmpty()) { | ||
159 | - logger.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, rpcPendingMap.size(), sessionId); | 217 | + if (!toDeviceRpcPendingMap.isEmpty()) { |
218 | + logger.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); | ||
160 | if (type == SessionType.SYNC) { | 219 | if (type == SessionType.SYNC) { |
161 | logger.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); | 220 | logger.debug("[{}] Cleanup sync rpc session [{}]", deviceId, sessionId); |
162 | rpcSubscriptions.remove(sessionId); | 221 | rpcSubscriptions.remove(sessionId); |
@@ -166,41 +225,196 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -166,41 +225,196 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
166 | } | 225 | } |
167 | Set<Integer> sentOneWayIds = new HashSet<>(); | 226 | Set<Integer> sentOneWayIds = new HashSet<>(); |
168 | if (type == SessionType.ASYNC) { | 227 | if (type == SessionType.ASYNC) { |
169 | - rpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, server, sentOneWayIds)); | 228 | + toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, server, sentOneWayIds)); |
170 | } else { | 229 | } else { |
171 | - rpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, server, sentOneWayIds)); | 230 | + toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, server, sentOneWayIds)); |
172 | } | 231 | } |
173 | 232 | ||
174 | - sentOneWayIds.forEach(rpcPendingMap::remove); | 233 | + sentOneWayIds.forEach(toDeviceRpcPendingMap::remove); |
175 | } | 234 | } |
176 | 235 | ||
177 | private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, SessionId sessionId, Optional<ServerAddress> server, Set<Integer> sentOneWayIds) { | 236 | private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, SessionId sessionId, Optional<ServerAddress> server, Set<Integer> sentOneWayIds) { |
178 | return entry -> { | 237 | return entry -> { |
238 | + ToDeviceRpcRequestActorMsg requestActorMsg = entry.getValue().getMsg(); | ||
179 | ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg(); | 239 | ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg(); |
180 | ToDeviceRpcRequestBody body = request.getBody(); | 240 | ToDeviceRpcRequestBody body = request.getBody(); |
181 | if (request.isOneway()) { | 241 | if (request.isOneway()) { |
182 | sentOneWayIds.add(entry.getKey()); | 242 | sentOneWayIds.add(entry.getKey()); |
183 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(entry.getValue().getMsg(), (String) null); | ||
184 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | 243 | + systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(request.getId(), requestActorMsg.getServerAddress(), null, null)); |
185 | } | 244 | } |
186 | ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( | 245 | ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( |
187 | entry.getKey(), | 246 | entry.getKey(), |
188 | body.getMethod(), | 247 | body.getMethod(), |
189 | body.getParams() | 248 | body.getParams() |
190 | ); | 249 | ); |
191 | - ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(rpcRequest, sessionId); | 250 | + ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(rpcRequest, sessionId); |
192 | sendMsgToSessionActor(response, server); | 251 | sendMsgToSessionActor(response, server); |
193 | }; | 252 | }; |
194 | } | 253 | } |
195 | 254 | ||
196 | - void process(ActorContext context, ToDeviceActorMsg msg) { | 255 | + void process(ActorContext context, DeviceToDeviceActorMsg msg) { |
197 | processSubscriptionCommands(context, msg); | 256 | processSubscriptionCommands(context, msg); |
198 | processRpcResponses(context, msg); | 257 | processRpcResponses(context, msg); |
199 | processSessionStateMsgs(msg); | 258 | processSessionStateMsgs(msg); |
259 | + | ||
260 | + SessionMsgType sessionMsgType = msg.getPayload().getMsgType(); | ||
261 | + if (sessionMsgType.requiresRulesProcessing()) { | ||
262 | + switch (sessionMsgType) { | ||
263 | + case GET_ATTRIBUTES_REQUEST: | ||
264 | + handleGetAttributesRequest(msg); | ||
265 | + break; | ||
266 | + case POST_ATTRIBUTES_REQUEST: | ||
267 | + handlePostAttributesRequest(context, msg); | ||
268 | + reportActivity(); | ||
269 | + break; | ||
270 | + case POST_TELEMETRY_REQUEST: | ||
271 | + handlePostTelemetryRequest(context, msg); | ||
272 | + reportActivity(); | ||
273 | + break; | ||
274 | + case TO_SERVER_RPC_REQUEST: | ||
275 | + handleClientSideRPCRequest(context, msg); | ||
276 | + reportActivity(); | ||
277 | + break; | ||
278 | + } | ||
279 | + } | ||
280 | + } | ||
281 | + | ||
282 | + private void reportActivity() { | ||
283 | + systemContext.getDeviceStateService().onDeviceActivity(deviceId); | ||
284 | + } | ||
285 | + | ||
286 | + private void reportSessionOpen() { | ||
287 | + systemContext.getDeviceStateService().onDeviceConnect(deviceId); | ||
288 | + } | ||
289 | + | ||
290 | + private void reportSessionClose() { | ||
291 | + systemContext.getDeviceStateService().onDeviceDisconnect(deviceId); | ||
292 | + } | ||
293 | + | ||
294 | + private void handleGetAttributesRequest(DeviceToDeviceActorMsg src) { | ||
295 | + GetAttributesRequest request = (GetAttributesRequest) src.getPayload(); | ||
296 | + ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, request.getClientAttributeNames()); | ||
297 | + ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, request.getClientAttributeNames()); | ||
298 | + | ||
299 | + Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() { | ||
300 | + @Override | ||
301 | + public void onSuccess(@Nullable List<List<AttributeKvEntry>> result) { | ||
302 | + BasicGetAttributesResponse response = BasicGetAttributesResponse.onSuccess(request.getMsgType(), | ||
303 | + request.getRequestId(), BasicAttributeKVMsg.from(result.get(0), result.get(1))); | ||
304 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(response, src.getSessionId()), src.getServerAddress()); | ||
305 | + } | ||
306 | + | ||
307 | + @Override | ||
308 | + public void onFailure(Throwable t) { | ||
309 | + if (t instanceof Exception) { | ||
310 | + ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onError(SessionMsgType.GET_ATTRIBUTES_REQUEST, request.getRequestId(), (Exception) t); | ||
311 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, src.getSessionId()), src.getServerAddress()); | ||
312 | + } else { | ||
313 | + logger.error("[{}] Failed to process attributes request", deviceId, t); | ||
314 | + } | ||
315 | + } | ||
316 | + }); | ||
317 | + } | ||
318 | + | ||
319 | + private ListenableFuture<List<AttributeKvEntry>> getAttributeKvEntries(DeviceId deviceId, String scope, Optional<Set<String>> names) { | ||
320 | + if (names.isPresent()) { | ||
321 | + if (!names.get().isEmpty()) { | ||
322 | + return systemContext.getAttributesService().find(deviceId, scope, names.get()); | ||
323 | + } else { | ||
324 | + return systemContext.getAttributesService().findAll(deviceId, scope); | ||
325 | + } | ||
326 | + } else { | ||
327 | + return Futures.immediateFuture(Collections.emptyList()); | ||
328 | + } | ||
329 | + } | ||
330 | + | ||
331 | + private void handlePostAttributesRequest(ActorContext context, DeviceToDeviceActorMsg src) { | ||
332 | + AttributesUpdateRequest request = (AttributesUpdateRequest) src.getPayload(); | ||
333 | + | ||
334 | + JsonObject json = new JsonObject(); | ||
335 | + for (AttributeKvEntry kv : request.getAttributes()) { | ||
336 | + kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
337 | + kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
338 | + kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
339 | + kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
340 | + } | ||
341 | + | ||
342 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
343 | + PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | ||
344 | + SessionMsgType.POST_ATTRIBUTES_REQUEST, request.getRequestId(), true, 1); | ||
345 | + pushToRuleEngineWithTimeout(context, tbMsg, msgData); | ||
346 | + } | ||
347 | + | ||
348 | + private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) { | ||
349 | + TelemetryUploadRequest request = (TelemetryUploadRequest) src.getPayload(); | ||
350 | + | ||
351 | + Map<Long, List<KvEntry>> tsData = request.getData(); | ||
352 | + | ||
353 | + PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), | ||
354 | + SessionMsgType.POST_TELEMETRY_REQUEST, request.getRequestId(), true, tsData.size()); | ||
355 | + | ||
356 | + for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) { | ||
357 | + JsonObject json = new JsonObject(); | ||
358 | + for (KvEntry kv : entry.getValue()) { | ||
359 | + kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
360 | + kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
361 | + kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
362 | + kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | ||
363 | + } | ||
364 | + TbMsgMetaData metaData = defaultMetaData.copy(); | ||
365 | + metaData.putValue("ts", entry.getKey() + ""); | ||
366 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
367 | + pushToRuleEngineWithTimeout(context, tbMsg, msgData); | ||
368 | + } | ||
369 | + } | ||
370 | + | ||
371 | + private void handleClientSideRPCRequest(ActorContext context, DeviceToDeviceActorMsg src) { | ||
372 | + ToServerRpcRequestMsg request = (ToServerRpcRequestMsg) src.getPayload(); | ||
373 | + | ||
374 | + JsonObject json = new JsonObject(); | ||
375 | + json.addProperty("method", request.getMethod()); | ||
376 | + json.add("params", jsonParser.parse(request.getParams())); | ||
377 | + | ||
378 | + TbMsgMetaData requestMetaData = defaultMetaData.copy(); | ||
379 | + requestMetaData.putValue("requestId", Integer.toString(request.getRequestId())); | ||
380 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.TO_SERVER_RPC_REQUEST.name(), deviceId, requestMetaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); | ||
381 | + PendingSessionMsgData msgData = new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), SessionMsgType.TO_SERVER_RPC_REQUEST, request.getRequestId(), false, 1); | ||
382 | + pushToRuleEngineWithTimeout(context, tbMsg, msgData); | ||
383 | + | ||
384 | + scheduleMsgWithDelay(context, new DeviceActorClientSideRpcTimeoutMsg(request.getRequestId(), systemContext.getClientSideRpcTimeout()), systemContext.getClientSideRpcTimeout()); | ||
385 | + toServerRpcPendingMap.put(request.getRequestId(), new ToServerRpcRequestMetadata(src.getSessionId(), src.getSessionType(), src.getServerAddress())); | ||
386 | + } | ||
387 | + | ||
388 | + public void processClientSideRpcTimeout(ActorContext context, DeviceActorClientSideRpcTimeoutMsg msg) { | ||
389 | + ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getId()); | ||
390 | + if (data != null) { | ||
391 | + logger.debug("[{}] Client side RPC request [{}] timeout detected!", deviceId, msg.getId()); | ||
392 | + ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(SessionMsgType.TO_SERVER_RPC_REQUEST, RuleEngineError.TIMEOUT); | ||
393 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServer()); | ||
394 | + } | ||
395 | + } | ||
396 | + | ||
397 | + void processToServerRPCResponse(ActorContext context, ToServerRpcResponseActorMsg msg) { | ||
398 | + ToServerRpcRequestMetadata data = toServerRpcPendingMap.remove(msg.getMsg().getRequestId()); | ||
399 | + if (data != null) { | ||
400 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(msg.getMsg(), data.getSessionId()), data.getServer()); | ||
401 | + } | ||
402 | + } | ||
403 | + | ||
404 | + private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, PendingSessionMsgData pendingMsgData) { | ||
405 | + SessionMsgType sessionMsgType = pendingMsgData.getSessionMsgType(); | ||
406 | + int requestId = pendingMsgData.getRequestId(); | ||
407 | + if (systemContext.isQueuePersistenceEnabled()) { | ||
408 | + pendingMsgs.put(tbMsg.getId(), pendingMsgData); | ||
409 | + scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout()); | ||
410 | + } else { | ||
411 | + ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), pendingMsgData.getSessionId()); | ||
412 | + sendMsgToSessionActor(response, pendingMsgData.getServerAddress()); | ||
413 | + } | ||
414 | + context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); | ||
200 | } | 415 | } |
201 | 416 | ||
202 | void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { | 417 | void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { |
203 | - refreshAttributes(msg); | ||
204 | if (attributeSubscriptions.size() > 0) { | 418 | if (attributeSubscriptions.size() > 0) { |
205 | ToDeviceMsg notification = null; | 419 | ToDeviceMsg notification = null; |
206 | if (msg.isDeleted()) { | 420 | if (msg.isDeleted()) { |
@@ -221,7 +435,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -221,7 +435,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
221 | if (notification != null) { | 435 | if (notification != null) { |
222 | ToDeviceMsg finalNotification = notification; | 436 | ToDeviceMsg finalNotification = notification; |
223 | attributeSubscriptions.entrySet().forEach(sub -> { | 437 | attributeSubscriptions.entrySet().forEach(sub -> { |
224 | - ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(finalNotification, sub.getKey()); | 438 | + ActorSystemToDeviceSessionActorMsg response = new BasicActorSystemToDeviceSessionActorMsg(finalNotification, sub.getKey()); |
225 | sendMsgToSessionActor(response, sub.getValue().getServer()); | 439 | sendMsgToSessionActor(response, sub.getValue().getServer()); |
226 | }); | 440 | }); |
227 | } | 441 | } |
@@ -230,50 +444,30 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -230,50 +444,30 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
230 | } | 444 | } |
231 | } | 445 | } |
232 | 446 | ||
233 | - void process(ActorContext context, RuleChainDeviceMsg srcMsg) { | ||
234 | - ChainProcessingMetaData md = new ChainProcessingMetaData(srcMsg.getRuleChain(), | ||
235 | - srcMsg.getToDeviceActorMsg(), new DeviceMetaData(deviceId, deviceName, deviceType, deviceAttributes), context.self()); | ||
236 | - ChainProcessingContext ctx = new ChainProcessingContext(md); | ||
237 | - if (ctx.getChainLength() > 0) { | ||
238 | - RuleProcessingMsg msg = new RuleProcessingMsg(ctx); | ||
239 | - ActorRef ruleActorRef = ctx.getCurrentActor(); | ||
240 | - ruleActorRef.tell(msg, ActorRef.noSender()); | ||
241 | - } else { | ||
242 | - context.self().tell(new RulesProcessedMsg(ctx), context.self()); | ||
243 | - } | ||
244 | - } | ||
245 | - | ||
246 | - void processRpcResponses(ActorContext context, ToDeviceActorMsg msg) { | 447 | + private void processRpcResponses(ActorContext context, DeviceToDeviceActorMsg msg) { |
247 | SessionId sessionId = msg.getSessionId(); | 448 | SessionId sessionId = msg.getSessionId(); |
248 | FromDeviceMsg inMsg = msg.getPayload(); | 449 | FromDeviceMsg inMsg = msg.getPayload(); |
249 | - if (inMsg.getMsgType() == MsgType.TO_DEVICE_RPC_RESPONSE) { | 450 | + if (inMsg.getMsgType() == SessionMsgType.TO_DEVICE_RPC_RESPONSE) { |
250 | logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); | 451 | logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); |
251 | ToDeviceRpcResponseMsg responseMsg = (ToDeviceRpcResponseMsg) inMsg; | 452 | ToDeviceRpcResponseMsg responseMsg = (ToDeviceRpcResponseMsg) inMsg; |
252 | - ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(responseMsg.getRequestId()); | 453 | + ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); |
253 | boolean success = requestMd != null; | 454 | boolean success = requestMd != null; |
254 | if (success) { | 455 | if (success) { |
255 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(requestMd.getMsg(), responseMsg.getData()); | ||
256 | - Optional<ServerAddress> pluginServerAddress = requestMd.getMsg().getServerAddress(); | ||
257 | - if (pluginServerAddress.isPresent()) { | ||
258 | - systemContext.getRpcService().tell(pluginServerAddress.get(), responsePluginMsg); | ||
259 | - logger.debug("[{}] Rpc command response sent to remote plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId()); | ||
260 | - } else { | ||
261 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | ||
262 | - logger.debug("[{}] Rpc command response sent to local plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId()); | ||
263 | - } | 456 | + systemContext.getDeviceRpcService().processRpcResponseFromDevice(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), |
457 | + requestMd.getMsg().getServerAddress(), responseMsg.getData(), null)); | ||
264 | } else { | 458 | } else { |
265 | logger.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); | 459 | logger.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); |
266 | } | 460 | } |
267 | if (msg.getSessionType() == SessionType.SYNC) { | 461 | if (msg.getSessionType() == SessionType.SYNC) { |
268 | BasicCommandAckResponse response = success | 462 | BasicCommandAckResponse response = success |
269 | - ? BasicCommandAckResponse.onSuccess(MsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId()) | ||
270 | - : BasicCommandAckResponse.onError(MsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId(), new TimeoutException()); | ||
271 | - sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(response, msg.getSessionId()), msg.getServerAddress()); | 463 | + ? BasicCommandAckResponse.onSuccess(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId()) |
464 | + : BasicCommandAckResponse.onError(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId(), new TimeoutException()); | ||
465 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(response, msg.getSessionId()), msg.getServerAddress()); | ||
272 | } | 466 | } |
273 | } | 467 | } |
274 | } | 468 | } |
275 | 469 | ||
276 | - public void processClusterEventMsg(ClusterEventMsg msg) { | 470 | + void processClusterEventMsg(ClusterEventMsg msg) { |
277 | if (!msg.isAdded()) { | 471 | if (!msg.isAdded()) { |
278 | logger.debug("[{}] Clearing attributes/rpc subscription for server [{}]", deviceId, msg.getServerAddress()); | 472 | logger.debug("[{}] Clearing attributes/rpc subscription for server [{}]", deviceId, msg.getServerAddress()); |
279 | Predicate<Map.Entry<SessionId, SessionInfo>> filter = e -> e.getValue().getServer() | 473 | Predicate<Map.Entry<SessionId, SessionInfo>> filter = e -> e.getValue().getServer() |
@@ -283,102 +477,79 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | @@ -283,102 +477,79 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso | ||
283 | } | 477 | } |
284 | } | 478 | } |
285 | 479 | ||
286 | - private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, String data) { | ||
287 | - return toPluginRpcResponseMsg(requestMsg, data, null); | ||
288 | - } | ||
289 | - | ||
290 | - private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, RpcError error) { | ||
291 | - return toPluginRpcResponseMsg(requestMsg, null, error); | ||
292 | - } | ||
293 | - | ||
294 | - private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, String data, RpcError error) { | ||
295 | - return new ToPluginRpcResponseDeviceMsg( | ||
296 | - requestMsg.getPluginId(), | ||
297 | - requestMsg.getPluginTenantId(), | ||
298 | - new FromDeviceRpcResponse(requestMsg.getMsg().getId(), | ||
299 | - data, | ||
300 | - error | ||
301 | - ) | ||
302 | - ); | ||
303 | - } | ||
304 | - | ||
305 | - void onRulesProcessedMsg(ActorContext context, RulesProcessedMsg msg) { | ||
306 | - ChainProcessingContext ctx = msg.getCtx(); | ||
307 | - ToDeviceActorMsg inMsg = ctx.getInMsg(); | ||
308 | - SessionId sid = inMsg.getSessionId(); | ||
309 | - ToDeviceSessionActorMsg response; | ||
310 | - if (ctx.getResponse() != null) { | ||
311 | - response = new BasicToDeviceSessionActorMsg(ctx.getResponse(), sid); | ||
312 | - } else { | ||
313 | - response = new BasicToDeviceSessionActorMsg(ctx.getError(), sid); | ||
314 | - } | ||
315 | - sendMsgToSessionActor(response, inMsg.getServerAddress()); | ||
316 | - } | ||
317 | - | ||
318 | - private void processSubscriptionCommands(ActorContext context, ToDeviceActorMsg msg) { | 480 | + private void processSubscriptionCommands(ActorContext context, DeviceToDeviceActorMsg msg) { |
319 | SessionId sessionId = msg.getSessionId(); | 481 | SessionId sessionId = msg.getSessionId(); |
320 | SessionType sessionType = msg.getSessionType(); | 482 | SessionType sessionType = msg.getSessionType(); |
321 | FromDeviceMsg inMsg = msg.getPayload(); | 483 | FromDeviceMsg inMsg = msg.getPayload(); |
322 | - if (inMsg.getMsgType() == MsgType.SUBSCRIBE_ATTRIBUTES_REQUEST) { | 484 | + if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST) { |
323 | logger.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); | 485 | logger.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); |
324 | attributeSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); | 486 | attributeSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); |
325 | - } else if (inMsg.getMsgType() == MsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST) { | 487 | + } else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST) { |
326 | logger.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId); | 488 | logger.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId); |
327 | attributeSubscriptions.remove(sessionId); | 489 | attributeSubscriptions.remove(sessionId); |
328 | - } else if (inMsg.getMsgType() == MsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST) { | 490 | + } else if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST) { |
329 | logger.debug("[{}] Registering rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); | 491 | logger.debug("[{}] Registering rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); |
330 | rpcSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); | 492 | rpcSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); |
331 | sendPendingRequests(context, sessionId, sessionType, msg.getServerAddress()); | 493 | sendPendingRequests(context, sessionId, sessionType, msg.getServerAddress()); |
332 | - } else if (inMsg.getMsgType() == MsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST) { | 494 | + } else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST) { |
333 | logger.debug("[{}] Canceling rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); | 495 | logger.debug("[{}] Canceling rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); |
334 | rpcSubscriptions.remove(sessionId); | 496 | rpcSubscriptions.remove(sessionId); |
335 | } | 497 | } |
336 | } | 498 | } |
337 | 499 | ||
338 | - private void processSessionStateMsgs(ToDeviceActorMsg msg) { | 500 | + private void processSessionStateMsgs(DeviceToDeviceActorMsg msg) { |
339 | SessionId sessionId = msg.getSessionId(); | 501 | SessionId sessionId = msg.getSessionId(); |
340 | FromDeviceMsg inMsg = msg.getPayload(); | 502 | FromDeviceMsg inMsg = msg.getPayload(); |
341 | if (inMsg instanceof SessionOpenMsg) { | 503 | if (inMsg instanceof SessionOpenMsg) { |
342 | logger.debug("[{}] Processing new session [{}]", deviceId, sessionId); | 504 | logger.debug("[{}] Processing new session [{}]", deviceId, sessionId); |
505 | + if (sessions.size() >= systemContext.getMaxConcurrentSessionsPerDevice()) { | ||
506 | + SessionId sessionIdToRemove = sessions.keySet().stream().findFirst().orElse(null); | ||
507 | + if (sessionIdToRemove != null) { | ||
508 | + closeSession(sessionIdToRemove, sessions.remove(sessionIdToRemove)); | ||
509 | + } | ||
510 | + } | ||
343 | sessions.put(sessionId, new SessionInfo(SessionType.ASYNC, msg.getServerAddress())); | 511 | sessions.put(sessionId, new SessionInfo(SessionType.ASYNC, msg.getServerAddress())); |
512 | + if (sessions.size() == 1) { | ||
513 | + reportSessionOpen(); | ||
514 | + } | ||
344 | } else if (inMsg instanceof SessionCloseMsg) { | 515 | } else if (inMsg instanceof SessionCloseMsg) { |
345 | logger.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); | 516 | logger.debug("[{}] Canceling subscriptions for closed session [{}]", deviceId, sessionId); |
346 | sessions.remove(sessionId); | 517 | sessions.remove(sessionId); |
347 | attributeSubscriptions.remove(sessionId); | 518 | attributeSubscriptions.remove(sessionId); |
348 | rpcSubscriptions.remove(sessionId); | 519 | rpcSubscriptions.remove(sessionId); |
520 | + if (sessions.isEmpty()) { | ||
521 | + reportSessionClose(); | ||
522 | + } | ||
349 | } | 523 | } |
350 | } | 524 | } |
351 | 525 | ||
352 | - private void sendMsgToSessionActor(ToDeviceSessionActorMsg response, Optional<ServerAddress> sessionAddress) { | 526 | + private void sendMsgToSessionActor(ActorSystemToDeviceSessionActorMsg response, Optional<ServerAddress> sessionAddress) { |
353 | if (sessionAddress.isPresent()) { | 527 | if (sessionAddress.isPresent()) { |
354 | ServerAddress address = sessionAddress.get(); | 528 | ServerAddress address = sessionAddress.get(); |
355 | logger.debug("{} Forwarding msg: {}", address, response); | 529 | logger.debug("{} Forwarding msg: {}", address, response); |
356 | - systemContext.getRpcService().tell(sessionAddress.get(), response); | 530 | + systemContext.getRpcService().tell(systemContext.getEncodingService() |
531 | + .convertToProtoDataMessage(sessionAddress.get(), response)); | ||
357 | } else { | 532 | } else { |
358 | systemContext.getSessionManagerActor().tell(response, ActorRef.noSender()); | 533 | systemContext.getSessionManagerActor().tell(response, ActorRef.noSender()); |
359 | } | 534 | } |
360 | } | 535 | } |
361 | 536 | ||
362 | - private List<AttributeKvEntry> fetchAttributes(String scope) { | ||
363 | - try { | ||
364 | - //TODO: replace this with async operation. Happens only during actor creation, but is still criticla for performance, | ||
365 | - return systemContext.getAttributesService().findAll(this.deviceId, scope).get(); | ||
366 | - } catch (InterruptedException | ExecutionException e) { | ||
367 | - logger.warning("[{}] Failed to fetch attributes for scope: {}", deviceId, scope); | ||
368 | - throw new RuntimeException(e); | ||
369 | - } | ||
370 | - } | ||
371 | - | ||
372 | - public void processCredentialsUpdate() { | ||
373 | - sessions.forEach((k, v) -> { | ||
374 | - sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(new SessionCloseNotification(), k), v.getServer()); | ||
375 | - }); | 537 | + void processCredentialsUpdate() { |
538 | + sessions.forEach(this::closeSession); | ||
376 | attributeSubscriptions.clear(); | 539 | attributeSubscriptions.clear(); |
377 | rpcSubscriptions.clear(); | 540 | rpcSubscriptions.clear(); |
378 | } | 541 | } |
379 | 542 | ||
380 | - public void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { | 543 | + private void closeSession(SessionId sessionId, SessionInfo sessionInfo) { |
544 | + sendMsgToSessionActor(new BasicActorSystemToDeviceSessionActorMsg(new SessionCloseNotification(), sessionId), sessionInfo.getServer()); | ||
545 | + } | ||
546 | + | ||
547 | + void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { | ||
381 | this.deviceName = msg.getDeviceName(); | 548 | this.deviceName = msg.getDeviceName(); |
382 | this.deviceType = msg.getDeviceType(); | 549 | this.deviceType = msg.getDeviceType(); |
550 | + this.defaultMetaData = new TbMsgMetaData(); | ||
551 | + this.defaultMetaData.putValue("deviceName", deviceName); | ||
552 | + this.defaultMetaData.putValue("deviceType", deviceType); | ||
383 | } | 553 | } |
554 | + | ||
384 | } | 555 | } |
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorToRuleEngineMsg.java
renamed from
application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingMetaData.java
@@ -13,29 +13,25 @@ | @@ -13,29 +13,25 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.actors.rule; | 16 | +package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | import akka.actor.ActorRef; | 18 | import akka.actor.ActorRef; |
19 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | ||
20 | -import org.thingsboard.server.extensions.api.device.DeviceMetaData; | 19 | +import lombok.Data; |
20 | +import org.thingsboard.server.common.msg.MsgType; | ||
21 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
22 | +import org.thingsboard.server.common.msg.TbMsg; | ||
21 | 23 | ||
22 | /** | 24 | /** |
23 | - * Immutable part of chain processing data; | ||
24 | - * | ||
25 | - * @author ashvayka | 25 | + * Created by ashvayka on 15.03.18. |
26 | */ | 26 | */ |
27 | -public final class ChainProcessingMetaData { | 27 | +@Data |
28 | +public final class DeviceActorToRuleEngineMsg implements TbActorMsg { | ||
28 | 29 | ||
29 | - final RuleActorChain chain; | ||
30 | - final ToDeviceActorMsg inMsg; | ||
31 | - final ActorRef originator; | ||
32 | - final DeviceMetaData deviceMetaData; | 30 | + private final ActorRef callbackRef; |
31 | + private final TbMsg tbMsg; | ||
33 | 32 | ||
34 | - public ChainProcessingMetaData(RuleActorChain chain, ToDeviceActorMsg inMsg, DeviceMetaData deviceMetaData, ActorRef originator) { | ||
35 | - super(); | ||
36 | - this.chain = chain; | ||
37 | - this.inMsg = inMsg; | ||
38 | - this.originator = originator; | ||
39 | - this.deviceMetaData = deviceMetaData; | 33 | + @Override |
34 | + public MsgType getMsgType() { | ||
35 | + return MsgType.DEVICE_ACTOR_TO_RULE_ENGINE_MSG; | ||
40 | } | 36 | } |
41 | } | 37 | } |
application/src/main/java/org/thingsboard/server/actors/device/PendingSessionMsgData.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.actors.device; | ||
17 | + | ||
18 | +import lombok.AllArgsConstructor; | ||
19 | +import lombok.Data; | ||
20 | +import org.thingsboard.server.common.data.id.SessionId; | ||
21 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
22 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
23 | + | ||
24 | +import java.util.Optional; | ||
25 | + | ||
26 | +/** | ||
27 | + * Created by ashvayka on 17.04.18. | ||
28 | + */ | ||
29 | +@Data | ||
30 | +@AllArgsConstructor | ||
31 | +public final class PendingSessionMsgData { | ||
32 | + | ||
33 | + private final SessionId sessionId; | ||
34 | + private final Optional<ServerAddress> serverAddress; | ||
35 | + private final SessionMsgType sessionMsgType; | ||
36 | + private final int requestId; | ||
37 | + private final boolean replyOnQueueAck; | ||
38 | + private int ackMsgCount; | ||
39 | + | ||
40 | +} |
application/src/main/java/org/thingsboard/server/actors/device/RuleEngineQueuePutAckMsg.java
renamed from
application/src/main/java/org/thingsboard/server/actors/rule/RuleToPluginTimeoutMsg.java
@@ -13,24 +13,24 @@ | @@ -13,24 +13,24 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.actors.rule; | 16 | +package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | -import java.io.Serializable; | ||
19 | -import java.util.UUID; | ||
20 | - | ||
21 | -public class RuleToPluginTimeoutMsg implements Serializable { | 18 | +import lombok.Data; |
19 | +import org.thingsboard.server.common.msg.MsgType; | ||
20 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
22 | 21 | ||
23 | - private static final long serialVersionUID = 1L; | 22 | +import java.util.UUID; |
24 | 23 | ||
25 | - private final UUID msgId; | 24 | +/** |
25 | + * Created by ashvayka on 15.03.18. | ||
26 | + */ | ||
27 | +@Data | ||
28 | +public final class RuleEngineQueuePutAckMsg implements TbActorMsg { | ||
26 | 29 | ||
27 | - public RuleToPluginTimeoutMsg(UUID msgId) { | ||
28 | - super(); | ||
29 | - this.msgId = msgId; | ||
30 | - } | 30 | + private final UUID id; |
31 | 31 | ||
32 | - public UUID getMsgId() { | ||
33 | - return msgId; | 32 | + @Override |
33 | + public MsgType getMsgType() { | ||
34 | + return MsgType.RULE_ENGINE_QUEUE_PUT_ACK_MSG; | ||
34 | } | 35 | } |
35 | - | ||
36 | } | 36 | } |
@@ -16,7 +16,6 @@ | @@ -16,7 +16,6 @@ | ||
16 | package org.thingsboard.server.actors.device; | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.data.id.SessionId; | ||
20 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 19 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
21 | import org.thingsboard.server.common.msg.session.SessionType; | 20 | import org.thingsboard.server.common.msg.session.SessionType; |
22 | 21 |
@@ -16,13 +16,13 @@ | @@ -16,13 +16,13 @@ | ||
16 | package org.thingsboard.server.actors.device; | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | 19 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @author Andrew Shvayka | 22 | * @author Andrew Shvayka |
23 | */ | 23 | */ |
24 | @Data | 24 | @Data |
25 | public class ToDeviceRpcRequestMetadata { | 25 | public class ToDeviceRpcRequestMetadata { |
26 | - private final ToDeviceRpcRequestPluginMsg msg; | 26 | + private final ToDeviceRpcRequestActorMsg msg; |
27 | private final boolean sent; | 27 | private final boolean sent; |
28 | } | 28 | } |
application/src/main/java/org/thingsboard/server/actors/device/ToServerRpcRequestMetadata.java
renamed from
extensions-core/src/main/java/org/thingsboard/server/extensions/core/action/rpc/ServerSideRpcCallActionConfiguration.java
@@ -13,22 +13,21 @@ | @@ -13,22 +13,21 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.extensions.core.action.rpc; | 16 | +package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | +import org.thingsboard.server.common.data.id.SessionId; | ||
20 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
21 | +import org.thingsboard.server.common.msg.session.SessionType; | ||
22 | + | ||
23 | +import java.util.Optional; | ||
19 | 24 | ||
20 | /** | 25 | /** |
21 | * @author Andrew Shvayka | 26 | * @author Andrew Shvayka |
22 | */ | 27 | */ |
23 | @Data | 28 | @Data |
24 | -public class ServerSideRpcCallActionConfiguration { | ||
25 | - | ||
26 | - private String sendFlag; | ||
27 | - | ||
28 | - private String deviceIdTemplate; | ||
29 | - private String rpcCallMethodTemplate; | ||
30 | - private String rpcCallBodyTemplate; | ||
31 | - private long rpcCallTimeoutInSec; | ||
32 | - private String fromDeviceRelationTemplate; | ||
33 | - private String toDeviceRelationTemplate; | 29 | +public class ToServerRpcRequestMetadata { |
30 | + private final SessionId sessionId; | ||
31 | + private final SessionType type; | ||
32 | + private final Optional<ServerAddress> server; | ||
34 | } | 33 | } |
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.plugin; | ||
17 | - | ||
18 | -import akka.actor.ActorContext; | ||
19 | -import akka.actor.ActorRef; | ||
20 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
21 | -import org.thingsboard.server.actors.service.ComponentActor; | ||
22 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
23 | -import org.thingsboard.server.actors.stats.StatsPersistTick; | ||
24 | -import org.thingsboard.server.common.data.id.PluginId; | ||
25 | -import org.thingsboard.server.common.data.id.TenantId; | ||
26 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
27 | -import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | ||
28 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | ||
29 | -import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg; | ||
30 | -import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg; | ||
31 | -import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; | ||
32 | -import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; | ||
33 | -import org.thingsboard.server.extensions.api.rules.RuleException; | ||
34 | - | ||
35 | -public class PluginActor extends ComponentActor<PluginId, PluginActorMessageProcessor> { | ||
36 | - | ||
37 | - private PluginActor(ActorSystemContext systemContext, TenantId tenantId, PluginId pluginId) { | ||
38 | - super(systemContext, tenantId, pluginId); | ||
39 | - setProcessor(new PluginActorMessageProcessor(tenantId, pluginId, systemContext, | ||
40 | - logger, context().parent(), context().self())); | ||
41 | - } | ||
42 | - | ||
43 | - @Override | ||
44 | - public void onReceive(Object msg) throws Exception { | ||
45 | - if (msg instanceof PluginWebsocketMsg) { | ||
46 | - onWebsocketMsg((PluginWebsocketMsg<?>) msg); | ||
47 | - } else if (msg instanceof PluginRestMsg) { | ||
48 | - onRestMsg((PluginRestMsg) msg); | ||
49 | - } else if (msg instanceof PluginCallbackMessage) { | ||
50 | - onPluginCallback((PluginCallbackMessage) msg); | ||
51 | - } else if (msg instanceof RuleToPluginMsgWrapper) { | ||
52 | - onRuleToPluginMsg((RuleToPluginMsgWrapper) msg); | ||
53 | - } else if (msg instanceof PluginRpcMsg) { | ||
54 | - onRpcMsg((PluginRpcMsg) msg); | ||
55 | - } else if (msg instanceof ClusterEventMsg) { | ||
56 | - onClusterEventMsg((ClusterEventMsg) msg); | ||
57 | - } else if (msg instanceof ComponentLifecycleMsg) { | ||
58 | - onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | ||
59 | - } else if (msg instanceof ToPluginRpcResponseDeviceMsg) { | ||
60 | - onRpcResponse((ToPluginRpcResponseDeviceMsg) msg); | ||
61 | - } else if (msg instanceof PluginTerminationMsg) { | ||
62 | - logger.info("[{}][{}] Going to terminate plugin actor.", tenantId, id); | ||
63 | - context().parent().tell(msg, ActorRef.noSender()); | ||
64 | - context().stop(self()); | ||
65 | - } else if (msg instanceof TimeoutMsg) { | ||
66 | - onTimeoutMsg(context(), (TimeoutMsg) msg); | ||
67 | - } else if (msg instanceof StatsPersistTick) { | ||
68 | - onStatsPersistTick(id); | ||
69 | - } else { | ||
70 | - logger.debug("[{}][{}] Unknown msg type.", tenantId, id, msg.getClass().getName()); | ||
71 | - } | ||
72 | - } | ||
73 | - | ||
74 | - private void onPluginCallback(PluginCallbackMessage msg) { | ||
75 | - try { | ||
76 | - processor.onPluginCallbackMsg(msg); | ||
77 | - } catch (Exception e) { | ||
78 | - logAndPersist("onPluginCallbackMsg", e); | ||
79 | - } | ||
80 | - } | ||
81 | - | ||
82 | - private void onTimeoutMsg(ActorContext context, TimeoutMsg msg) { | ||
83 | - processor.onTimeoutMsg(context, msg); | ||
84 | - } | ||
85 | - | ||
86 | - private void onRpcResponse(ToPluginRpcResponseDeviceMsg msg) { | ||
87 | - processor.onDeviceRpcMsg(msg.getResponse()); | ||
88 | - } | ||
89 | - | ||
90 | - private void onRuleToPluginMsg(RuleToPluginMsgWrapper msg) throws RuleException { | ||
91 | - logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg()); | ||
92 | - try { | ||
93 | - processor.onRuleToPluginMsg(msg); | ||
94 | - increaseMessagesProcessedCount(); | ||
95 | - } catch (Exception e) { | ||
96 | - logAndPersist("onRuleMsg", e); | ||
97 | - } | ||
98 | - } | ||
99 | - | ||
100 | - private void onWebsocketMsg(PluginWebsocketMsg<?> msg) { | ||
101 | - logger.debug("[{}] Going to process web socket msg: {}", id, msg); | ||
102 | - try { | ||
103 | - processor.onWebsocketMsg(msg); | ||
104 | - increaseMessagesProcessedCount(); | ||
105 | - } catch (Exception e) { | ||
106 | - logAndPersist("onWebsocketMsg", e); | ||
107 | - } | ||
108 | - } | ||
109 | - | ||
110 | - private void onRestMsg(PluginRestMsg msg) { | ||
111 | - logger.debug("[{}] Going to process rest msg: {}", id, msg); | ||
112 | - try { | ||
113 | - processor.onRestMsg(msg); | ||
114 | - increaseMessagesProcessedCount(); | ||
115 | - } catch (Exception e) { | ||
116 | - logAndPersist("onRestMsg", e); | ||
117 | - } | ||
118 | - } | ||
119 | - | ||
120 | - private void onRpcMsg(PluginRpcMsg msg) { | ||
121 | - try { | ||
122 | - logger.debug("[{}] Going to process rpc msg: {}", id, msg); | ||
123 | - processor.onRpcMsg(msg); | ||
124 | - } catch (Exception e) { | ||
125 | - logAndPersist("onRpcMsg", e); | ||
126 | - } | ||
127 | - } | ||
128 | - | ||
129 | - public static class ActorCreator extends ContextBasedCreator<PluginActor> { | ||
130 | - private static final long serialVersionUID = 1L; | ||
131 | - | ||
132 | - private final TenantId tenantId; | ||
133 | - private final PluginId pluginId; | ||
134 | - | ||
135 | - public ActorCreator(ActorSystemContext context, TenantId tenantId, PluginId pluginId) { | ||
136 | - super(context); | ||
137 | - this.tenantId = tenantId; | ||
138 | - this.pluginId = pluginId; | ||
139 | - } | ||
140 | - | ||
141 | - @Override | ||
142 | - public PluginActor create() throws Exception { | ||
143 | - return new PluginActor(context, tenantId, pluginId); | ||
144 | - } | ||
145 | - } | ||
146 | - | ||
147 | - @Override | ||
148 | - protected long getErrorPersistFrequency() { | ||
149 | - return systemContext.getPluginErrorPersistFrequency(); | ||
150 | - } | ||
151 | -} |
application/src/main/java/org/thingsboard/server/actors/plugin/PluginActorMessageProcessor.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.plugin; | ||
17 | - | ||
18 | -import akka.actor.ActorContext; | ||
19 | -import akka.actor.ActorRef; | ||
20 | -import akka.event.LoggingAdapter; | ||
21 | -import com.fasterxml.jackson.core.JsonProcessingException; | ||
22 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
23 | -import org.thingsboard.server.actors.shared.ComponentMsgProcessor; | ||
24 | -import org.thingsboard.server.common.data.id.PluginId; | ||
25 | -import org.thingsboard.server.common.data.id.TenantId; | ||
26 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | ||
27 | -import org.thingsboard.server.common.data.plugin.ComponentType; | ||
28 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | ||
29 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
30 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
31 | -import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; | ||
32 | -import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; | ||
33 | -import org.thingsboard.server.common.msg.session.MsgType; | ||
34 | -import org.thingsboard.server.extensions.api.plugins.Plugin; | ||
35 | -import org.thingsboard.server.extensions.api.plugins.PluginInitializationException; | ||
36 | -import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; | ||
37 | -import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; | ||
38 | -import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; | ||
39 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | ||
40 | -import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg; | ||
41 | -import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; | ||
42 | -import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; | ||
43 | -import org.thingsboard.server.extensions.api.rules.RuleException; | ||
44 | - | ||
45 | -/** | ||
46 | - * @author Andrew Shvayka | ||
47 | - */ | ||
48 | -public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> { | ||
49 | - | ||
50 | - private final SharedPluginProcessingContext pluginCtx; | ||
51 | - private final PluginProcessingContext trustedCtx; | ||
52 | - private PluginMetaData pluginMd; | ||
53 | - private Plugin pluginImpl; | ||
54 | - private ComponentLifecycleState state; | ||
55 | - | ||
56 | - | ||
57 | - protected PluginActorMessageProcessor(TenantId tenantId, PluginId pluginId, ActorSystemContext systemContext | ||
58 | - , LoggingAdapter logger, ActorRef parent, ActorRef self) { | ||
59 | - super(systemContext, logger, tenantId, pluginId); | ||
60 | - this.pluginCtx = new SharedPluginProcessingContext(systemContext, tenantId, pluginId, parent, self); | ||
61 | - this.trustedCtx = new PluginProcessingContext(pluginCtx, null); | ||
62 | - } | ||
63 | - | ||
64 | - @Override | ||
65 | - public void start() throws Exception { | ||
66 | - logger.info("[{}] Going to start plugin actor.", entityId); | ||
67 | - pluginMd = systemContext.getPluginService().findPluginById(entityId); | ||
68 | - if (pluginMd == null) { | ||
69 | - throw new PluginInitializationException("Plugin not found!"); | ||
70 | - } | ||
71 | - if (pluginMd.getConfiguration() == null) { | ||
72 | - throw new PluginInitializationException("Plugin metadata is empty!"); | ||
73 | - } | ||
74 | - state = pluginMd.getState(); | ||
75 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
76 | - logger.info("[{}] Plugin is active. Going to initialize plugin.", entityId); | ||
77 | - initComponent(); | ||
78 | - } else { | ||
79 | - logger.info("[{}] Plugin is suspended. Skipping plugin initialization.", entityId); | ||
80 | - } | ||
81 | - } | ||
82 | - | ||
83 | - @Override | ||
84 | - public void stop() throws Exception { | ||
85 | - onStop(); | ||
86 | - } | ||
87 | - | ||
88 | - private void initComponent() { | ||
89 | - try { | ||
90 | - pluginImpl = initComponent(pluginMd.getClazz(), ComponentType.PLUGIN, mapper.writeValueAsString(pluginMd.getConfiguration())); | ||
91 | - } catch (InstantiationException e) { | ||
92 | - throw new PluginInitializationException("No default constructor for plugin implementation!", e); | ||
93 | - } catch (IllegalAccessException e) { | ||
94 | - throw new PluginInitializationException("Illegal Access Exception during plugin initialization!", e); | ||
95 | - } catch (ClassNotFoundException e) { | ||
96 | - throw new PluginInitializationException("Plugin Class not found!", e); | ||
97 | - } catch (JsonProcessingException e) { | ||
98 | - throw new PluginInitializationException("Plugin Configuration is invalid!", e); | ||
99 | - } catch (Exception e) { | ||
100 | - throw new PluginInitializationException(e.getMessage(), e); | ||
101 | - } | ||
102 | - } | ||
103 | - | ||
104 | - public void onRuleToPluginMsg(RuleToPluginMsgWrapper msg) throws RuleException { | ||
105 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
106 | - try { | ||
107 | - pluginImpl.process(trustedCtx, msg.getRuleTenantId(), msg.getRuleId(), msg.getMsg()); | ||
108 | - } catch (Exception ex) { | ||
109 | - logger.debug("[{}] Failed to process RuleToPlugin msg: [{}] [{}]", tenantId, msg.getMsg(), ex); | ||
110 | - RuleToPluginMsg ruleMsg = msg.getMsg(); | ||
111 | - MsgType responceMsgType = MsgType.RULE_ENGINE_ERROR; | ||
112 | - Integer requestId = 0; | ||
113 | - if (ruleMsg.getPayload() instanceof FromDeviceRequestMsg) { | ||
114 | - requestId = ((FromDeviceRequestMsg) ruleMsg.getPayload()).getRequestId(); | ||
115 | - } | ||
116 | - trustedCtx.reply( | ||
117 | - new ResponsePluginToRuleMsg(ruleMsg.getUid(), tenantId, msg.getRuleId(), | ||
118 | - BasicStatusCodeResponse.onError(responceMsgType, requestId, ex))); | ||
119 | - } | ||
120 | - } else { | ||
121 | - //TODO: reply with plugin suspended message | ||
122 | - } | ||
123 | - } | ||
124 | - | ||
125 | - public void onWebsocketMsg(PluginWebsocketMsg<?> msg) { | ||
126 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
127 | - pluginImpl.process(new PluginProcessingContext(pluginCtx, msg.getSecurityCtx()), msg); | ||
128 | - } else { | ||
129 | - //TODO: reply with plugin suspended message | ||
130 | - } | ||
131 | - } | ||
132 | - | ||
133 | - public void onRestMsg(PluginRestMsg msg) { | ||
134 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
135 | - pluginImpl.process(new PluginProcessingContext(pluginCtx, msg.getSecurityCtx()), msg); | ||
136 | - } | ||
137 | - } | ||
138 | - | ||
139 | - public void onRpcMsg(PluginRpcMsg msg) { | ||
140 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
141 | - pluginImpl.process(trustedCtx, msg.getRpcMsg()); | ||
142 | - } else { | ||
143 | - //TODO: reply with plugin suspended message | ||
144 | - } | ||
145 | - } | ||
146 | - | ||
147 | - public void onPluginCallbackMsg(PluginCallbackMessage msg) { | ||
148 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
149 | - if (msg.isSuccess()) { | ||
150 | - msg.getCallback().onSuccess(trustedCtx, msg.getV()); | ||
151 | - } else { | ||
152 | - msg.getCallback().onFailure(trustedCtx, msg.getE()); | ||
153 | - } | ||
154 | - } else { | ||
155 | - //TODO: reply with plugin suspended message | ||
156 | - } | ||
157 | - } | ||
158 | - | ||
159 | - | ||
160 | - public void onTimeoutMsg(ActorContext context, TimeoutMsg<?> msg) { | ||
161 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
162 | - pluginImpl.process(trustedCtx, msg); | ||
163 | - } | ||
164 | - } | ||
165 | - | ||
166 | - | ||
167 | - public void onDeviceRpcMsg(FromDeviceRpcResponse response) { | ||
168 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
169 | - pluginImpl.process(trustedCtx, response); | ||
170 | - } | ||
171 | - } | ||
172 | - | ||
173 | - @Override | ||
174 | - public void onClusterEventMsg(ClusterEventMsg msg) { | ||
175 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
176 | - ServerAddress address = msg.getServerAddress(); | ||
177 | - if (msg.isAdded()) { | ||
178 | - logger.debug("[{}] Going to process server add msg: {}", entityId, address); | ||
179 | - pluginImpl.onServerAdded(trustedCtx, address); | ||
180 | - } else { | ||
181 | - logger.debug("[{}] Going to process server remove msg: {}", entityId, address); | ||
182 | - pluginImpl.onServerRemoved(trustedCtx, address); | ||
183 | - } | ||
184 | - } | ||
185 | - } | ||
186 | - | ||
187 | - @Override | ||
188 | - public void onCreated(ActorContext context) { | ||
189 | - logger.info("[{}] Going to process onCreated plugin.", entityId); | ||
190 | - } | ||
191 | - | ||
192 | - @Override | ||
193 | - public void onUpdate(ActorContext context) throws Exception { | ||
194 | - PluginMetaData oldPluginMd = pluginMd; | ||
195 | - pluginMd = systemContext.getPluginService().findPluginById(entityId); | ||
196 | - boolean requiresRestart = false; | ||
197 | - logger.info("[{}] Plugin configuration was updated from {} to {}.", entityId, oldPluginMd, pluginMd); | ||
198 | - if (!oldPluginMd.getClazz().equals(pluginMd.getClazz())) { | ||
199 | - logger.info("[{}] Plugin requires restart due to clazz change from {} to {}.", | ||
200 | - entityId, oldPluginMd.getClazz(), pluginMd.getClazz()); | ||
201 | - requiresRestart = true; | ||
202 | - } else if (!oldPluginMd.getConfiguration().equals(pluginMd.getConfiguration())) { | ||
203 | - logger.info("[{}] Plugin requires restart due to configuration change from {} to {}.", | ||
204 | - entityId, oldPluginMd.getConfiguration(), pluginMd.getConfiguration()); | ||
205 | - requiresRestart = true; | ||
206 | - } | ||
207 | - if (requiresRestart) { | ||
208 | - this.state = ComponentLifecycleState.SUSPENDED; | ||
209 | - if (pluginImpl != null) { | ||
210 | - pluginImpl.stop(trustedCtx); | ||
211 | - } | ||
212 | - start(); | ||
213 | - } | ||
214 | - } | ||
215 | - | ||
216 | - @Override | ||
217 | - public void onStop(ActorContext context) { | ||
218 | - onStop(); | ||
219 | - scheduleMsgWithDelay(context, new PluginTerminationMsg(entityId), systemContext.getPluginActorTerminationDelay()); | ||
220 | - } | ||
221 | - | ||
222 | - private void onStop() { | ||
223 | - logger.info("[{}] Going to process onStop plugin.", entityId); | ||
224 | - this.state = ComponentLifecycleState.SUSPENDED; | ||
225 | - if (pluginImpl != null) { | ||
226 | - pluginImpl.stop(trustedCtx); | ||
227 | - } | ||
228 | - } | ||
229 | - | ||
230 | - @Override | ||
231 | - public void onActivate(ActorContext context) throws Exception { | ||
232 | - logger.info("[{}] Going to process onActivate plugin.", entityId); | ||
233 | - this.state = ComponentLifecycleState.ACTIVE; | ||
234 | - if (pluginImpl != null) { | ||
235 | - pluginImpl.resume(trustedCtx); | ||
236 | - logger.info("[{}] Plugin resumed.", entityId); | ||
237 | - } else { | ||
238 | - start(); | ||
239 | - } | ||
240 | - } | ||
241 | - | ||
242 | - @Override | ||
243 | - public void onSuspend(ActorContext context) { | ||
244 | - logger.info("[{}] Going to process onSuspend plugin.", entityId); | ||
245 | - this.state = ComponentLifecycleState.SUSPENDED; | ||
246 | - if (pluginImpl != null) { | ||
247 | - pluginImpl.suspend(trustedCtx); | ||
248 | - } | ||
249 | - } | ||
250 | - | ||
251 | -} |
application/src/main/java/org/thingsboard/server/actors/plugin/PluginCallbackMessage.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.plugin; | ||
17 | - | ||
18 | -import lombok.Data; | ||
19 | -import lombok.Getter; | ||
20 | -import lombok.ToString; | ||
21 | -import org.thingsboard.server.extensions.api.plugins.PluginCallback; | ||
22 | - | ||
23 | -import java.util.Optional; | ||
24 | - | ||
25 | -/** | ||
26 | - * @author Andrew Shvayka | ||
27 | - */ | ||
28 | -@ToString | ||
29 | -public final class PluginCallbackMessage<V> { | ||
30 | - @Getter | ||
31 | - private final PluginCallback<V> callback; | ||
32 | - @Getter | ||
33 | - private final boolean success; | ||
34 | - @Getter | ||
35 | - private final V v; | ||
36 | - @Getter | ||
37 | - private final Exception e; | ||
38 | - | ||
39 | - public static <V> PluginCallbackMessage<V> onSuccess(PluginCallback<V> callback, V data) { | ||
40 | - return new PluginCallbackMessage<V>(true, callback, data, null); | ||
41 | - } | ||
42 | - | ||
43 | - public static <V> PluginCallbackMessage<V> onError(PluginCallback<V> callback, Exception e) { | ||
44 | - return new PluginCallbackMessage<V>(false, callback, null, e); | ||
45 | - } | ||
46 | - | ||
47 | - private PluginCallbackMessage(boolean success, PluginCallback<V> callback, V v, Exception e) { | ||
48 | - this.success = success; | ||
49 | - this.callback = callback; | ||
50 | - this.v = v; | ||
51 | - this.e = e; | ||
52 | - } | ||
53 | -} |
application/src/main/java/org/thingsboard/server/actors/plugin/PluginProcessingContext.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.plugin; | ||
17 | - | ||
18 | -import akka.actor.ActorRef; | ||
19 | -import com.google.common.base.Function; | ||
20 | -import com.google.common.util.concurrent.FutureCallback; | ||
21 | -import com.google.common.util.concurrent.Futures; | ||
22 | -import com.google.common.util.concurrent.ListenableFuture; | ||
23 | -import lombok.extern.slf4j.Slf4j; | ||
24 | -import org.thingsboard.server.common.data.Customer; | ||
25 | -import org.thingsboard.server.common.data.Device; | ||
26 | -import org.thingsboard.server.common.data.EntityType; | ||
27 | -import org.thingsboard.server.common.data.Tenant; | ||
28 | -import org.thingsboard.server.common.data.asset.Asset; | ||
29 | -import org.thingsboard.server.common.data.audit.ActionType; | ||
30 | -import org.thingsboard.server.common.data.id.*; | ||
31 | -import org.thingsboard.server.common.data.kv.AttributeKey; | ||
32 | -import org.thingsboard.server.common.data.kv.AttributeKvEntry; | ||
33 | -import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
34 | -import org.thingsboard.server.common.data.kv.TsKvQuery; | ||
35 | -import org.thingsboard.server.common.data.page.TextPageLink; | ||
36 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | ||
37 | -import org.thingsboard.server.common.data.relation.EntityRelation; | ||
38 | -import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
39 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | ||
40 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
41 | -import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; | ||
42 | -import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext; | ||
43 | -import org.thingsboard.server.extensions.api.plugins.PluginCallback; | ||
44 | -import org.thingsboard.server.extensions.api.plugins.PluginContext; | ||
45 | -import org.thingsboard.server.extensions.api.plugins.msg.*; | ||
46 | -import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; | ||
47 | -import org.thingsboard.server.extensions.api.plugins.rpc.RpcMsg; | ||
48 | -import org.thingsboard.server.extensions.api.plugins.ws.PluginWebsocketSessionRef; | ||
49 | -import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; | ||
50 | - | ||
51 | -import javax.annotation.Nullable; | ||
52 | -import java.io.IOException; | ||
53 | -import java.util.*; | ||
54 | -import java.util.concurrent.Executor; | ||
55 | -import java.util.concurrent.Executors; | ||
56 | -import java.util.stream.Collectors; | ||
57 | - | ||
58 | -@Slf4j | ||
59 | -public final class PluginProcessingContext implements PluginContext { | ||
60 | - | ||
61 | - private static final Executor executor = Executors.newSingleThreadExecutor(); | ||
62 | - public static final String CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "Customer user is not allowed to perform this operation!"; | ||
63 | - public static final String SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION = "System administrator is not allowed to perform this operation!"; | ||
64 | - public static final String DEVICE_WITH_REQUESTED_ID_NOT_FOUND = "Device with requested id wasn't found!"; | ||
65 | - | ||
66 | - private final SharedPluginProcessingContext pluginCtx; | ||
67 | - private final Optional<PluginApiCallSecurityContext> securityCtx; | ||
68 | - | ||
69 | - public PluginProcessingContext(SharedPluginProcessingContext pluginCtx, PluginApiCallSecurityContext securityCtx) { | ||
70 | - super(); | ||
71 | - this.pluginCtx = pluginCtx; | ||
72 | - this.securityCtx = Optional.ofNullable(securityCtx); | ||
73 | - } | ||
74 | - | ||
75 | - public void persistError(String method, Exception e) { | ||
76 | - pluginCtx.persistError(method, e); | ||
77 | - } | ||
78 | - | ||
79 | - @Override | ||
80 | - public void sendPluginRpcMsg(RpcMsg msg) { | ||
81 | - this.pluginCtx.rpcService.tell(new PluginRpcMsg(pluginCtx.tenantId, pluginCtx.pluginId, msg)); | ||
82 | - } | ||
83 | - | ||
84 | - @Override | ||
85 | - public void send(PluginWebsocketMsg<?> wsMsg) throws IOException { | ||
86 | - pluginCtx.msgEndpoint.send(wsMsg); | ||
87 | - } | ||
88 | - | ||
89 | - @Override | ||
90 | - public void close(PluginWebsocketSessionRef sessionRef) throws IOException { | ||
91 | - pluginCtx.msgEndpoint.close(sessionRef); | ||
92 | - } | ||
93 | - | ||
94 | - @Override | ||
95 | - public void saveAttributes(final TenantId tenantId, final EntityId entityId, final String scope, final List<AttributeKvEntry> attributes, final PluginCallback<Void> callback) { | ||
96 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
97 | - ListenableFuture<List<Void>> futures = pluginCtx.attributesService.save(entityId, scope, attributes); | ||
98 | - Futures.addCallback(futures, getListCallback(callback, v -> { | ||
99 | - if (entityId.getEntityType() == EntityType.DEVICE) { | ||
100 | - onDeviceAttributesChanged(tenantId, new DeviceId(entityId.getId()), scope, attributes); | ||
101 | - } | ||
102 | - return null; | ||
103 | - }), executor); | ||
104 | - })); | ||
105 | - } | ||
106 | - | ||
107 | - @Override | ||
108 | - public void removeAttributes(final TenantId tenantId, final EntityId entityId, final String scope, final List<String> keys, final PluginCallback<Void> callback) { | ||
109 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
110 | - ListenableFuture<List<Void>> futures = pluginCtx.attributesService.removeAll(entityId, scope, keys); | ||
111 | - Futures.addCallback(futures, getCallback(callback, v -> null), executor); | ||
112 | - if (entityId.getEntityType() == EntityType.DEVICE) { | ||
113 | - onDeviceAttributesDeleted(tenantId, new DeviceId(entityId.getId()), keys.stream().map(key -> new AttributeKey(scope, key)).collect(Collectors.toSet())); | ||
114 | - } | ||
115 | - })); | ||
116 | - } | ||
117 | - | ||
118 | - @Override | ||
119 | - public void loadAttribute(EntityId entityId, String attributeType, String attributeKey, final PluginCallback<Optional<AttributeKvEntry>> callback) { | ||
120 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
121 | - ListenableFuture<Optional<AttributeKvEntry>> future = pluginCtx.attributesService.find(entityId, attributeType, attributeKey); | ||
122 | - Futures.addCallback(future, getCallback(callback, v -> v), executor); | ||
123 | - })); | ||
124 | - } | ||
125 | - | ||
126 | - @Override | ||
127 | - public void loadAttributes(EntityId entityId, String attributeType, Collection<String> attributeKeys, final PluginCallback<List<AttributeKvEntry>> callback) { | ||
128 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
129 | - ListenableFuture<List<AttributeKvEntry>> future = pluginCtx.attributesService.find(entityId, attributeType, attributeKeys); | ||
130 | - Futures.addCallback(future, getCallback(callback, v -> v), executor); | ||
131 | - })); | ||
132 | - } | ||
133 | - | ||
134 | - @Override | ||
135 | - public void loadAttributes(EntityId entityId, String attributeType, PluginCallback<List<AttributeKvEntry>> callback) { | ||
136 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
137 | - ListenableFuture<List<AttributeKvEntry>> future = pluginCtx.attributesService.findAll(entityId, attributeType); | ||
138 | - Futures.addCallback(future, getCallback(callback, v -> v), executor); | ||
139 | - })); | ||
140 | - } | ||
141 | - | ||
142 | - @Override | ||
143 | - public void loadAttributes(final EntityId entityId, final Collection<String> attributeTypes, final PluginCallback<List<AttributeKvEntry>> callback) { | ||
144 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
145 | - List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>(); | ||
146 | - attributeTypes.forEach(attributeType -> futures.add(pluginCtx.attributesService.findAll(entityId, attributeType))); | ||
147 | - convertFuturesAndAddCallback(callback, futures); | ||
148 | - })); | ||
149 | - } | ||
150 | - | ||
151 | - @Override | ||
152 | - public void loadAttributes(final EntityId entityId, final Collection<String> attributeTypes, final Collection<String> attributeKeys, final PluginCallback<List<AttributeKvEntry>> callback) { | ||
153 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
154 | - List<ListenableFuture<List<AttributeKvEntry>>> futures = new ArrayList<>(); | ||
155 | - attributeTypes.forEach(attributeType -> futures.add(pluginCtx.attributesService.find(entityId, attributeType, attributeKeys))); | ||
156 | - convertFuturesAndAddCallback(callback, futures); | ||
157 | - })); | ||
158 | - } | ||
159 | - | ||
160 | - @Override | ||
161 | - public void saveTsData(final EntityId entityId, final TsKvEntry entry, final PluginCallback<Void> callback) { | ||
162 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
163 | - ListenableFuture<List<Void>> rsListFuture = pluginCtx.tsService.save(entityId, entry); | ||
164 | - Futures.addCallback(rsListFuture, getListCallback(callback, v -> null), executor); | ||
165 | - })); | ||
166 | - } | ||
167 | - | ||
168 | - @Override | ||
169 | - public void saveTsData(final EntityId entityId, final List<TsKvEntry> entries, final PluginCallback<Void> callback) { | ||
170 | - saveTsData(entityId, entries, 0L, callback); | ||
171 | - } | ||
172 | - | ||
173 | - @Override | ||
174 | - public void saveTsData(final EntityId entityId, final List<TsKvEntry> entries, long ttl, final PluginCallback<Void> callback) { | ||
175 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
176 | - ListenableFuture<List<Void>> rsListFuture = pluginCtx.tsService.save(entityId, entries, ttl); | ||
177 | - Futures.addCallback(rsListFuture, getListCallback(callback, v -> null), executor); | ||
178 | - })); | ||
179 | - } | ||
180 | - | ||
181 | - | ||
182 | - @Override | ||
183 | - public void loadTimeseries(final EntityId entityId, final List<TsKvQuery> queries, final PluginCallback<List<TsKvEntry>> callback) { | ||
184 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
185 | - ListenableFuture<List<TsKvEntry>> future = pluginCtx.tsService.findAll(entityId, queries); | ||
186 | - Futures.addCallback(future, getCallback(callback, v -> v), executor); | ||
187 | - })); | ||
188 | - } | ||
189 | - | ||
190 | - @Override | ||
191 | - public void loadLatestTimeseries(final EntityId entityId, final PluginCallback<List<TsKvEntry>> callback) { | ||
192 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
193 | - ListenableFuture<List<TsKvEntry>> future = pluginCtx.tsService.findAllLatest(entityId); | ||
194 | - Futures.addCallback(future, getCallback(callback, v -> v), executor); | ||
195 | - })); | ||
196 | - } | ||
197 | - | ||
198 | - @Override | ||
199 | - public void logAttributesUpdated(PluginApiCallSecurityContext ctx, EntityId entityId, String attributeType, | ||
200 | - List<AttributeKvEntry> attributes, Exception e) { | ||
201 | - pluginCtx.auditLogService.logEntityAction( | ||
202 | - ctx.getTenantId(), | ||
203 | - ctx.getCustomerId(), | ||
204 | - ctx.getUserId(), | ||
205 | - ctx.getUserName(), | ||
206 | - (UUIDBased & EntityId)entityId, | ||
207 | - null, | ||
208 | - ActionType.ATTRIBUTES_UPDATED, | ||
209 | - e, | ||
210 | - attributeType, | ||
211 | - attributes); | ||
212 | - } | ||
213 | - | ||
214 | - @Override | ||
215 | - public void logAttributesDeleted(PluginApiCallSecurityContext ctx, EntityId entityId, String attributeType, List<String> keys, Exception e) { | ||
216 | - pluginCtx.auditLogService.logEntityAction( | ||
217 | - ctx.getTenantId(), | ||
218 | - ctx.getCustomerId(), | ||
219 | - ctx.getUserId(), | ||
220 | - ctx.getUserName(), | ||
221 | - (UUIDBased & EntityId)entityId, | ||
222 | - null, | ||
223 | - ActionType.ATTRIBUTES_DELETED, | ||
224 | - e, | ||
225 | - attributeType, | ||
226 | - keys); | ||
227 | - } | ||
228 | - | ||
229 | - @Override | ||
230 | - public void logAttributesRead(PluginApiCallSecurityContext ctx, EntityId entityId, String attributeType, List<String> keys, Exception e) { | ||
231 | - pluginCtx.auditLogService.logEntityAction( | ||
232 | - ctx.getTenantId(), | ||
233 | - ctx.getCustomerId(), | ||
234 | - ctx.getUserId(), | ||
235 | - ctx.getUserName(), | ||
236 | - (UUIDBased & EntityId)entityId, | ||
237 | - null, | ||
238 | - ActionType.ATTRIBUTES_READ, | ||
239 | - e, | ||
240 | - attributeType, | ||
241 | - keys); | ||
242 | - } | ||
243 | - | ||
244 | - @Override | ||
245 | - public void loadLatestTimeseries(final EntityId entityId, final Collection<String> keys, final PluginCallback<List<TsKvEntry>> callback) { | ||
246 | - validate(entityId, new ValidationCallback(callback, ctx -> { | ||
247 | - ListenableFuture<List<TsKvEntry>> rsListFuture = pluginCtx.tsService.findLatest(entityId, keys); | ||
248 | - Futures.addCallback(rsListFuture, getCallback(callback, v -> v), executor); | ||
249 | - })); | ||
250 | - } | ||
251 | - | ||
252 | - @Override | ||
253 | - public void reply(PluginToRuleMsg<?> msg) { | ||
254 | - pluginCtx.parentActor.tell(msg, ActorRef.noSender()); | ||
255 | - } | ||
256 | - | ||
257 | - @Override | ||
258 | - public PluginId getPluginId() { | ||
259 | - return pluginCtx.pluginId; | ||
260 | - } | ||
261 | - | ||
262 | - @Override | ||
263 | - public Optional<PluginApiCallSecurityContext> getSecurityCtx() { | ||
264 | - return securityCtx; | ||
265 | - } | ||
266 | - | ||
267 | - private void onDeviceAttributesDeleted(TenantId tenantId, DeviceId deviceId, Set<AttributeKey> keys) { | ||
268 | - pluginCtx.toDeviceActor(DeviceAttributesEventNotificationMsg.onDelete(tenantId, deviceId, keys)); | ||
269 | - } | ||
270 | - | ||
271 | - private void onDeviceAttributesChanged(TenantId tenantId, DeviceId deviceId, String scope, List<AttributeKvEntry> values) { | ||
272 | - pluginCtx.toDeviceActor(DeviceAttributesEventNotificationMsg.onUpdate(tenantId, deviceId, scope, values)); | ||
273 | - } | ||
274 | - | ||
275 | - private <T, R> FutureCallback<List<T>> getListCallback(final PluginCallback<R> callback, Function<List<T>, R> transformer) { | ||
276 | - return new FutureCallback<List<T>>() { | ||
277 | - @Override | ||
278 | - public void onSuccess(@Nullable List<T> result) { | ||
279 | - pluginCtx.self().tell(PluginCallbackMessage.onSuccess(callback, transformer.apply(result)), ActorRef.noSender()); | ||
280 | - } | ||
281 | - | ||
282 | - @Override | ||
283 | - public void onFailure(Throwable t) { | ||
284 | - if (t instanceof Exception) { | ||
285 | - pluginCtx.self().tell(PluginCallbackMessage.onError(callback, (Exception) t), ActorRef.noSender()); | ||
286 | - } else { | ||
287 | - log.error("Critical error: {}", t.getMessage(), t); | ||
288 | - } | ||
289 | - } | ||
290 | - }; | ||
291 | - } | ||
292 | - | ||
293 | - private <T, R> FutureCallback<R> getCallback(final PluginCallback<T> callback, Function<R, T> transformer) { | ||
294 | - return new FutureCallback<R>() { | ||
295 | - @Override | ||
296 | - public void onSuccess(@Nullable R result) { | ||
297 | - try { | ||
298 | - pluginCtx.self().tell(PluginCallbackMessage.onSuccess(callback, transformer.apply(result)), ActorRef.noSender()); | ||
299 | - } catch (Exception e) { | ||
300 | - pluginCtx.self().tell(PluginCallbackMessage.onError(callback, e), ActorRef.noSender()); | ||
301 | - } | ||
302 | - } | ||
303 | - | ||
304 | - @Override | ||
305 | - public void onFailure(Throwable t) { | ||
306 | - if (t instanceof Exception) { | ||
307 | - pluginCtx.self().tell(PluginCallbackMessage.onError(callback, (Exception) t), ActorRef.noSender()); | ||
308 | - } else { | ||
309 | - log.error("Critical error: {}", t.getMessage(), t); | ||
310 | - } | ||
311 | - } | ||
312 | - }; | ||
313 | - } | ||
314 | - | ||
315 | - @Override | ||
316 | - public void checkAccess(DeviceId deviceId, PluginCallback<Void> callback) { | ||
317 | - validate(deviceId, new ValidationCallback(callback, ctx -> callback.onSuccess(ctx, null))); | ||
318 | - } | ||
319 | - | ||
320 | - private void validate(EntityId entityId, ValidationCallback callback) { | ||
321 | - if (securityCtx.isPresent()) { | ||
322 | - final PluginApiCallSecurityContext ctx = securityCtx.get(); | ||
323 | - switch (entityId.getEntityType()) { | ||
324 | - case DEVICE: | ||
325 | - validateDevice(ctx, entityId, callback); | ||
326 | - return; | ||
327 | - case ASSET: | ||
328 | - validateAsset(ctx, entityId, callback); | ||
329 | - return; | ||
330 | - case RULE: | ||
331 | - validateRule(ctx, entityId, callback); | ||
332 | - return; | ||
333 | - case PLUGIN: | ||
334 | - validatePlugin(ctx, entityId, callback); | ||
335 | - return; | ||
336 | - case CUSTOMER: | ||
337 | - validateCustomer(ctx, entityId, callback); | ||
338 | - return; | ||
339 | - case TENANT: | ||
340 | - validateTenant(ctx, entityId, callback); | ||
341 | - return; | ||
342 | - default: | ||
343 | - //TODO: add support of other entities | ||
344 | - throw new IllegalStateException("Not Implemented!"); | ||
345 | - } | ||
346 | - } else { | ||
347 | - callback.onSuccess(this, ValidationResult.ok()); | ||
348 | - } | ||
349 | - } | ||
350 | - | ||
351 | - private void validateDevice(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { | ||
352 | - if (ctx.isSystemAdmin()) { | ||
353 | - callback.onSuccess(this, ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | ||
354 | - } else { | ||
355 | - ListenableFuture<Device> deviceFuture = pluginCtx.deviceService.findDeviceByIdAsync(new DeviceId(entityId.getId())); | ||
356 | - Futures.addCallback(deviceFuture, getCallback(callback, device -> { | ||
357 | - if (device == null) { | ||
358 | - return ValidationResult.entityNotFound(DEVICE_WITH_REQUESTED_ID_NOT_FOUND); | ||
359 | - } else { | ||
360 | - if (!device.getTenantId().equals(ctx.getTenantId())) { | ||
361 | - return ValidationResult.accessDenied("Device doesn't belong to the current Tenant!"); | ||
362 | - } else if (ctx.isCustomerUser() && !device.getCustomerId().equals(ctx.getCustomerId())) { | ||
363 | - return ValidationResult.accessDenied("Device doesn't belong to the current Customer!"); | ||
364 | - } else { | ||
365 | - return ValidationResult.ok(); | ||
366 | - } | ||
367 | - } | ||
368 | - })); | ||
369 | - } | ||
370 | - } | ||
371 | - | ||
372 | - private void validateAsset(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { | ||
373 | - if (ctx.isSystemAdmin()) { | ||
374 | - callback.onSuccess(this, ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | ||
375 | - } else { | ||
376 | - ListenableFuture<Asset> assetFuture = pluginCtx.assetService.findAssetByIdAsync(new AssetId(entityId.getId())); | ||
377 | - Futures.addCallback(assetFuture, getCallback(callback, asset -> { | ||
378 | - if (asset == null) { | ||
379 | - return ValidationResult.entityNotFound("Asset with requested id wasn't found!"); | ||
380 | - } else { | ||
381 | - if (!asset.getTenantId().equals(ctx.getTenantId())) { | ||
382 | - return ValidationResult.accessDenied("Asset doesn't belong to the current Tenant!"); | ||
383 | - } else if (ctx.isCustomerUser() && !asset.getCustomerId().equals(ctx.getCustomerId())) { | ||
384 | - return ValidationResult.accessDenied("Asset doesn't belong to the current Customer!"); | ||
385 | - } else { | ||
386 | - return ValidationResult.ok(); | ||
387 | - } | ||
388 | - } | ||
389 | - })); | ||
390 | - } | ||
391 | - } | ||
392 | - | ||
393 | - private void validateRule(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { | ||
394 | - if (ctx.isCustomerUser()) { | ||
395 | - callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | ||
396 | - } else { | ||
397 | - ListenableFuture<RuleMetaData> ruleFuture = pluginCtx.ruleService.findRuleByIdAsync(new RuleId(entityId.getId())); | ||
398 | - Futures.addCallback(ruleFuture, getCallback(callback, rule -> { | ||
399 | - if (rule == null) { | ||
400 | - return ValidationResult.entityNotFound("Rule with requested id wasn't found!"); | ||
401 | - } else { | ||
402 | - if (ctx.isTenantAdmin() && !rule.getTenantId().equals(ctx.getTenantId())) { | ||
403 | - return ValidationResult.accessDenied("Rule doesn't belong to the current Tenant!"); | ||
404 | - } else if (ctx.isSystemAdmin() && !rule.getTenantId().isNullUid()) { | ||
405 | - return ValidationResult.accessDenied("Rule is not in system scope!"); | ||
406 | - } else { | ||
407 | - return ValidationResult.ok(); | ||
408 | - } | ||
409 | - } | ||
410 | - })); | ||
411 | - } | ||
412 | - } | ||
413 | - | ||
414 | - private void validatePlugin(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { | ||
415 | - if (ctx.isCustomerUser()) { | ||
416 | - callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | ||
417 | - } else { | ||
418 | - ListenableFuture<PluginMetaData> pluginFuture = pluginCtx.pluginService.findPluginByIdAsync(new PluginId(entityId.getId())); | ||
419 | - Futures.addCallback(pluginFuture, getCallback(callback, plugin -> { | ||
420 | - if (plugin == null) { | ||
421 | - return ValidationResult.entityNotFound("Plugin with requested id wasn't found!"); | ||
422 | - } else { | ||
423 | - if (ctx.isTenantAdmin() && !plugin.getTenantId().equals(ctx.getTenantId())) { | ||
424 | - return ValidationResult.accessDenied("Plugin doesn't belong to the current Tenant!"); | ||
425 | - } else if (ctx.isSystemAdmin() && !plugin.getTenantId().isNullUid()) { | ||
426 | - return ValidationResult.accessDenied("Plugin is not in system scope!"); | ||
427 | - } else { | ||
428 | - return ValidationResult.ok(); | ||
429 | - } | ||
430 | - } | ||
431 | - })); | ||
432 | - } | ||
433 | - } | ||
434 | - | ||
435 | - private void validateCustomer(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { | ||
436 | - if (ctx.isSystemAdmin()) { | ||
437 | - callback.onSuccess(this, ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | ||
438 | - } else { | ||
439 | - ListenableFuture<Customer> customerFuture = pluginCtx.customerService.findCustomerByIdAsync(new CustomerId(entityId.getId())); | ||
440 | - Futures.addCallback(customerFuture, getCallback(callback, customer -> { | ||
441 | - if (customer == null) { | ||
442 | - return ValidationResult.entityNotFound("Customer with requested id wasn't found!"); | ||
443 | - } else { | ||
444 | - if (!customer.getTenantId().equals(ctx.getTenantId())) { | ||
445 | - return ValidationResult.accessDenied("Customer doesn't belong to the current Tenant!"); | ||
446 | - } else if (ctx.isCustomerUser() && !customer.getId().equals(ctx.getCustomerId())) { | ||
447 | - return ValidationResult.accessDenied("Customer doesn't relate to the currently authorized customer user!"); | ||
448 | - } else { | ||
449 | - return ValidationResult.ok(); | ||
450 | - } | ||
451 | - } | ||
452 | - })); | ||
453 | - } | ||
454 | - } | ||
455 | - | ||
456 | - private void validateTenant(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { | ||
457 | - if (ctx.isCustomerUser()) { | ||
458 | - callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | ||
459 | - } else if (ctx.isSystemAdmin()) { | ||
460 | - callback.onSuccess(this, ValidationResult.ok()); | ||
461 | - } else { | ||
462 | - ListenableFuture<Tenant> tenantFuture = pluginCtx.tenantService.findTenantByIdAsync(new TenantId(entityId.getId())); | ||
463 | - Futures.addCallback(tenantFuture, getCallback(callback, tenant -> { | ||
464 | - if (tenant == null) { | ||
465 | - return ValidationResult.entityNotFound("Tenant with requested id wasn't found!"); | ||
466 | - } else if (!tenant.getId().equals(ctx.getTenantId())) { | ||
467 | - return ValidationResult.accessDenied("Tenant doesn't relate to the currently authorized user!"); | ||
468 | - } else { | ||
469 | - return ValidationResult.ok(); | ||
470 | - } | ||
471 | - })); | ||
472 | - } | ||
473 | - } | ||
474 | - | ||
475 | - @Override | ||
476 | - public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType) { | ||
477 | - return this.pluginCtx.relationService.findByFromAndTypeAsync(from, relationType, RelationTypeGroup.COMMON); | ||
478 | - } | ||
479 | - | ||
480 | - @Override | ||
481 | - public ListenableFuture<List<EntityRelation>> findByToAndType(EntityId from, String relationType) { | ||
482 | - return this.pluginCtx.relationService.findByToAndTypeAsync(from, relationType, RelationTypeGroup.COMMON); | ||
483 | - } | ||
484 | - | ||
485 | - @Override | ||
486 | - public Optional<ServerAddress> resolve(EntityId entityId) { | ||
487 | - return pluginCtx.routingService.resolveById(entityId); | ||
488 | - } | ||
489 | - | ||
490 | - @Override | ||
491 | - public void getDevice(DeviceId deviceId, PluginCallback<Device> callback) { | ||
492 | - ListenableFuture<Device> deviceFuture = pluginCtx.deviceService.findDeviceByIdAsync(deviceId); | ||
493 | - Futures.addCallback(deviceFuture, getCallback(callback, v -> v)); | ||
494 | - } | ||
495 | - | ||
496 | - @Override | ||
497 | - public void getCustomerDevices(TenantId tenantId, CustomerId customerId, int limit, PluginCallback<List<Device>> callback) { | ||
498 | - //TODO: add caching here with async api. | ||
499 | - List<Device> devices = pluginCtx.deviceService.findDevicesByTenantIdAndCustomerId(tenantId, customerId, new TextPageLink(limit)).getData(); | ||
500 | - pluginCtx.self().tell(PluginCallbackMessage.onSuccess(callback, devices), ActorRef.noSender()); | ||
501 | - } | ||
502 | - | ||
503 | - @Override | ||
504 | - public void sendRpcRequest(ToDeviceRpcRequest msg) { | ||
505 | - pluginCtx.sendRpcRequest(msg); | ||
506 | - } | ||
507 | - | ||
508 | - @Override | ||
509 | - public void logRpcRequest(PluginApiCallSecurityContext ctx, DeviceId deviceId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Exception e) { | ||
510 | - String rpcErrorStr = ""; | ||
511 | - if (rpcError.isPresent()) { | ||
512 | - rpcErrorStr = "RPC Error: " + rpcError.get().name(); | ||
513 | - } | ||
514 | - String method = body.getMethod(); | ||
515 | - String params = body.getParams(); | ||
516 | - pluginCtx.auditLogService.logEntityAction( | ||
517 | - ctx.getTenantId(), | ||
518 | - ctx.getCustomerId(), | ||
519 | - ctx.getUserId(), | ||
520 | - ctx.getUserName(), | ||
521 | - deviceId, | ||
522 | - null, | ||
523 | - ActionType.RPC_CALL, | ||
524 | - e, | ||
525 | - rpcErrorStr, | ||
526 | - new Boolean(oneWay), | ||
527 | - method, | ||
528 | - params); | ||
529 | - } | ||
530 | - | ||
531 | - @Override | ||
532 | - public void scheduleTimeoutMsg(TimeoutMsg msg) { | ||
533 | - pluginCtx.scheduleTimeoutMsg(msg); | ||
534 | - } | ||
535 | - | ||
536 | - | ||
537 | - private void convertFuturesAndAddCallback(PluginCallback<List<AttributeKvEntry>> callback, List<ListenableFuture<List<AttributeKvEntry>>> futures) { | ||
538 | - ListenableFuture<List<AttributeKvEntry>> future = Futures.transform(Futures.successfulAsList(futures), | ||
539 | - (Function<? super List<List<AttributeKvEntry>>, ? extends List<AttributeKvEntry>>) input -> { | ||
540 | - List<AttributeKvEntry> result = new ArrayList<>(); | ||
541 | - input.forEach(r -> result.addAll(r)); | ||
542 | - return result; | ||
543 | - }, executor); | ||
544 | - Futures.addCallback(future, getCallback(callback, v -> v), executor); | ||
545 | - } | ||
546 | -} |
application/src/main/java/org/thingsboard/server/actors/plugin/RuleToPluginMsgWrapper.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.plugin; | ||
17 | - | ||
18 | -import org.thingsboard.server.common.data.id.PluginId; | ||
19 | -import org.thingsboard.server.common.data.id.RuleId; | ||
20 | -import org.thingsboard.server.common.data.id.TenantId; | ||
21 | -import org.thingsboard.server.common.msg.aware.RuleAwareMsg; | ||
22 | -import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; | ||
23 | -import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg; | ||
24 | - | ||
25 | -public class RuleToPluginMsgWrapper implements ToPluginActorMsg, RuleAwareMsg { | ||
26 | - | ||
27 | - private final TenantId pluginTenantId; | ||
28 | - private final PluginId pluginId; | ||
29 | - private final TenantId ruleTenantId; | ||
30 | - private final RuleId ruleId; | ||
31 | - private final RuleToPluginMsg<?> msg; | ||
32 | - | ||
33 | - public RuleToPluginMsgWrapper(TenantId pluginTenantId, PluginId pluginId, TenantId ruleTenantId, RuleId ruleId, RuleToPluginMsg<?> msg) { | ||
34 | - super(); | ||
35 | - this.pluginTenantId = pluginTenantId; | ||
36 | - this.pluginId = pluginId; | ||
37 | - this.ruleTenantId = ruleTenantId; | ||
38 | - this.ruleId = ruleId; | ||
39 | - this.msg = msg; | ||
40 | - } | ||
41 | - | ||
42 | - @Override | ||
43 | - public TenantId getPluginTenantId() { | ||
44 | - return pluginTenantId; | ||
45 | - } | ||
46 | - | ||
47 | - @Override | ||
48 | - public PluginId getPluginId() { | ||
49 | - return pluginId; | ||
50 | - } | ||
51 | - | ||
52 | - public TenantId getRuleTenantId() { | ||
53 | - return ruleTenantId; | ||
54 | - } | ||
55 | - | ||
56 | - @Override | ||
57 | - public RuleId getRuleId() { | ||
58 | - return ruleId; | ||
59 | - } | ||
60 | - | ||
61 | - | ||
62 | - public RuleToPluginMsg getMsg() { | ||
63 | - return msg; | ||
64 | - } | ||
65 | - | ||
66 | -} |
application/src/main/java/org/thingsboard/server/actors/plugin/SharedPluginProcessingContext.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.plugin; | ||
17 | - | ||
18 | -import akka.actor.ActorRef; | ||
19 | -import lombok.extern.slf4j.Slf4j; | ||
20 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
21 | -import org.thingsboard.server.common.data.Device; | ||
22 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
23 | -import org.thingsboard.server.common.data.id.EntityId; | ||
24 | -import org.thingsboard.server.common.data.id.TenantId; | ||
25 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
26 | -import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; | ||
27 | -import org.thingsboard.server.common.data.id.PluginId; | ||
28 | -import org.thingsboard.server.dao.asset.AssetService; | ||
29 | -import org.thingsboard.server.dao.attributes.AttributesService; | ||
30 | -import org.thingsboard.server.dao.audit.AuditLogService; | ||
31 | -import org.thingsboard.server.dao.customer.CustomerService; | ||
32 | -import org.thingsboard.server.dao.device.DeviceService; | ||
33 | -import org.thingsboard.server.dao.plugin.PluginService; | ||
34 | -import org.thingsboard.server.dao.relation.RelationService; | ||
35 | -import org.thingsboard.server.dao.rule.RuleService; | ||
36 | -import org.thingsboard.server.dao.tenant.TenantService; | ||
37 | -import org.thingsboard.server.dao.timeseries.TimeseriesService; | ||
38 | -import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; | ||
39 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | ||
40 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest; | ||
41 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | ||
42 | -import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | ||
43 | -import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | ||
44 | -import scala.concurrent.duration.Duration; | ||
45 | - | ||
46 | -import java.util.Optional; | ||
47 | -import java.util.concurrent.TimeUnit; | ||
48 | -import java.util.function.BiConsumer; | ||
49 | - | ||
50 | -@Slf4j | ||
51 | -public final class SharedPluginProcessingContext { | ||
52 | - final ActorRef parentActor; | ||
53 | - final ActorRef currentActor; | ||
54 | - final ActorSystemContext systemContext; | ||
55 | - final PluginWebSocketMsgEndpoint msgEndpoint; | ||
56 | - final AssetService assetService; | ||
57 | - final DeviceService deviceService; | ||
58 | - final RuleService ruleService; | ||
59 | - final PluginService pluginService; | ||
60 | - final CustomerService customerService; | ||
61 | - final TenantService tenantService; | ||
62 | - final TimeseriesService tsService; | ||
63 | - final AttributesService attributesService; | ||
64 | - final ClusterRpcService rpcService; | ||
65 | - final ClusterRoutingService routingService; | ||
66 | - final RelationService relationService; | ||
67 | - final AuditLogService auditLogService; | ||
68 | - final PluginId pluginId; | ||
69 | - final TenantId tenantId; | ||
70 | - | ||
71 | - public SharedPluginProcessingContext(ActorSystemContext sysContext, TenantId tenantId, PluginId pluginId, | ||
72 | - ActorRef parentActor, ActorRef self) { | ||
73 | - super(); | ||
74 | - this.tenantId = tenantId; | ||
75 | - this.pluginId = pluginId; | ||
76 | - this.parentActor = parentActor; | ||
77 | - this.currentActor = self; | ||
78 | - this.systemContext = sysContext; | ||
79 | - this.msgEndpoint = sysContext.getWsMsgEndpoint(); | ||
80 | - this.tsService = sysContext.getTsService(); | ||
81 | - this.attributesService = sysContext.getAttributesService(); | ||
82 | - this.assetService = sysContext.getAssetService(); | ||
83 | - this.deviceService = sysContext.getDeviceService(); | ||
84 | - this.rpcService = sysContext.getRpcService(); | ||
85 | - this.routingService = sysContext.getRoutingService(); | ||
86 | - this.ruleService = sysContext.getRuleService(); | ||
87 | - this.pluginService = sysContext.getPluginService(); | ||
88 | - this.customerService = sysContext.getCustomerService(); | ||
89 | - this.tenantService = sysContext.getTenantService(); | ||
90 | - this.relationService = sysContext.getRelationService(); | ||
91 | - this.auditLogService = sysContext.getAuditLogService(); | ||
92 | - } | ||
93 | - | ||
94 | - public PluginId getPluginId() { | ||
95 | - return pluginId; | ||
96 | - } | ||
97 | - | ||
98 | - public TenantId getPluginTenantId() { | ||
99 | - return tenantId; | ||
100 | - } | ||
101 | - | ||
102 | - public void toDeviceActor(DeviceAttributesEventNotificationMsg msg) { | ||
103 | - forward(msg.getDeviceId(), msg, rpcService::tell); | ||
104 | - } | ||
105 | - | ||
106 | - public void sendRpcRequest(ToDeviceRpcRequest msg) { | ||
107 | - log.trace("[{}] Forwarding msg {} to device actor!", pluginId, msg); | ||
108 | - ToDeviceRpcRequestPluginMsg rpcMsg = new ToDeviceRpcRequestPluginMsg(pluginId, tenantId, msg); | ||
109 | - forward(msg.getDeviceId(), rpcMsg, rpcService::tell); | ||
110 | - } | ||
111 | - | ||
112 | - private <T> void forward(DeviceId deviceId, T msg, BiConsumer<ServerAddress, T> rpcFunction) { | ||
113 | - Optional<ServerAddress> instance = routingService.resolveById(deviceId); | ||
114 | - if (instance.isPresent()) { | ||
115 | - log.trace("[{}] Forwarding msg {} to remote device actor!", pluginId, msg); | ||
116 | - rpcFunction.accept(instance.get(), msg); | ||
117 | - } else { | ||
118 | - log.trace("[{}] Forwarding msg {} to local device actor!", pluginId, msg); | ||
119 | - parentActor.tell(msg, ActorRef.noSender()); | ||
120 | - } | ||
121 | - } | ||
122 | - | ||
123 | - public void scheduleTimeoutMsg(TimeoutMsg msg) { | ||
124 | - log.debug("Scheduling msg {} with delay {} ms", msg, msg.getTimeout()); | ||
125 | - systemContext.getScheduler().scheduleOnce( | ||
126 | - Duration.create(msg.getTimeout(), TimeUnit.MILLISECONDS), | ||
127 | - currentActor, | ||
128 | - msg, | ||
129 | - systemContext.getActorSystem().dispatcher(), | ||
130 | - ActorRef.noSender()); | ||
131 | - | ||
132 | - } | ||
133 | - | ||
134 | - public void persistError(String method, Exception e) { | ||
135 | - systemContext.persistError(tenantId, pluginId, method, e); | ||
136 | - } | ||
137 | - | ||
138 | - public ActorRef self() { | ||
139 | - return currentActor; | ||
140 | - } | ||
141 | -} |
@@ -17,43 +17,23 @@ package org.thingsboard.server.actors.rpc; | @@ -17,43 +17,23 @@ package org.thingsboard.server.actors.rpc; | ||
17 | 17 | ||
18 | import akka.actor.ActorRef; | 18 | import akka.actor.ActorRef; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | -import org.springframework.util.SerializationUtils; | ||
21 | -import org.springframework.util.StringUtils; | ||
22 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
23 | import org.thingsboard.server.actors.service.ActorService; | 20 | import org.thingsboard.server.actors.service.ActorService; |
24 | -import org.thingsboard.server.common.data.id.DeviceId; | ||
25 | -import org.thingsboard.server.common.data.id.PluginId; | ||
26 | -import org.thingsboard.server.common.data.id.TenantId; | ||
27 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
28 | -import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; | ||
29 | -import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; | ||
30 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | ||
31 | -import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; | ||
32 | -import org.thingsboard.server.extensions.api.plugins.msg.*; | ||
33 | -import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; | ||
34 | -import org.thingsboard.server.extensions.api.plugins.rpc.RpcMsg; | ||
35 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | 21 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
36 | import org.thingsboard.server.service.cluster.rpc.GrpcSession; | 22 | import org.thingsboard.server.service.cluster.rpc.GrpcSession; |
37 | import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; | 23 | import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; |
38 | 24 | ||
39 | -import java.io.Serializable; | ||
40 | -import java.util.UUID; | ||
41 | - | ||
42 | /** | 25 | /** |
43 | * @author Andrew Shvayka | 26 | * @author Andrew Shvayka |
44 | */ | 27 | */ |
45 | @Slf4j | 28 | @Slf4j |
46 | public class BasicRpcSessionListener implements GrpcSessionListener { | 29 | public class BasicRpcSessionListener implements GrpcSessionListener { |
47 | 30 | ||
48 | - public static final String SESSION_RECEIVED_SESSION_ACTOR_MSG = "{} session [{}] received session actor msg {}"; | ||
49 | - private final ActorSystemContext context; | ||
50 | private final ActorService service; | 31 | private final ActorService service; |
51 | private final ActorRef manager; | 32 | private final ActorRef manager; |
52 | private final ActorRef self; | 33 | private final ActorRef self; |
53 | 34 | ||
54 | - public BasicRpcSessionListener(ActorSystemContext context, ActorRef manager, ActorRef self) { | ||
55 | - this.context = context; | ||
56 | - this.service = context.getActorService(); | 35 | + public BasicRpcSessionListener(ActorService service, ActorRef manager, ActorRef self) { |
36 | + this.service = service; | ||
57 | this.manager = manager; | 37 | this.manager = manager; |
58 | this.self = self; | 38 | this.self = self; |
59 | } | 39 | } |
@@ -73,47 +53,11 @@ public class BasicRpcSessionListener implements GrpcSessionListener { | @@ -73,47 +53,11 @@ public class BasicRpcSessionListener implements GrpcSessionListener { | ||
73 | } | 53 | } |
74 | 54 | ||
75 | @Override | 55 | @Override |
76 | - public void onToPluginRpcMsg(GrpcSession session, ClusterAPIProtos.ToPluginRpcMessage msg) { | ||
77 | - if (log.isTraceEnabled()) { | ||
78 | - log.trace("{} session [{}] received plugin msg {}", getType(session), session.getRemoteServer(), msg); | ||
79 | - } | ||
80 | - service.onMsg(convert(session.getRemoteServer(), msg)); | ||
81 | - } | ||
82 | - | ||
83 | - @Override | ||
84 | - public void onToDeviceActorRpcMsg(GrpcSession session, ClusterAPIProtos.ToDeviceActorRpcMessage msg) { | ||
85 | - log.trace("{} session [{}] received device actor msg {}", getType(session), session.getRemoteServer(), msg); | ||
86 | - service.onMsg((ToDeviceActorMsg) deserialize(msg.getData().toByteArray())); | ||
87 | - } | ||
88 | - | ||
89 | - @Override | ||
90 | - public void onToDeviceActorNotificationRpcMsg(GrpcSession session, ClusterAPIProtos.ToDeviceActorNotificationRpcMessage msg) { | ||
91 | - log.trace("{} session [{}] received device actor notification msg {}", getType(session), session.getRemoteServer(), msg); | ||
92 | - service.onMsg((ToDeviceActorNotificationMsg) deserialize(msg.getData().toByteArray())); | ||
93 | - } | ||
94 | - | ||
95 | - @Override | ||
96 | - public void onToDeviceSessionActorRpcMsg(GrpcSession session, ClusterAPIProtos.ToDeviceSessionActorRpcMessage msg) { | ||
97 | - log.trace(SESSION_RECEIVED_SESSION_ACTOR_MSG, getType(session), session.getRemoteServer(), msg); | ||
98 | - service.onMsg((ToDeviceSessionActorMsg) deserialize(msg.getData().toByteArray())); | ||
99 | - } | ||
100 | - | ||
101 | - @Override | ||
102 | - public void onToDeviceRpcRequestRpcMsg(GrpcSession session, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) { | ||
103 | - log.trace(SESSION_RECEIVED_SESSION_ACTOR_MSG, getType(session), session.getRemoteServer(), msg); | ||
104 | - service.onMsg(deserialize(session.getRemoteServer(), msg)); | ||
105 | - } | ||
106 | - | ||
107 | - @Override | ||
108 | - public void onFromDeviceRpcResponseRpcMsg(GrpcSession session, ClusterAPIProtos.ToPluginRpcResponseRpcMessage msg) { | ||
109 | - log.trace(SESSION_RECEIVED_SESSION_ACTOR_MSG, getType(session), session.getRemoteServer(), msg); | ||
110 | - service.onMsg(deserialize(session.getRemoteServer(), msg)); | ||
111 | - } | ||
112 | - | ||
113 | - @Override | ||
114 | - public void onToAllNodesRpcMessage(GrpcSession session, ClusterAPIProtos.ToAllNodesRpcMessage msg) { | ||
115 | - log.trace(SESSION_RECEIVED_SESSION_ACTOR_MSG, getType(session), session.getRemoteServer(), msg); | ||
116 | - service.onMsg((ToAllNodesMsg) deserialize(msg.getData().toByteArray())); | 56 | + public void onReceiveClusterGrpcMsg(GrpcSession session, ClusterAPIProtos.ClusterMessage clusterMessage) { |
57 | + log.trace("{} Service [{}] received session actor msg {}", getType(session), | ||
58 | + session.getRemoteServer(), | ||
59 | + clusterMessage); | ||
60 | + service.onReceivedMsg(session.getRemoteServer(), clusterMessage); | ||
117 | } | 61 | } |
118 | 62 | ||
119 | @Override | 63 | @Override |
@@ -127,45 +71,5 @@ public class BasicRpcSessionListener implements GrpcSessionListener { | @@ -127,45 +71,5 @@ public class BasicRpcSessionListener implements GrpcSessionListener { | ||
127 | return session.isClient() ? "Client" : "Server"; | 71 | return session.isClient() ? "Client" : "Server"; |
128 | } | 72 | } |
129 | 73 | ||
130 | - private static PluginRpcMsg convert(ServerAddress serverAddress, ClusterAPIProtos.ToPluginRpcMessage msg) { | ||
131 | - ClusterAPIProtos.PluginAddress address = msg.getAddress(); | ||
132 | - TenantId tenantId = new TenantId(toUUID(address.getTenantId())); | ||
133 | - PluginId pluginId = new PluginId(toUUID(address.getPluginId())); | ||
134 | - RpcMsg rpcMsg = new RpcMsg(serverAddress, msg.getClazz(), msg.getData().toByteArray()); | ||
135 | - return new PluginRpcMsg(tenantId, pluginId, rpcMsg); | ||
136 | - } | ||
137 | - | ||
138 | - private static UUID toUUID(ClusterAPIProtos.Uid uid) { | ||
139 | - return new UUID(uid.getPluginUuidMsb(), uid.getPluginUuidLsb()); | ||
140 | - } | ||
141 | - | ||
142 | - private static ToDeviceRpcRequestPluginMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) { | ||
143 | - ClusterAPIProtos.PluginAddress address = msg.getAddress(); | ||
144 | - TenantId pluginTenantId = new TenantId(toUUID(address.getTenantId())); | ||
145 | - PluginId pluginId = new PluginId(toUUID(address.getPluginId())); | ||
146 | - | ||
147 | - TenantId deviceTenantId = new TenantId(toUUID(msg.getDeviceTenantId())); | ||
148 | - DeviceId deviceId = new DeviceId(toUUID(msg.getDeviceId())); | ||
149 | - | ||
150 | - ToDeviceRpcRequestBody requestBody = new ToDeviceRpcRequestBody(msg.getMethod(), msg.getParams()); | ||
151 | - ToDeviceRpcRequest request = new ToDeviceRpcRequest(toUUID(msg.getMsgId()), null, deviceTenantId, deviceId, msg.getOneway(), msg.getExpTime(), requestBody); | ||
152 | - | ||
153 | - return new ToDeviceRpcRequestPluginMsg(serverAddress, pluginId, pluginTenantId, request); | ||
154 | - } | ||
155 | - | ||
156 | - private static ToPluginRpcResponseDeviceMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToPluginRpcResponseRpcMessage msg) { | ||
157 | - ClusterAPIProtos.PluginAddress address = msg.getAddress(); | ||
158 | - TenantId pluginTenantId = new TenantId(toUUID(address.getTenantId())); | ||
159 | - PluginId pluginId = new PluginId(toUUID(address.getPluginId())); | ||
160 | - | ||
161 | - RpcError error = !StringUtils.isEmpty(msg.getError()) ? RpcError.valueOf(msg.getError()) : null; | ||
162 | - FromDeviceRpcResponse response = new FromDeviceRpcResponse(toUUID(msg.getMsgId()), msg.getResponse(), error); | ||
163 | - return new ToPluginRpcResponseDeviceMsg(pluginId, pluginTenantId, response); | ||
164 | - } | ||
165 | - | ||
166 | - @SuppressWarnings("unchecked") | ||
167 | - private static <T extends Serializable> T deserialize(byte[] data) { | ||
168 | - return (T) SerializationUtils.deserialize(data); | ||
169 | - } | ||
170 | 74 | ||
171 | } | 75 | } |
@@ -23,5 +23,5 @@ import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | @@ -23,5 +23,5 @@ import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | ||
23 | */ | 23 | */ |
24 | @Data | 24 | @Data |
25 | public final class RpcBroadcastMsg { | 25 | public final class RpcBroadcastMsg { |
26 | - private final ClusterAPIProtos.ToRpcServerMessage msg; | 26 | + private final ClusterAPIProtos.ClusterMessage msg; |
27 | } | 27 | } |
@@ -23,12 +23,17 @@ import org.thingsboard.server.actors.ActorSystemContext; | @@ -23,12 +23,17 @@ import org.thingsboard.server.actors.ActorSystemContext; | ||
23 | import org.thingsboard.server.actors.service.ContextAwareActor; | 23 | import org.thingsboard.server.actors.service.ContextAwareActor; |
24 | import org.thingsboard.server.actors.service.ContextBasedCreator; | 24 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
25 | import org.thingsboard.server.actors.service.DefaultActorService; | 25 | import org.thingsboard.server.actors.service.DefaultActorService; |
26 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
26 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | 27 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
27 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 28 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
28 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | 29 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
29 | import org.thingsboard.server.service.cluster.discovery.ServerInstance; | 30 | import org.thingsboard.server.service.cluster.discovery.ServerInstance; |
30 | 31 | ||
31 | -import java.util.*; | 32 | +import java.util.HashMap; |
33 | +import java.util.LinkedList; | ||
34 | +import java.util.Map; | ||
35 | +import java.util.Queue; | ||
36 | +import java.util.UUID; | ||
32 | 37 | ||
33 | /** | 38 | /** |
34 | * @author Andrew Shvayka | 39 | * @author Andrew Shvayka |
@@ -39,7 +44,7 @@ public class RpcManagerActor extends ContextAwareActor { | @@ -39,7 +44,7 @@ public class RpcManagerActor extends ContextAwareActor { | ||
39 | 44 | ||
40 | private final Map<ServerAddress, SessionActorInfo> sessionActors; | 45 | private final Map<ServerAddress, SessionActorInfo> sessionActors; |
41 | 46 | ||
42 | - private final Map<ServerAddress, Queue<ClusterAPIProtos.ToRpcServerMessage>> pendingMsgs; | 47 | + private final Map<ServerAddress, Queue<ClusterAPIProtos.ClusterMessage>> pendingMsgs; |
43 | 48 | ||
44 | private final ServerAddress instance; | 49 | private final ServerAddress instance; |
45 | 50 | ||
@@ -57,9 +62,15 @@ public class RpcManagerActor extends ContextAwareActor { | @@ -57,9 +62,15 @@ public class RpcManagerActor extends ContextAwareActor { | ||
57 | } | 62 | } |
58 | 63 | ||
59 | @Override | 64 | @Override |
65 | + protected boolean process(TbActorMsg msg) { | ||
66 | + //TODO Move everything here, to work with TbActorMsg | ||
67 | + return false; | ||
68 | + } | ||
69 | + | ||
70 | + @Override | ||
60 | public void onReceive(Object msg) throws Exception { | 71 | public void onReceive(Object msg) throws Exception { |
61 | - if (msg instanceof RpcSessionTellMsg) { | ||
62 | - onMsg((RpcSessionTellMsg) msg); | 72 | + if (msg instanceof ClusterAPIProtos.ClusterMessage) { |
73 | + onMsg((ClusterAPIProtos.ClusterMessage) msg); | ||
63 | } else if (msg instanceof RpcBroadcastMsg) { | 74 | } else if (msg instanceof RpcBroadcastMsg) { |
64 | onMsg((RpcBroadcastMsg) msg); | 75 | onMsg((RpcBroadcastMsg) msg); |
65 | } else if (msg instanceof RpcSessionCreateRequestMsg) { | 76 | } else if (msg instanceof RpcSessionCreateRequestMsg) { |
@@ -77,24 +88,30 @@ public class RpcManagerActor extends ContextAwareActor { | @@ -77,24 +88,30 @@ public class RpcManagerActor extends ContextAwareActor { | ||
77 | 88 | ||
78 | private void onMsg(RpcBroadcastMsg msg) { | 89 | private void onMsg(RpcBroadcastMsg msg) { |
79 | log.debug("Forwarding msg to session actors {}", msg); | 90 | log.debug("Forwarding msg to session actors {}", msg); |
80 | - sessionActors.keySet().forEach(address -> onMsg(new RpcSessionTellMsg(address, msg.getMsg()))); | 91 | + sessionActors.keySet().forEach(address -> onMsg(msg.getMsg())); |
81 | pendingMsgs.values().forEach(queue -> queue.add(msg.getMsg())); | 92 | pendingMsgs.values().forEach(queue -> queue.add(msg.getMsg())); |
82 | } | 93 | } |
83 | 94 | ||
84 | - private void onMsg(RpcSessionTellMsg msg) { | ||
85 | - ServerAddress address = msg.getServerAddress(); | ||
86 | - SessionActorInfo session = sessionActors.get(address); | ||
87 | - if (session != null) { | ||
88 | - log.debug("{} Forwarding msg to session actor", address); | ||
89 | - session.actor.tell(msg, ActorRef.noSender()); | ||
90 | - } else { | ||
91 | - log.debug("{} Storing msg to pending queue", address); | ||
92 | - Queue<ClusterAPIProtos.ToRpcServerMessage> queue = pendingMsgs.get(address); | ||
93 | - if (queue == null) { | ||
94 | - queue = new LinkedList<>(); | ||
95 | - pendingMsgs.put(address, queue); | 95 | + private void onMsg(ClusterAPIProtos.ClusterMessage msg) { |
96 | + if (msg.hasServerAddress()) { | ||
97 | + ServerAddress address = new ServerAddress(msg.getServerAddress().getHost(), | ||
98 | + msg.getServerAddress().getPort()); | ||
99 | + SessionActorInfo session = sessionActors.get(address); | ||
100 | + if (session != null) { | ||
101 | + log.debug("{} Forwarding msg to session actor", address); | ||
102 | + session.getActor().tell(msg, ActorRef.noSender()); | ||
103 | + } else { | ||
104 | + log.debug("{} Storing msg to pending queue", address); | ||
105 | + Queue<ClusterAPIProtos.ClusterMessage> queue = pendingMsgs.get(address); | ||
106 | + if (queue == null) { | ||
107 | + queue = new LinkedList<>(); | ||
108 | + pendingMsgs.put(new ServerAddress( | ||
109 | + msg.getServerAddress().getHost(), msg.getServerAddress().getPort()), queue); | ||
110 | + } | ||
111 | + queue.add(msg); | ||
96 | } | 112 | } |
97 | - queue.add(msg.getMsg()); | 113 | + } else { |
114 | + logger.warning("Cluster msg doesn't have set Server Address [{}]", msg); | ||
98 | } | 115 | } |
99 | } | 116 | } |
100 | 117 | ||
@@ -141,7 +158,7 @@ public class RpcManagerActor extends ContextAwareActor { | @@ -141,7 +158,7 @@ public class RpcManagerActor extends ContextAwareActor { | ||
141 | private void onSessionClose(boolean reconnect, ServerAddress remoteAddress) { | 158 | private void onSessionClose(boolean reconnect, ServerAddress remoteAddress) { |
142 | log.debug("[{}] session closed. Should reconnect: {}", remoteAddress, reconnect); | 159 | log.debug("[{}] session closed. Should reconnect: {}", remoteAddress, reconnect); |
143 | SessionActorInfo sessionRef = sessionActors.get(remoteAddress); | 160 | SessionActorInfo sessionRef = sessionActors.get(remoteAddress); |
144 | - if (context().sender().equals(sessionRef.actor)) { | 161 | + if (context().sender() != null && context().sender().equals(sessionRef.actor)) { |
145 | sessionActors.remove(remoteAddress); | 162 | sessionActors.remove(remoteAddress); |
146 | pendingMsgs.remove(remoteAddress); | 163 | pendingMsgs.remove(remoteAddress); |
147 | if (reconnect) { | 164 | if (reconnect) { |
@@ -160,10 +177,10 @@ public class RpcManagerActor extends ContextAwareActor { | @@ -160,10 +177,10 @@ public class RpcManagerActor extends ContextAwareActor { | ||
160 | private void register(ServerAddress remoteAddress, UUID uuid, ActorRef sender) { | 177 | private void register(ServerAddress remoteAddress, UUID uuid, ActorRef sender) { |
161 | sessionActors.put(remoteAddress, new SessionActorInfo(uuid, sender)); | 178 | sessionActors.put(remoteAddress, new SessionActorInfo(uuid, sender)); |
162 | log.debug("[{}][{}] Registering session actor.", remoteAddress, uuid); | 179 | log.debug("[{}][{}] Registering session actor.", remoteAddress, uuid); |
163 | - Queue<ClusterAPIProtos.ToRpcServerMessage> data = pendingMsgs.remove(remoteAddress); | 180 | + Queue<ClusterAPIProtos.ClusterMessage> data = pendingMsgs.remove(remoteAddress); |
164 | if (data != null) { | 181 | if (data != null) { |
165 | log.debug("[{}][{}] Forwarding {} pending messages.", remoteAddress, uuid, data.size()); | 182 | log.debug("[{}][{}] Forwarding {} pending messages.", remoteAddress, uuid, data.size()); |
166 | - data.forEach(msg -> sender.tell(new RpcSessionTellMsg(remoteAddress, msg), ActorRef.noSender())); | 183 | + data.forEach(msg -> sender.tell(new RpcSessionTellMsg(msg), ActorRef.noSender())); |
167 | } else { | 184 | } else { |
168 | log.debug("[{}][{}] No pending messages to forward.", remoteAddress, uuid); | 185 | log.debug("[{}][{}] No pending messages to forward.", remoteAddress, uuid); |
169 | } | 186 | } |
@@ -23,6 +23,7 @@ import io.grpc.stub.StreamObserver; | @@ -23,6 +23,7 @@ import io.grpc.stub.StreamObserver; | ||
23 | import org.thingsboard.server.actors.ActorSystemContext; | 23 | import org.thingsboard.server.actors.ActorSystemContext; |
24 | import org.thingsboard.server.actors.service.ContextAwareActor; | 24 | import org.thingsboard.server.actors.service.ContextAwareActor; |
25 | import org.thingsboard.server.actors.service.ContextBasedCreator; | 25 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
26 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
26 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 27 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
27 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | 28 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
28 | import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; | 29 | import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; |
@@ -31,6 +32,8 @@ import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; | @@ -31,6 +32,8 @@ import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; | ||
31 | 32 | ||
32 | import java.util.UUID; | 33 | import java.util.UUID; |
33 | 34 | ||
35 | +import static org.thingsboard.server.gen.cluster.ClusterAPIProtos.MessageType.CONNECT_RPC_MESSAGE; | ||
36 | + | ||
34 | /** | 37 | /** |
35 | * @author Andrew Shvayka | 38 | * @author Andrew Shvayka |
36 | */ | 39 | */ |
@@ -48,16 +51,22 @@ public class RpcSessionActor extends ContextAwareActor { | @@ -48,16 +51,22 @@ public class RpcSessionActor extends ContextAwareActor { | ||
48 | } | 51 | } |
49 | 52 | ||
50 | @Override | 53 | @Override |
54 | + protected boolean process(TbActorMsg msg) { | ||
55 | + //TODO Move everything here, to work with TbActorMsg | ||
56 | + return false; | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
51 | public void onReceive(Object msg) throws Exception { | 60 | public void onReceive(Object msg) throws Exception { |
52 | - if (msg instanceof RpcSessionTellMsg) { | ||
53 | - tell((RpcSessionTellMsg) msg); | 61 | + if (msg instanceof ClusterAPIProtos.ClusterMessage) { |
62 | + tell((ClusterAPIProtos.ClusterMessage) msg); | ||
54 | } else if (msg instanceof RpcSessionCreateRequestMsg) { | 63 | } else if (msg instanceof RpcSessionCreateRequestMsg) { |
55 | initSession((RpcSessionCreateRequestMsg) msg); | 64 | initSession((RpcSessionCreateRequestMsg) msg); |
56 | } | 65 | } |
57 | } | 66 | } |
58 | 67 | ||
59 | - private void tell(RpcSessionTellMsg msg) { | ||
60 | - session.sendMsg(msg.getMsg()); | 68 | + private void tell(ClusterAPIProtos.ClusterMessage msg) { |
69 | + session.sendMsg(msg); | ||
61 | } | 70 | } |
62 | 71 | ||
63 | @Override | 72 | @Override |
@@ -69,7 +78,7 @@ public class RpcSessionActor extends ContextAwareActor { | @@ -69,7 +78,7 @@ public class RpcSessionActor extends ContextAwareActor { | ||
69 | private void initSession(RpcSessionCreateRequestMsg msg) { | 78 | private void initSession(RpcSessionCreateRequestMsg msg) { |
70 | log.info("[{}] Initializing session", context().self()); | 79 | log.info("[{}] Initializing session", context().self()); |
71 | ServerAddress remoteServer = msg.getRemoteAddress(); | 80 | ServerAddress remoteServer = msg.getRemoteAddress(); |
72 | - listener = new BasicRpcSessionListener(systemContext, context().parent(), context().self()); | 81 | + listener = new BasicRpcSessionListener(systemContext.getActorService(), context().parent(), context().self()); |
73 | if (msg.getRemoteAddress() == null) { | 82 | if (msg.getRemoteAddress() == null) { |
74 | // Server session | 83 | // Server session |
75 | session = new GrpcSession(listener); | 84 | session = new GrpcSession(listener); |
@@ -84,7 +93,7 @@ public class RpcSessionActor extends ContextAwareActor { | @@ -84,7 +93,7 @@ public class RpcSessionActor extends ContextAwareActor { | ||
84 | session.initInputStream(); | 93 | session.initInputStream(); |
85 | 94 | ||
86 | ClusterRpcServiceGrpc.ClusterRpcServiceStub stub = ClusterRpcServiceGrpc.newStub(channel); | 95 | ClusterRpcServiceGrpc.ClusterRpcServiceStub stub = ClusterRpcServiceGrpc.newStub(channel); |
87 | - StreamObserver<ClusterAPIProtos.ToRpcServerMessage> outputStream = stub.handlePluginMsgs(session.getInputStream()); | 96 | + StreamObserver<ClusterAPIProtos.ClusterMessage> outputStream = stub.handleMsgs(session.getInputStream()); |
88 | 97 | ||
89 | session.setOutputStream(outputStream); | 98 | session.setOutputStream(outputStream); |
90 | session.initOutputStream(); | 99 | session.initOutputStream(); |
@@ -108,11 +117,10 @@ public class RpcSessionActor extends ContextAwareActor { | @@ -108,11 +117,10 @@ public class RpcSessionActor extends ContextAwareActor { | ||
108 | } | 117 | } |
109 | } | 118 | } |
110 | 119 | ||
111 | - private ClusterAPIProtos.ToRpcServerMessage toConnectMsg() { | 120 | + private ClusterAPIProtos.ClusterMessage toConnectMsg() { |
112 | ServerAddress instance = systemContext.getDiscoveryService().getCurrentServer().getServerAddress(); | 121 | ServerAddress instance = systemContext.getDiscoveryService().getCurrentServer().getServerAddress(); |
113 | - return ClusterAPIProtos.ToRpcServerMessage.newBuilder().setConnectMsg( | ||
114 | - ClusterAPIProtos.ConnectRpcMessage.newBuilder().setServerAddress( | ||
115 | - ClusterAPIProtos.ServerAddress.newBuilder().setHost(instance.getHost()).setPort(instance.getPort()).build()).build()).build(); | ||
116 | - | 122 | + return ClusterAPIProtos.ClusterMessage.newBuilder().setMessageType(CONNECT_RPC_MESSAGE).setServerAddress( |
123 | + ClusterAPIProtos.ServerAddress.newBuilder().setHost(instance.getHost()) | ||
124 | + .setPort(instance.getPort()).build()).build(); | ||
117 | } | 125 | } |
118 | } | 126 | } |
@@ -30,6 +30,6 @@ public final class RpcSessionCreateRequestMsg { | @@ -30,6 +30,6 @@ public final class RpcSessionCreateRequestMsg { | ||
30 | 30 | ||
31 | private final UUID msgUid; | 31 | private final UUID msgUid; |
32 | private final ServerAddress remoteAddress; | 32 | private final ServerAddress remoteAddress; |
33 | - private final StreamObserver<ClusterAPIProtos.ToRpcServerMessage> responseObserver; | 33 | + private final StreamObserver<ClusterAPIProtos.ClusterMessage> responseObserver; |
34 | 34 | ||
35 | } | 35 | } |
@@ -16,7 +16,6 @@ | @@ -16,7 +16,6 @@ | ||
16 | package org.thingsboard.server.actors.rpc; | 16 | package org.thingsboard.server.actors.rpc; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.msg.cluster.ServerAddress; | ||
20 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | 19 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
21 | 20 | ||
22 | /** | 21 | /** |
@@ -24,6 +23,5 @@ import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | @@ -24,6 +23,5 @@ import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | ||
24 | */ | 23 | */ |
25 | @Data | 24 | @Data |
26 | public final class RpcSessionTellMsg { | 25 | public final class RpcSessionTellMsg { |
27 | - private final ServerAddress serverAddress; | ||
28 | - private final ClusterAPIProtos.ToRpcServerMessage msg; | 26 | + private final ClusterAPIProtos.ClusterMessage msg; |
29 | } | 27 | } |
application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingContext.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rule; | ||
17 | - | ||
18 | -import akka.actor.ActorRef; | ||
19 | -import org.thingsboard.server.common.msg.core.RuleEngineError; | ||
20 | -import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg; | ||
21 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | ||
22 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | ||
23 | -import org.thingsboard.server.extensions.api.device.DeviceAttributes; | ||
24 | -import org.thingsboard.server.extensions.api.device.DeviceMetaData; | ||
25 | - | ||
26 | -public class ChainProcessingContext { | ||
27 | - | ||
28 | - private final ChainProcessingMetaData md; | ||
29 | - private final int index; | ||
30 | - private final RuleEngineError error; | ||
31 | - private ToDeviceMsg response; | ||
32 | - | ||
33 | - | ||
34 | - public ChainProcessingContext(ChainProcessingMetaData md) { | ||
35 | - super(); | ||
36 | - this.md = md; | ||
37 | - this.index = 0; | ||
38 | - this.error = RuleEngineError.NO_RULES; | ||
39 | - } | ||
40 | - | ||
41 | - private ChainProcessingContext(ChainProcessingContext other, int indexOffset, RuleEngineError error) { | ||
42 | - super(); | ||
43 | - this.md = other.md; | ||
44 | - this.index = other.index + indexOffset; | ||
45 | - this.error = error; | ||
46 | - this.response = other.response; | ||
47 | - | ||
48 | - if (this.index < 0 || this.index >= this.md.chain.size()) { | ||
49 | - throw new IllegalArgumentException("Can't apply offset " + indexOffset + " to the chain!"); | ||
50 | - } | ||
51 | - } | ||
52 | - | ||
53 | - public ActorRef getDeviceActor() { | ||
54 | - return md.originator; | ||
55 | - } | ||
56 | - | ||
57 | - public ActorRef getCurrentActor() { | ||
58 | - return md.chain.getRuleActorMd(index).getActorRef(); | ||
59 | - } | ||
60 | - | ||
61 | - public boolean hasNext() { | ||
62 | - return (getChainLength() - 1) > index; | ||
63 | - } | ||
64 | - | ||
65 | - public boolean isFailure() { | ||
66 | - return (error != null && error.isCritical()) || (response != null && !response.isSuccess()); | ||
67 | - } | ||
68 | - | ||
69 | - public ChainProcessingContext getNext() { | ||
70 | - return new ChainProcessingContext(this, 1, this.error); | ||
71 | - } | ||
72 | - | ||
73 | - public ChainProcessingContext withError(RuleEngineError error) { | ||
74 | - if (error != null && (this.error == null || this.error.getPriority() < error.getPriority())) { | ||
75 | - return new ChainProcessingContext(this, 0, error); | ||
76 | - } else { | ||
77 | - return this; | ||
78 | - } | ||
79 | - } | ||
80 | - | ||
81 | - public int getChainLength() { | ||
82 | - return md.chain.size(); | ||
83 | - } | ||
84 | - | ||
85 | - public ToDeviceActorMsg getInMsg() { | ||
86 | - return md.inMsg; | ||
87 | - } | ||
88 | - | ||
89 | - public DeviceMetaData getDeviceMetaData() { | ||
90 | - return md.deviceMetaData; | ||
91 | - } | ||
92 | - | ||
93 | - public String getDeviceName() { | ||
94 | - return md.deviceMetaData.getDeviceName(); | ||
95 | - } | ||
96 | - | ||
97 | - public String getDeviceType() { | ||
98 | - return md.deviceMetaData.getDeviceType(); | ||
99 | - } | ||
100 | - | ||
101 | - public DeviceAttributes getAttributes() { | ||
102 | - return md.deviceMetaData.getDeviceAttributes(); | ||
103 | - } | ||
104 | - | ||
105 | - public ToDeviceMsg getResponse() { | ||
106 | - return response; | ||
107 | - } | ||
108 | - | ||
109 | - public void mergeResponse(ToDeviceMsg response) { | ||
110 | - // TODO add merge logic | ||
111 | - this.response = response; | ||
112 | - } | ||
113 | - | ||
114 | - public RuleEngineErrorMsg getError() { | ||
115 | - return new RuleEngineErrorMsg(md.inMsg.getPayload().getMsgType(), error); | ||
116 | - } | ||
117 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleActor.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rule; | ||
17 | - | ||
18 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
19 | -import org.thingsboard.server.actors.service.ComponentActor; | ||
20 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
21 | -import org.thingsboard.server.actors.stats.StatsPersistTick; | ||
22 | -import org.thingsboard.server.common.data.id.RuleId; | ||
23 | -import org.thingsboard.server.common.data.id.TenantId; | ||
24 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
25 | -import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | ||
26 | -import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; | ||
27 | - | ||
28 | -public class RuleActor extends ComponentActor<RuleId, RuleActorMessageProcessor> { | ||
29 | - | ||
30 | - private RuleActor(ActorSystemContext systemContext, TenantId tenantId, RuleId ruleId) { | ||
31 | - super(systemContext, tenantId, ruleId); | ||
32 | - setProcessor(new RuleActorMessageProcessor(tenantId, ruleId, systemContext, logger)); | ||
33 | - } | ||
34 | - | ||
35 | - @Override | ||
36 | - public void onReceive(Object msg) throws Exception { | ||
37 | - logger.debug("[{}] Received message: {}", id, msg); | ||
38 | - if (msg instanceof RuleProcessingMsg) { | ||
39 | - try { | ||
40 | - processor.onRuleProcessingMsg(context(), (RuleProcessingMsg) msg); | ||
41 | - increaseMessagesProcessedCount(); | ||
42 | - } catch (Exception e) { | ||
43 | - logAndPersist("onDeviceMsg", e); | ||
44 | - } | ||
45 | - } else if (msg instanceof PluginToRuleMsg<?>) { | ||
46 | - try { | ||
47 | - processor.onPluginMsg(context(), (PluginToRuleMsg<?>) msg); | ||
48 | - } catch (Exception e) { | ||
49 | - logAndPersist("onPluginMsg", e); | ||
50 | - } | ||
51 | - } else if (msg instanceof ComponentLifecycleMsg) { | ||
52 | - onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | ||
53 | - } else if (msg instanceof ClusterEventMsg) { | ||
54 | - onClusterEventMsg((ClusterEventMsg) msg); | ||
55 | - } else if (msg instanceof RuleToPluginTimeoutMsg) { | ||
56 | - try { | ||
57 | - processor.onTimeoutMsg(context(), (RuleToPluginTimeoutMsg) msg); | ||
58 | - } catch (Exception e) { | ||
59 | - logAndPersist("onTimeoutMsg", e); | ||
60 | - } | ||
61 | - } else if (msg instanceof StatsPersistTick) { | ||
62 | - onStatsPersistTick(id); | ||
63 | - } else { | ||
64 | - logger.debug("[{}][{}] Unknown msg type.", tenantId, id, msg.getClass().getName()); | ||
65 | - } | ||
66 | - } | ||
67 | - | ||
68 | - public static class ActorCreator extends ContextBasedCreator<RuleActor> { | ||
69 | - private static final long serialVersionUID = 1L; | ||
70 | - | ||
71 | - private final TenantId tenantId; | ||
72 | - private final RuleId ruleId; | ||
73 | - | ||
74 | - public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleId ruleId) { | ||
75 | - super(context); | ||
76 | - this.tenantId = tenantId; | ||
77 | - this.ruleId = ruleId; | ||
78 | - } | ||
79 | - | ||
80 | - @Override | ||
81 | - public RuleActor create() throws Exception { | ||
82 | - return new RuleActor(context, tenantId, ruleId); | ||
83 | - } | ||
84 | - } | ||
85 | - | ||
86 | - @Override | ||
87 | - protected long getErrorPersistFrequency() { | ||
88 | - return systemContext.getRuleErrorPersistFrequency(); | ||
89 | - } | ||
90 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMessageProcessor.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rule; | ||
17 | - | ||
18 | -import akka.actor.ActorContext; | ||
19 | -import akka.actor.ActorRef; | ||
20 | -import akka.event.LoggingAdapter; | ||
21 | -import com.fasterxml.jackson.core.JsonProcessingException; | ||
22 | -import org.springframework.util.StringUtils; | ||
23 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
24 | -import org.thingsboard.server.actors.plugin.RuleToPluginMsgWrapper; | ||
25 | -import org.thingsboard.server.actors.shared.ComponentMsgProcessor; | ||
26 | -import org.thingsboard.server.common.data.id.PluginId; | ||
27 | -import org.thingsboard.server.common.data.id.RuleId; | ||
28 | -import org.thingsboard.server.common.data.id.TenantId; | ||
29 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | ||
30 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | ||
31 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | ||
32 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | ||
33 | -import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; | ||
34 | -import org.thingsboard.server.common.msg.core.RuleEngineError; | ||
35 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | ||
36 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | ||
37 | -import org.thingsboard.server.extensions.api.plugins.PluginAction; | ||
38 | -import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; | ||
39 | -import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; | ||
40 | -import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; | ||
41 | -import org.thingsboard.server.extensions.api.rules.*; | ||
42 | - | ||
43 | -import java.util.*; | ||
44 | - | ||
45 | -class RuleActorMessageProcessor extends ComponentMsgProcessor<RuleId> { | ||
46 | - | ||
47 | - private final RuleProcessingContext ruleCtx; | ||
48 | - private final Map<UUID, RuleProcessingMsg> pendingMsgMap; | ||
49 | - | ||
50 | - private RuleMetaData ruleMd; | ||
51 | - private ComponentLifecycleState state; | ||
52 | - private List<RuleFilter> filters; | ||
53 | - private RuleProcessor processor; | ||
54 | - private PluginAction action; | ||
55 | - | ||
56 | - private TenantId pluginTenantId; | ||
57 | - private PluginId pluginId; | ||
58 | - | ||
59 | - protected RuleActorMessageProcessor(TenantId tenantId, RuleId ruleId, ActorSystemContext systemContext, LoggingAdapter logger) { | ||
60 | - super(systemContext, logger, tenantId, ruleId); | ||
61 | - this.pendingMsgMap = new HashMap<>(); | ||
62 | - this.ruleCtx = new RuleProcessingContext(systemContext, ruleId); | ||
63 | - } | ||
64 | - | ||
65 | - @Override | ||
66 | - public void start() throws Exception { | ||
67 | - logger.info("[{}][{}] Starting rule actor.", entityId, tenantId); | ||
68 | - ruleMd = systemContext.getRuleService().findRuleById(entityId); | ||
69 | - if (ruleMd == null) { | ||
70 | - throw new RuleInitializationException("Rule not found!"); | ||
71 | - } | ||
72 | - state = ruleMd.getState(); | ||
73 | - if (state == ComponentLifecycleState.ACTIVE) { | ||
74 | - logger.info("[{}] Rule is active. Going to initialize rule components.", entityId); | ||
75 | - initComponent(); | ||
76 | - } else { | ||
77 | - logger.info("[{}] Rule is suspended. Skipping rule components initialization.", entityId); | ||
78 | - } | ||
79 | - | ||
80 | - logger.info("[{}][{}] Started rule actor.", entityId, tenantId); | ||
81 | - } | ||
82 | - | ||
83 | - @Override | ||
84 | - public void stop() throws Exception { | ||
85 | - onStop(); | ||
86 | - } | ||
87 | - | ||
88 | - | ||
89 | - private void initComponent() throws RuleException { | ||
90 | - try { | ||
91 | - if (!ruleMd.getFilters().isArray()) { | ||
92 | - throw new RuntimeException("Filters are not array!"); | ||
93 | - } | ||
94 | - fetchPluginInfo(); | ||
95 | - initFilters(); | ||
96 | - initProcessor(); | ||
97 | - initAction(); | ||
98 | - } catch (RuntimeException e) { | ||
99 | - throw new RuleInitializationException("Unknown runtime exception!", e); | ||
100 | - } catch (InstantiationException e) { | ||
101 | - throw new RuleInitializationException("No default constructor for rule implementation!", e); | ||
102 | - } catch (IllegalAccessException e) { | ||
103 | - throw new RuleInitializationException("Illegal Access Exception during rule initialization!", e); | ||
104 | - } catch (ClassNotFoundException e) { | ||
105 | - throw new RuleInitializationException("Rule Class not found!", e); | ||
106 | - } catch (Exception e) { | ||
107 | - throw new RuleException(e.getMessage(), e); | ||
108 | - } | ||
109 | - } | ||
110 | - | ||
111 | - private void initAction() throws Exception { | ||
112 | - if (ruleMd.getAction() != null && !ruleMd.getAction().isNull()) { | ||
113 | - action = initComponent(ruleMd.getAction()); | ||
114 | - } | ||
115 | - } | ||
116 | - | ||
117 | - private void initProcessor() throws Exception { | ||
118 | - if (ruleMd.getProcessor() != null && !ruleMd.getProcessor().isNull()) { | ||
119 | - processor = initComponent(ruleMd.getProcessor()); | ||
120 | - } | ||
121 | - } | ||
122 | - | ||
123 | - private void initFilters() throws Exception { | ||
124 | - filters = new ArrayList<>(ruleMd.getFilters().size()); | ||
125 | - for (int i = 0; i < ruleMd.getFilters().size(); i++) { | ||
126 | - filters.add(initComponent(ruleMd.getFilters().get(i))); | ||
127 | - } | ||
128 | - } | ||
129 | - | ||
130 | - private void fetchPluginInfo() { | ||
131 | - if (!StringUtils.isEmpty(ruleMd.getPluginToken())) { | ||
132 | - PluginMetaData pluginMd = systemContext.getPluginService().findPluginByApiToken(ruleMd.getPluginToken()); | ||
133 | - pluginTenantId = pluginMd.getTenantId(); | ||
134 | - pluginId = pluginMd.getId(); | ||
135 | - } | ||
136 | - } | ||
137 | - | ||
138 | - protected void onRuleProcessingMsg(ActorContext context, RuleProcessingMsg msg) throws RuleException { | ||
139 | - if (state != ComponentLifecycleState.ACTIVE) { | ||
140 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_ACTIVE_RULES); | ||
141 | - return; | ||
142 | - } | ||
143 | - ChainProcessingContext chainCtx = msg.getCtx(); | ||
144 | - ToDeviceActorMsg inMsg = chainCtx.getInMsg(); | ||
145 | - | ||
146 | - ruleCtx.update(inMsg, chainCtx.getDeviceMetaData()); | ||
147 | - | ||
148 | - logger.debug("[{}] Going to filter in msg: {}", entityId, inMsg); | ||
149 | - for (RuleFilter filter : filters) { | ||
150 | - if (!filter.filter(ruleCtx, inMsg)) { | ||
151 | - logger.debug("[{}] In msg is NOT valid for processing by current rule: {}", entityId, inMsg); | ||
152 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_FILTERS_MATCHED); | ||
153 | - return; | ||
154 | - } | ||
155 | - } | ||
156 | - RuleProcessingMetaData inMsgMd; | ||
157 | - if (processor != null) { | ||
158 | - logger.debug("[{}] Going to process in msg: {}", entityId, inMsg); | ||
159 | - inMsgMd = processor.process(ruleCtx, inMsg); | ||
160 | - } else { | ||
161 | - inMsgMd = new RuleProcessingMetaData(); | ||
162 | - } | ||
163 | - logger.debug("[{}] Going to convert in msg: {}", entityId, inMsg); | ||
164 | - if (action != null) { | ||
165 | - Optional<RuleToPluginMsg<?>> ruleToPluginMsgOptional = action.convert(ruleCtx, inMsg, inMsgMd); | ||
166 | - if (ruleToPluginMsgOptional.isPresent()) { | ||
167 | - RuleToPluginMsg<?> ruleToPluginMsg = ruleToPluginMsgOptional.get(); | ||
168 | - logger.debug("[{}] Device msg is converted to: {}", entityId, ruleToPluginMsg); | ||
169 | - context.parent().tell(new RuleToPluginMsgWrapper(pluginTenantId, pluginId, tenantId, entityId, ruleToPluginMsg), context.self()); | ||
170 | - if (action.isOneWayAction()) { | ||
171 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_TWO_WAY_ACTIONS); | ||
172 | - return; | ||
173 | - } else { | ||
174 | - pendingMsgMap.put(ruleToPluginMsg.getUid(), msg); | ||
175 | - scheduleMsgWithDelay(context, new RuleToPluginTimeoutMsg(ruleToPluginMsg.getUid()), systemContext.getPluginProcessingTimeout()); | ||
176 | - return; | ||
177 | - } | ||
178 | - } | ||
179 | - } | ||
180 | - logger.debug("[{}] Nothing to send to plugin: {}", entityId, pluginId); | ||
181 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_TWO_WAY_ACTIONS); | ||
182 | - } | ||
183 | - | ||
184 | - void onPluginMsg(ActorContext context, PluginToRuleMsg<?> msg) { | ||
185 | - RuleProcessingMsg pendingMsg = pendingMsgMap.remove(msg.getUid()); | ||
186 | - if (pendingMsg != null) { | ||
187 | - ChainProcessingContext ctx = pendingMsg.getCtx(); | ||
188 | - if (isErrorResponce(msg)) { | ||
189 | - pushToNextRule(context, ctx, RuleEngineError.NO_RESPONSE_FROM_ACTIONS); | ||
190 | - } else { | ||
191 | - Optional<ToDeviceMsg> ruleResponseOptional = action.convert(msg); | ||
192 | - if (ruleResponseOptional.isPresent()) { | ||
193 | - ctx.mergeResponse(ruleResponseOptional.get()); | ||
194 | - pushToNextRule(context, ctx, null); | ||
195 | - } else { | ||
196 | - pushToNextRule(context, ctx, RuleEngineError.NO_RESPONSE_FROM_ACTIONS); | ||
197 | - } | ||
198 | - } | ||
199 | - } else { | ||
200 | - logger.warning("[{}] Processing timeout detected: [{}]", entityId, msg.getUid()); | ||
201 | - } | ||
202 | - } | ||
203 | - | ||
204 | - private boolean isErrorResponce(PluginToRuleMsg<?> msg) { | ||
205 | - if (msg instanceof ResponsePluginToRuleMsg) { | ||
206 | - if (((ResponsePluginToRuleMsg) msg).getPayload() instanceof BasicStatusCodeResponse) { | ||
207 | - BasicStatusCodeResponse responce = (BasicStatusCodeResponse) ((ResponsePluginToRuleMsg) msg).getPayload(); | ||
208 | - return !responce.isSuccess(); | ||
209 | - } | ||
210 | - } | ||
211 | - return false; | ||
212 | - } | ||
213 | - | ||
214 | - void onTimeoutMsg(ActorContext context, RuleToPluginTimeoutMsg msg) { | ||
215 | - RuleProcessingMsg pendingMsg = pendingMsgMap.remove(msg.getMsgId()); | ||
216 | - if (pendingMsg != null) { | ||
217 | - logger.debug("[{}] Processing timeout detected [{}]: {}", entityId, msg.getMsgId(), pendingMsg); | ||
218 | - ChainProcessingContext ctx = pendingMsg.getCtx(); | ||
219 | - pushToNextRule(context, ctx, RuleEngineError.PLUGIN_TIMEOUT); | ||
220 | - } | ||
221 | - } | ||
222 | - | ||
223 | - private void pushToNextRule(ActorContext context, ChainProcessingContext ctx, RuleEngineError error) { | ||
224 | - if (error != null) { | ||
225 | - ctx = ctx.withError(error); | ||
226 | - } | ||
227 | - if (ctx.isFailure()) { | ||
228 | - logger.debug("[{}][{}] Forwarding processing chain to device actor due to failure.", ruleMd.getId(), ctx.getInMsg().getDeviceId()); | ||
229 | - ctx.getDeviceActor().tell(new RulesProcessedMsg(ctx), ActorRef.noSender()); | ||
230 | - } else if (!ctx.hasNext()) { | ||
231 | - logger.debug("[{}][{}] Forwarding processing chain to device actor due to end of chain.", ruleMd.getId(), ctx.getInMsg().getDeviceId()); | ||
232 | - ctx.getDeviceActor().tell(new RulesProcessedMsg(ctx), ActorRef.noSender()); | ||
233 | - } else { | ||
234 | - logger.debug("[{}][{}] Forwarding processing chain to next rule actor.", ruleMd.getId(), ctx.getInMsg().getDeviceId()); | ||
235 | - ChainProcessingContext nextTask = ctx.getNext(); | ||
236 | - nextTask.getCurrentActor().tell(new RuleProcessingMsg(nextTask), context.self()); | ||
237 | - } | ||
238 | - } | ||
239 | - | ||
240 | - @Override | ||
241 | - public void onCreated(ActorContext context) { | ||
242 | - logger.info("[{}] Going to process onCreated rule.", entityId); | ||
243 | - } | ||
244 | - | ||
245 | - @Override | ||
246 | - public void onUpdate(ActorContext context) throws RuleException { | ||
247 | - RuleMetaData oldRuleMd = ruleMd; | ||
248 | - ruleMd = systemContext.getRuleService().findRuleById(entityId); | ||
249 | - logger.info("[{}] Rule configuration was updated from {} to {}.", entityId, oldRuleMd, ruleMd); | ||
250 | - try { | ||
251 | - fetchPluginInfo(); | ||
252 | - if (filters == null || !Objects.equals(oldRuleMd.getFilters(), ruleMd.getFilters())) { | ||
253 | - logger.info("[{}] Rule filters require restart due to json change from {} to {}.", | ||
254 | - entityId, mapper.writeValueAsString(oldRuleMd.getFilters()), mapper.writeValueAsString(ruleMd.getFilters())); | ||
255 | - stopFilters(); | ||
256 | - initFilters(); | ||
257 | - } | ||
258 | - if (processor == null || !Objects.equals(oldRuleMd.getProcessor(), ruleMd.getProcessor())) { | ||
259 | - logger.info("[{}] Rule processor require restart due to configuration change.", entityId); | ||
260 | - stopProcessor(); | ||
261 | - initProcessor(); | ||
262 | - } | ||
263 | - if (action == null || !Objects.equals(oldRuleMd.getAction(), ruleMd.getAction())) { | ||
264 | - logger.info("[{}] Rule action require restart due to configuration change.", entityId); | ||
265 | - stopAction(); | ||
266 | - initAction(); | ||
267 | - } | ||
268 | - } catch (RuntimeException e) { | ||
269 | - throw new RuleInitializationException("Unknown runtime exception!", e); | ||
270 | - } catch (InstantiationException e) { | ||
271 | - throw new RuleInitializationException("No default constructor for rule implementation!", e); | ||
272 | - } catch (IllegalAccessException e) { | ||
273 | - throw new RuleInitializationException("Illegal Access Exception during rule initialization!", e); | ||
274 | - } catch (ClassNotFoundException e) { | ||
275 | - throw new RuleInitializationException("Rule Class not found!", e); | ||
276 | - } catch (JsonProcessingException e) { | ||
277 | - throw new RuleInitializationException("Rule configuration is invalid!", e); | ||
278 | - } catch (Exception e) { | ||
279 | - throw new RuleInitializationException(e.getMessage(), e); | ||
280 | - } | ||
281 | - } | ||
282 | - | ||
283 | - @Override | ||
284 | - public void onActivate(ActorContext context) throws Exception { | ||
285 | - logger.info("[{}] Going to process onActivate rule.", entityId); | ||
286 | - this.state = ComponentLifecycleState.ACTIVE; | ||
287 | - if (filters != null) { | ||
288 | - filters.forEach(RuleLifecycleComponent::resume); | ||
289 | - if (processor != null) { | ||
290 | - processor.resume(); | ||
291 | - } else { | ||
292 | - initProcessor(); | ||
293 | - } | ||
294 | - if (action != null) { | ||
295 | - action.resume(); | ||
296 | - } | ||
297 | - logger.info("[{}] Rule resumed.", entityId); | ||
298 | - } else { | ||
299 | - start(); | ||
300 | - } | ||
301 | - } | ||
302 | - | ||
303 | - @Override | ||
304 | - public void onSuspend(ActorContext context) { | ||
305 | - logger.info("[{}] Going to process onSuspend rule.", entityId); | ||
306 | - this.state = ComponentLifecycleState.SUSPENDED; | ||
307 | - if (filters != null) { | ||
308 | - filters.forEach(f -> f.suspend()); | ||
309 | - } | ||
310 | - if (processor != null) { | ||
311 | - processor.suspend(); | ||
312 | - } | ||
313 | - if (action != null) { | ||
314 | - action.suspend(); | ||
315 | - } | ||
316 | - } | ||
317 | - | ||
318 | - @Override | ||
319 | - public void onStop(ActorContext context) { | ||
320 | - logger.info("[{}] Going to process onStop rule.", entityId); | ||
321 | - onStop(); | ||
322 | - scheduleMsgWithDelay(context, new RuleTerminationMsg(entityId), systemContext.getRuleActorTerminationDelay()); | ||
323 | - } | ||
324 | - | ||
325 | - private void onStop() { | ||
326 | - this.state = ComponentLifecycleState.SUSPENDED; | ||
327 | - stopFilters(); | ||
328 | - stopProcessor(); | ||
329 | - stopAction(); | ||
330 | - } | ||
331 | - | ||
332 | - @Override | ||
333 | - public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | ||
334 | - //Do nothing | ||
335 | - } | ||
336 | - | ||
337 | - private void stopAction() { | ||
338 | - if (action != null) { | ||
339 | - action.stop(); | ||
340 | - } | ||
341 | - } | ||
342 | - | ||
343 | - private void stopProcessor() { | ||
344 | - if (processor != null) { | ||
345 | - processor.stop(); | ||
346 | - } | ||
347 | - } | ||
348 | - | ||
349 | - private void stopFilters() { | ||
350 | - if (filters != null) { | ||
351 | - filters.forEach(f -> f.stop()); | ||
352 | - } | ||
353 | - } | ||
354 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMetaData.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rule; | ||
17 | - | ||
18 | -import java.util.Comparator; | ||
19 | - | ||
20 | -import org.thingsboard.server.common.data.id.RuleId; | ||
21 | - | ||
22 | -import akka.actor.ActorRef; | ||
23 | - | ||
24 | -public class RuleActorMetaData { | ||
25 | - | ||
26 | - private final RuleId ruleId; | ||
27 | - private final boolean systemRule; | ||
28 | - private final int weight; | ||
29 | - private final ActorRef actorRef; | ||
30 | - | ||
31 | - public static final Comparator<RuleActorMetaData> RULE_ACTOR_MD_COMPARATOR = new Comparator<RuleActorMetaData>() { | ||
32 | - | ||
33 | - @Override | ||
34 | - public int compare(RuleActorMetaData r1, RuleActorMetaData r2) { | ||
35 | - if (r1.isSystemRule() && !r2.isSystemRule()) { | ||
36 | - return 1; | ||
37 | - } else if (!r1.isSystemRule() && r2.isSystemRule()) { | ||
38 | - return -1; | ||
39 | - } else { | ||
40 | - return Integer.compare(r2.getWeight(), r1.getWeight()); | ||
41 | - } | ||
42 | - } | ||
43 | - }; | ||
44 | - | ||
45 | - public static RuleActorMetaData systemRule(RuleId ruleId, int weight, ActorRef actorRef) { | ||
46 | - return new RuleActorMetaData(ruleId, true, weight, actorRef); | ||
47 | - } | ||
48 | - | ||
49 | - public static RuleActorMetaData tenantRule(RuleId ruleId, int weight, ActorRef actorRef) { | ||
50 | - return new RuleActorMetaData(ruleId, false, weight, actorRef); | ||
51 | - } | ||
52 | - | ||
53 | - private RuleActorMetaData(RuleId ruleId, boolean systemRule, int weight, ActorRef actorRef) { | ||
54 | - super(); | ||
55 | - this.ruleId = ruleId; | ||
56 | - this.systemRule = systemRule; | ||
57 | - this.weight = weight; | ||
58 | - this.actorRef = actorRef; | ||
59 | - } | ||
60 | - | ||
61 | - public RuleId getRuleId() { | ||
62 | - return ruleId; | ||
63 | - } | ||
64 | - | ||
65 | - public boolean isSystemRule() { | ||
66 | - return systemRule; | ||
67 | - } | ||
68 | - | ||
69 | - public int getWeight() { | ||
70 | - return weight; | ||
71 | - } | ||
72 | - | ||
73 | - public ActorRef getActorRef() { | ||
74 | - return actorRef; | ||
75 | - } | ||
76 | - | ||
77 | - @Override | ||
78 | - public int hashCode() { | ||
79 | - final int prime = 31; | ||
80 | - int result = 1; | ||
81 | - result = prime * result + ((ruleId == null) ? 0 : ruleId.hashCode()); | ||
82 | - return result; | ||
83 | - } | ||
84 | - | ||
85 | - @Override | ||
86 | - public boolean equals(Object obj) { | ||
87 | - if (this == obj) | ||
88 | - return true; | ||
89 | - if (obj == null) | ||
90 | - return false; | ||
91 | - if (getClass() != obj.getClass()) | ||
92 | - return false; | ||
93 | - RuleActorMetaData other = (RuleActorMetaData) obj; | ||
94 | - if (ruleId == null) { | ||
95 | - if (other.ruleId != null) | ||
96 | - return false; | ||
97 | - } else if (!ruleId.equals(other.ruleId)) | ||
98 | - return false; | ||
99 | - return true; | ||
100 | - } | ||
101 | - | ||
102 | - @Override | ||
103 | - public String toString() { | ||
104 | - return "RuleActorMetaData [ruleId=" + ruleId + ", systemRule=" + systemRule + ", weight=" + weight + ", actorRef=" + actorRef + "]"; | ||
105 | - } | ||
106 | - | ||
107 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingContext.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.actors.rule; | ||
17 | - | ||
18 | -import com.google.common.util.concurrent.ListenableFuture; | ||
19 | -import org.thingsboard.server.actors.ActorSystemContext; | ||
20 | -import org.thingsboard.server.common.data.Event; | ||
21 | -import org.thingsboard.server.common.data.alarm.Alarm; | ||
22 | -import org.thingsboard.server.common.data.alarm.AlarmId; | ||
23 | -import org.thingsboard.server.common.data.id.*; | ||
24 | -import org.thingsboard.server.dao.alarm.AlarmService; | ||
25 | -import org.thingsboard.server.dao.event.EventService; | ||
26 | -import org.thingsboard.server.dao.timeseries.TimeseriesService; | ||
27 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | ||
28 | -import org.thingsboard.server.extensions.api.device.DeviceMetaData; | ||
29 | -import org.thingsboard.server.extensions.api.rules.RuleContext; | ||
30 | - | ||
31 | -import java.util.Optional; | ||
32 | -import java.util.concurrent.ExecutionException; | ||
33 | - | ||
34 | -public class RuleProcessingContext implements RuleContext { | ||
35 | - | ||
36 | - private final TimeseriesService tsService; | ||
37 | - private final EventService eventService; | ||
38 | - private final AlarmService alarmService; | ||
39 | - private final RuleId ruleId; | ||
40 | - private TenantId tenantId; | ||
41 | - private CustomerId customerId; | ||
42 | - private DeviceId deviceId; | ||
43 | - private DeviceMetaData deviceMetaData; | ||
44 | - | ||
45 | - RuleProcessingContext(ActorSystemContext systemContext, RuleId ruleId) { | ||
46 | - this.tsService = systemContext.getTsService(); | ||
47 | - this.eventService = systemContext.getEventService(); | ||
48 | - this.alarmService = systemContext.getAlarmService(); | ||
49 | - this.ruleId = ruleId; | ||
50 | - } | ||
51 | - | ||
52 | - void update(ToDeviceActorMsg toDeviceActorMsg, DeviceMetaData deviceMetaData) { | ||
53 | - this.tenantId = toDeviceActorMsg.getTenantId(); | ||
54 | - this.customerId = toDeviceActorMsg.getCustomerId(); | ||
55 | - this.deviceId = toDeviceActorMsg.getDeviceId(); | ||
56 | - this.deviceMetaData = deviceMetaData; | ||
57 | - } | ||
58 | - | ||
59 | - @Override | ||
60 | - public RuleId getRuleId() { | ||
61 | - return ruleId; | ||
62 | - } | ||
63 | - | ||
64 | - @Override | ||
65 | - public DeviceMetaData getDeviceMetaData() { | ||
66 | - return deviceMetaData; | ||
67 | - } | ||
68 | - | ||
69 | - @Override | ||
70 | - public Event save(Event event) { | ||
71 | - checkEvent(event); | ||
72 | - return eventService.save(event); | ||
73 | - } | ||
74 | - | ||
75 | - @Override | ||
76 | - public Optional<Event> saveIfNotExists(Event event) { | ||
77 | - checkEvent(event); | ||
78 | - return eventService.saveIfNotExists(event); | ||
79 | - } | ||
80 | - | ||
81 | - @Override | ||
82 | - public Optional<Event> findEvent(String eventType, String eventUid) { | ||
83 | - return eventService.findEvent(tenantId, deviceId, eventType, eventUid); | ||
84 | - } | ||
85 | - | ||
86 | - @Override | ||
87 | - public Alarm createOrUpdateAlarm(Alarm alarm) { | ||
88 | - alarm.setTenantId(tenantId); | ||
89 | - return alarmService.createOrUpdateAlarm(alarm); | ||
90 | - } | ||
91 | - | ||
92 | - public Optional<Alarm> findLatestAlarm(EntityId originator, String alarmType) { | ||
93 | - try { | ||
94 | - return Optional.ofNullable(alarmService.findLatestByOriginatorAndType(tenantId, originator, alarmType).get()); | ||
95 | - } catch (InterruptedException | ExecutionException e) { | ||
96 | - throw new RuntimeException("Failed to lookup alarm!", e); | ||
97 | - } | ||
98 | - } | ||
99 | - | ||
100 | - @Override | ||
101 | - public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long clearTs) { | ||
102 | - return alarmService.clearAlarm(alarmId, clearTs); | ||
103 | - } | ||
104 | - | ||
105 | - private void checkEvent(Event event) { | ||
106 | - if (event.getTenantId() == null) { | ||
107 | - event.setTenantId(tenantId); | ||
108 | - } else if (!tenantId.equals(event.getTenantId())) { | ||
109 | - throw new IllegalArgumentException("Invalid Tenant id!"); | ||
110 | - } | ||
111 | - if (event.getEntityId() == null) { | ||
112 | - event.setEntityId(deviceId); | ||
113 | - } | ||
114 | - } | ||
115 | -} |
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.actors.ruleChain; | ||
17 | + | ||
18 | +import akka.actor.ActorRef; | ||
19 | +import com.datastax.driver.core.utils.UUIDs; | ||
20 | +import org.thingsboard.rule.engine.api.ListeningExecutor; | ||
21 | +import org.thingsboard.rule.engine.api.MailService; | ||
22 | +import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcRequest; | ||
23 | +import org.thingsboard.rule.engine.api.RuleEngineDeviceRpcResponse; | ||
24 | +import org.thingsboard.rule.engine.api.RuleEngineRpcService; | ||
25 | +import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; | ||
26 | +import org.thingsboard.rule.engine.api.ScriptEngine; | ||
27 | +import org.thingsboard.rule.engine.api.TbContext; | ||
28 | +import org.thingsboard.rule.engine.api.TbRelationTypes; | ||
29 | +import org.thingsboard.server.actors.ActorSystemContext; | ||
30 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
31 | +import org.thingsboard.server.common.data.id.EntityId; | ||
32 | +import org.thingsboard.server.common.data.id.RuleNodeId; | ||
33 | +import org.thingsboard.server.common.data.id.TenantId; | ||
34 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | ||
35 | +import org.thingsboard.server.common.data.rule.RuleNode; | ||
36 | +import org.thingsboard.server.common.msg.TbMsg; | ||
37 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
38 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | ||
39 | +import org.thingsboard.server.dao.alarm.AlarmService; | ||
40 | +import org.thingsboard.server.dao.asset.AssetService; | ||
41 | +import org.thingsboard.server.dao.attributes.AttributesService; | ||
42 | +import org.thingsboard.server.dao.customer.CustomerService; | ||
43 | +import org.thingsboard.server.dao.device.DeviceService; | ||
44 | +import org.thingsboard.server.dao.relation.RelationService; | ||
45 | +import org.thingsboard.server.dao.rule.RuleChainService; | ||
46 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | ||
47 | +import org.thingsboard.server.dao.user.UserService; | ||
48 | +import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; | ||
49 | +import scala.concurrent.duration.Duration; | ||
50 | + | ||
51 | +import java.util.Collections; | ||
52 | +import java.util.Set; | ||
53 | +import java.util.concurrent.TimeUnit; | ||
54 | +import java.util.function.Consumer; | ||
55 | + | ||
56 | +/** | ||
57 | + * Created by ashvayka on 19.03.18. | ||
58 | + */ | ||
59 | +class DefaultTbContext implements TbContext { | ||
60 | + | ||
61 | + private final ActorSystemContext mainCtx; | ||
62 | + private final RuleNodeCtx nodeCtx; | ||
63 | + | ||
64 | + public DefaultTbContext(ActorSystemContext mainCtx, RuleNodeCtx nodeCtx) { | ||
65 | + this.mainCtx = mainCtx; | ||
66 | + this.nodeCtx = nodeCtx; | ||
67 | + } | ||
68 | + | ||
69 | + @Override | ||
70 | + public void tellNext(TbMsg msg, String relationType) { | ||
71 | + tellNext(msg, Collections.singleton(relationType), null); | ||
72 | + } | ||
73 | + | ||
74 | + @Override | ||
75 | + public void tellNext(TbMsg msg, Set<String> relationTypes) { | ||
76 | + tellNext(msg, relationTypes, null); | ||
77 | + } | ||
78 | + | ||
79 | + @Override | ||
80 | + public void tellNext(TbMsg msg, String relationType, Throwable th) { | ||
81 | + tellNext(msg, Collections.singleton(relationType), th); | ||
82 | + } | ||
83 | + | ||
84 | + private void tellNext(TbMsg msg, Set<String> relationTypes, Throwable th) { | ||
85 | + if (nodeCtx.getSelf().isDebugMode()) { | ||
86 | + relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th)); | ||
87 | + } | ||
88 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg), nodeCtx.getSelfActor()); | ||
89 | + } | ||
90 | + | ||
91 | + @Override | ||
92 | + public void tellSelf(TbMsg msg, long delayMs) { | ||
93 | + //TODO: add persistence layer | ||
94 | + scheduleMsgWithDelay(new RuleNodeToSelfMsg(msg), delayMs, nodeCtx.getSelfActor()); | ||
95 | + } | ||
96 | + | ||
97 | + private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) { | ||
98 | + mainCtx.getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, mainCtx.getActorSystem().dispatcher(), nodeCtx.getSelfActor()); | ||
99 | + } | ||
100 | + | ||
101 | + @Override | ||
102 | + public void tellFailure(TbMsg msg, Throwable th) { | ||
103 | + if (nodeCtx.getSelf().isDebugMode()) { | ||
104 | + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); | ||
105 | + } | ||
106 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), msg), nodeCtx.getSelfActor()); | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
110 | + public void updateSelf(RuleNode self) { | ||
111 | + nodeCtx.setSelf(self); | ||
112 | + } | ||
113 | + | ||
114 | + @Override | ||
115 | + public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { | ||
116 | + return new TbMsg(UUIDs.timeBased(), type, originator, metaData.copy(), data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), mainCtx.getQueuePartitionId()); | ||
117 | + } | ||
118 | + | ||
119 | + @Override | ||
120 | + public TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { | ||
121 | + return new TbMsg(origMsg.getId(), type, originator, metaData.copy(), data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), mainCtx.getQueuePartitionId()); | ||
122 | + } | ||
123 | + | ||
124 | + @Override | ||
125 | + public RuleNodeId getSelfId() { | ||
126 | + return nodeCtx.getSelf().getId(); | ||
127 | + } | ||
128 | + | ||
129 | + @Override | ||
130 | + public TenantId getTenantId() { | ||
131 | + return nodeCtx.getTenantId(); | ||
132 | + } | ||
133 | + | ||
134 | + @Override | ||
135 | + public ListeningExecutor getJsExecutor() { | ||
136 | + return mainCtx.getJsExecutor(); | ||
137 | + } | ||
138 | + | ||
139 | + @Override | ||
140 | + public ListeningExecutor getMailExecutor() { | ||
141 | + return mainCtx.getMailExecutor(); | ||
142 | + } | ||
143 | + | ||
144 | + @Override | ||
145 | + public ListeningExecutor getDbCallbackExecutor() { | ||
146 | + return mainCtx.getDbCallbackExecutor(); | ||
147 | + } | ||
148 | + | ||
149 | + @Override | ||
150 | + public ListeningExecutor getExternalCallExecutor() { | ||
151 | + return mainCtx.getExternalCallExecutorService(); | ||
152 | + } | ||
153 | + | ||
154 | + @Override | ||
155 | + public ScriptEngine createJsScriptEngine(String script, String... argNames) { | ||
156 | + return new RuleNodeJsScriptEngine(mainCtx.getJsSandbox(), script, argNames); | ||
157 | + } | ||
158 | + | ||
159 | + @Override | ||
160 | + public AttributesService getAttributesService() { | ||
161 | + return mainCtx.getAttributesService(); | ||
162 | + } | ||
163 | + | ||
164 | + @Override | ||
165 | + public CustomerService getCustomerService() { | ||
166 | + return mainCtx.getCustomerService(); | ||
167 | + } | ||
168 | + | ||
169 | + @Override | ||
170 | + public UserService getUserService() { | ||
171 | + return mainCtx.getUserService(); | ||
172 | + } | ||
173 | + | ||
174 | + @Override | ||
175 | + public AssetService getAssetService() { | ||
176 | + return mainCtx.getAssetService(); | ||
177 | + } | ||
178 | + | ||
179 | + @Override | ||
180 | + public DeviceService getDeviceService() { | ||
181 | + return mainCtx.getDeviceService(); | ||
182 | + } | ||
183 | + | ||
184 | + @Override | ||
185 | + public AlarmService getAlarmService() { | ||
186 | + return mainCtx.getAlarmService(); | ||
187 | + } | ||
188 | + | ||
189 | + @Override | ||
190 | + public RuleChainService getRuleChainService() { | ||
191 | + return mainCtx.getRuleChainService(); | ||
192 | + } | ||
193 | + | ||
194 | + @Override | ||
195 | + public TimeseriesService getTimeseriesService() { | ||
196 | + return mainCtx.getTsService(); | ||
197 | + } | ||
198 | + | ||
199 | + @Override | ||
200 | + public RuleEngineTelemetryService getTelemetryService() { | ||
201 | + return mainCtx.getTsSubService(); | ||
202 | + } | ||
203 | + | ||
204 | + @Override | ||
205 | + public RelationService getRelationService() { | ||
206 | + return mainCtx.getRelationService(); | ||
207 | + } | ||
208 | + | ||
209 | + @Override | ||
210 | + public MailService getMailService() { | ||
211 | + if (mainCtx.isAllowSystemMailService()) { | ||
212 | + return mainCtx.getMailService(); | ||
213 | + } else { | ||
214 | + throw new RuntimeException("Access to System Mail Service is forbidden!"); | ||
215 | + } | ||
216 | + } | ||
217 | + | ||
218 | + @Override | ||
219 | + public RuleEngineRpcService getRpcService() { | ||
220 | + return new RuleEngineRpcService() { | ||
221 | + @Override | ||
222 | + public void sendRpcReply(DeviceId deviceId, int requestId, String body) { | ||
223 | + mainCtx.getDeviceRpcService().sendRpcReplyToDevice(nodeCtx.getTenantId(), deviceId, requestId, body); | ||
224 | + } | ||
225 | + | ||
226 | + @Override | ||
227 | + public void sendRpcRequest(RuleEngineDeviceRpcRequest src, Consumer<RuleEngineDeviceRpcResponse> consumer) { | ||
228 | + ToDeviceRpcRequest request = new ToDeviceRpcRequest(UUIDs.timeBased(), nodeCtx.getTenantId(), src.getDeviceId(), | ||
229 | + src.isOneway(), System.currentTimeMillis() + src.getTimeout(), new ToDeviceRpcRequestBody(src.getMethod(), src.getBody())); | ||
230 | + mainCtx.getDeviceRpcService().processRpcRequestToDevice(request, response -> { | ||
231 | + consumer.accept(RuleEngineDeviceRpcResponse.builder() | ||
232 | + .deviceId(src.getDeviceId()) | ||
233 | + .requestId(src.getRequestId()) | ||
234 | + .error(response.getError()) | ||
235 | + .response(response.getResponse()) | ||
236 | + .build()); | ||
237 | + }); | ||
238 | + } | ||
239 | + }; | ||
240 | + } | ||
241 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2018 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.actors.ruleChain; | ||
17 | + | ||
18 | +import akka.actor.OneForOneStrategy; | ||
19 | +import akka.actor.SupervisorStrategy; | ||
20 | +import org.thingsboard.server.actors.ActorSystemContext; | ||
21 | +import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; | ||
22 | +import org.thingsboard.server.actors.service.ComponentActor; | ||
23 | +import org.thingsboard.server.actors.service.ContextBasedCreator; | ||
24 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
25 | +import org.thingsboard.server.common.data.id.TenantId; | ||
26 | +import org.thingsboard.server.common.msg.TbActorMsg; | ||
27 | +import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | ||
28 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | ||
29 | +import scala.concurrent.duration.Duration; | ||
30 | + | ||
31 | +public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> { | ||
32 | + | ||
33 | + private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) { | ||
34 | + super(systemContext, tenantId, ruleChainId); | ||
35 | + setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext, | ||
36 | + logger, context().parent(), context().self())); | ||
37 | + } | ||
38 | + | ||
39 | + @Override | ||
40 | + protected boolean process(TbActorMsg msg) { | ||
41 | + switch (msg.getMsgType()) { | ||
42 | + case COMPONENT_LIFE_CYCLE_MSG: | ||
43 | + onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | ||
44 | + break; | ||
45 | + case SERVICE_TO_RULE_ENGINE_MSG: | ||
46 | + processor.onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | ||
47 | + break; | ||
48 | + case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: | ||
49 | + processor.onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); | ||
50 | + break; | ||
51 | + case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG: | ||
52 | + processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg); | ||
53 | + break; | ||
54 | + case RULE_CHAIN_TO_RULE_CHAIN_MSG: | ||
55 | + processor.onRuleChainToRuleChainMsg((RuleChainToRuleChainMsg) msg); | ||
56 | + break; | ||
57 | + case CLUSTER_EVENT_MSG: | ||
58 | + break; | ||
59 | + default: | ||
60 | + return false; | ||
61 | + } | ||
62 | + return true; | ||
63 | + } | ||
64 | + | ||
65 | + public static class ActorCreator extends ContextBasedCreator<RuleChainActor> { | ||
66 | + private static final long serialVersionUID = 1L; | ||
67 | + | ||
68 | + private final TenantId tenantId; | ||
69 | + private final RuleChainId ruleChainId; | ||
70 | + | ||
71 | + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId pluginId) { | ||
72 | + super(context); | ||
73 | + this.tenantId = tenantId; | ||
74 | + this.ruleChainId = pluginId; | ||
75 | + } | ||
76 | + | ||
77 | + @Override | ||
78 | + public RuleChainActor create() throws Exception { | ||
79 | + return new RuleChainActor(context, tenantId, ruleChainId); | ||
80 | + } | ||
81 | + } | ||
82 | + | ||
83 | + @Override | ||
84 | + protected long getErrorPersistFrequency() { | ||
85 | + return systemContext.getRuleChainErrorPersistFrequency(); | ||
86 | + } | ||
87 | + | ||
88 | + @Override | ||
89 | + public SupervisorStrategy supervisorStrategy() { | ||
90 | + return strategy; | ||
91 | + } | ||
92 | + | ||
93 | + private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> { | ||
94 | + logAndPersist("Unknown Failure", ActorSystemContext.toException(t)); | ||
95 | + return SupervisorStrategy.resume(); | ||
96 | + }); | ||
97 | +} |