Commit e0f978992e67b1bf6738c3688c013070f41b67f1
Committed by
GitHub
Merge pull request #3811 from volodymyr-babak/develop/3.3-edge
Edge functionality
Showing
44 changed files
with
3444 additions
and
76 deletions
Too many changes to show.
To preserve performance only 44 of 371 files are displayed.
@@ -102,6 +102,10 @@ | @@ -102,6 +102,10 @@ | ||
102 | <artifactId>stats</artifactId> | 102 | <artifactId>stats</artifactId> |
103 | </dependency> | 103 | </dependency> |
104 | <dependency> | 104 | <dependency> |
105 | + <groupId>org.thingsboard.common</groupId> | ||
106 | + <artifactId>edge-api</artifactId> | ||
107 | + </dependency> | ||
108 | + <dependency> | ||
105 | <groupId>org.thingsboard</groupId> | 109 | <groupId>org.thingsboard</groupId> |
106 | <artifactId>dao</artifactId> | 110 | <artifactId>dao</artifactId> |
107 | <type>test-jar</type> | 111 | <type>test-jar</type> |
application/src/main/data/json/demo/edge_management/rule_chains/edge_root_rule_chain.json
0 → 100644
1 | +{ | ||
2 | + "ruleChain": { | ||
3 | + "additionalInfo": null, | ||
4 | + "name": "Edge Root Rule Chain", | ||
5 | + "type": "EDGE", | ||
6 | + "firstRuleNodeId": null, | ||
7 | + "root": true, | ||
8 | + "debugMode": false, | ||
9 | + "configuration": null | ||
10 | + }, | ||
11 | + "metadata": { | ||
12 | + "firstNodeIndex": 0, | ||
13 | + "nodes": [ | ||
14 | + { | ||
15 | + "additionalInfo": { | ||
16 | + "description": "Process incoming messages from devices with the alarm rules defined in the device profile. Dispatch all incoming messages with \"Success\" relation type.", | ||
17 | + "layoutX": 203, | ||
18 | + "layoutY": 259 | ||
19 | + }, | ||
20 | + "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", | ||
21 | + "name": "Device Profile Node", | ||
22 | + "debugMode": false, | ||
23 | + "configuration": { | ||
24 | + "persistAlarmRulesState": false, | ||
25 | + "fetchAlarmRulesStateOnStart": false | ||
26 | + } | ||
27 | + }, | ||
28 | + { | ||
29 | + "additionalInfo": { | ||
30 | + "layoutX": 823, | ||
31 | + "layoutY": 157 | ||
32 | + }, | ||
33 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", | ||
34 | + "name": "Save Timeseries", | ||
35 | + "debugMode": false, | ||
36 | + "configuration": { | ||
37 | + "defaultTTL": 0 | ||
38 | + } | ||
39 | + }, | ||
40 | + { | ||
41 | + "additionalInfo": { | ||
42 | + "layoutX": 824, | ||
43 | + "layoutY": 52 | ||
44 | + }, | ||
45 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", | ||
46 | + "name": "Save Client Attributes", | ||
47 | + "debugMode": false, | ||
48 | + "configuration": { | ||
49 | + "scope": "CLIENT_SCOPE" | ||
50 | + } | ||
51 | + }, | ||
52 | + { | ||
53 | + "additionalInfo": { | ||
54 | + "layoutX": 347, | ||
55 | + "layoutY": 149 | ||
56 | + }, | ||
57 | + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", | ||
58 | + "name": "Message Type Switch", | ||
59 | + "debugMode": false, | ||
60 | + "configuration": { | ||
61 | + "version": 0 | ||
62 | + } | ||
63 | + }, | ||
64 | + { | ||
65 | + "additionalInfo": { | ||
66 | + "layoutX": 825, | ||
67 | + "layoutY": 266 | ||
68 | + }, | ||
69 | + "type": "org.thingsboard.rule.engine.action.TbLogNode", | ||
70 | + "name": "Log RPC from Device", | ||
71 | + "debugMode": false, | ||
72 | + "configuration": { | ||
73 | + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" | ||
74 | + } | ||
75 | + }, | ||
76 | + { | ||
77 | + "additionalInfo": { | ||
78 | + "layoutX": 824, | ||
79 | + "layoutY": 378 | ||
80 | + }, | ||
81 | + "type": "org.thingsboard.rule.engine.action.TbLogNode", | ||
82 | + "name": "Log Other", | ||
83 | + "debugMode": false, | ||
84 | + "configuration": { | ||
85 | + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" | ||
86 | + } | ||
87 | + }, | ||
88 | + { | ||
89 | + "additionalInfo": { | ||
90 | + "layoutX": 824, | ||
91 | + "layoutY": 466 | ||
92 | + }, | ||
93 | + "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", | ||
94 | + "name": "RPC Call Request", | ||
95 | + "debugMode": false, | ||
96 | + "configuration": { | ||
97 | + "timeoutInSeconds": 60 | ||
98 | + } | ||
99 | + }, | ||
100 | + { | ||
101 | + "additionalInfo": { | ||
102 | + "layoutX": 1134, | ||
103 | + "layoutY": 132 | ||
104 | + }, | ||
105 | + "type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", | ||
106 | + "name": "Push to cloud", | ||
107 | + "debugMode": false, | ||
108 | + "configuration": { | ||
109 | + "version": 0 | ||
110 | + } | ||
111 | + } | ||
112 | + ], | ||
113 | + "connections": [ | ||
114 | + { | ||
115 | + "fromIndex": 0, | ||
116 | + "toIndex": 3, | ||
117 | + "type": "Success" | ||
118 | + }, | ||
119 | + { | ||
120 | + "fromIndex": 1, | ||
121 | + "toIndex": 7, | ||
122 | + "type": "Success" | ||
123 | + }, | ||
124 | + { | ||
125 | + "fromIndex": 2, | ||
126 | + "toIndex": 7, | ||
127 | + "type": "Success" | ||
128 | + }, | ||
129 | + { | ||
130 | + "fromIndex": 3, | ||
131 | + "toIndex": 6, | ||
132 | + "type": "RPC Request to Device" | ||
133 | + }, | ||
134 | + { | ||
135 | + "fromIndex": 3, | ||
136 | + "toIndex": 5, | ||
137 | + "type": "Other" | ||
138 | + }, | ||
139 | + { | ||
140 | + "fromIndex": 3, | ||
141 | + "toIndex": 2, | ||
142 | + "type": "Post attributes" | ||
143 | + }, | ||
144 | + { | ||
145 | + "fromIndex": 3, | ||
146 | + "toIndex": 1, | ||
147 | + "type": "Post telemetry" | ||
148 | + }, | ||
149 | + { | ||
150 | + "fromIndex": 3, | ||
151 | + "toIndex": 4, | ||
152 | + "type": "RPC Request from Device" | ||
153 | + }, | ||
154 | + { | ||
155 | + "fromIndex": 4, | ||
156 | + "toIndex": 7, | ||
157 | + "type": "Success" | ||
158 | + } | ||
159 | + ], | ||
160 | + "ruleChainConnections": null | ||
161 | + } | ||
162 | +} |
1 | +{ | ||
2 | + "widgetsBundle": { | ||
3 | + "alias": "edge_widgets", | ||
4 | + "title": "Edge widgets", | ||
5 | + "image": null | ||
6 | + }, | ||
7 | + "widgetTypes": [ | ||
8 | + { | ||
9 | + "alias": "edges_overview", | ||
10 | + "name": "Edge Quick Overview", | ||
11 | + "descriptor": { | ||
12 | + "type": "latest", | ||
13 | + "sizeX": 7.5, | ||
14 | + "sizeY": 5, | ||
15 | + "resources": [], | ||
16 | + "templateHtml": "<tb-edges-overview-widget \n [ctx]=\"ctx\">\n</tb-edges-overview-widget>", | ||
17 | + "templateCss": "", | ||
18 | + "controllerScript": "self.onInit = function() {\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n dataKeysOptional: true\n };\n}\n\nself.onDestroy = function() {\n};\n", | ||
19 | + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"EdgeOverviewSettings\",\n \"properties\": {\n \"enableDefaultTitle\": {\n \"title\": \"Display default title\",\n \"type\": \"boolean\",\n \"default\": true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"enableDefaultTitle\"\n ]\n}", | ||
20 | + "dataKeySettingsSchema": "{}\n", | ||
21 | + "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"showTitleIcon\":true,\"titleIcon\":\"router\",\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{},\"title\":\"Edge Quick Overview\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\"}]}],\"widgetStyle\":{},\"actions\":{}}" | ||
22 | + } | ||
23 | + } | ||
24 | + ] | ||
25 | +} |
application/src/main/data/json/tenant/edge_management/rule_chains/edge_root_rule_chain.json
0 → 100644
1 | +{ | ||
2 | + "ruleChain": { | ||
3 | + "additionalInfo": null, | ||
4 | + "name": "Edge Root Rule Chain", | ||
5 | + "type": "EDGE", | ||
6 | + "firstRuleNodeId": null, | ||
7 | + "root": true, | ||
8 | + "debugMode": false, | ||
9 | + "configuration": null | ||
10 | + }, | ||
11 | + "metadata": { | ||
12 | + "firstNodeIndex": 0, | ||
13 | + "nodes": [ | ||
14 | + { | ||
15 | + "additionalInfo": { | ||
16 | + "description": "Process incoming messages from devices with the alarm rules defined in the device profile. Dispatch all incoming messages with \"Success\" relation type.", | ||
17 | + "layoutX": 203, | ||
18 | + "layoutY": 259 | ||
19 | + }, | ||
20 | + "type": "org.thingsboard.rule.engine.profile.TbDeviceProfileNode", | ||
21 | + "name": "Device Profile Node", | ||
22 | + "debugMode": false, | ||
23 | + "configuration": { | ||
24 | + "persistAlarmRulesState": false, | ||
25 | + "fetchAlarmRulesStateOnStart": false | ||
26 | + } | ||
27 | + }, | ||
28 | + { | ||
29 | + "additionalInfo": { | ||
30 | + "layoutX": 823, | ||
31 | + "layoutY": 157 | ||
32 | + }, | ||
33 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", | ||
34 | + "name": "Save Timeseries", | ||
35 | + "debugMode": false, | ||
36 | + "configuration": { | ||
37 | + "defaultTTL": 0 | ||
38 | + } | ||
39 | + }, | ||
40 | + { | ||
41 | + "additionalInfo": { | ||
42 | + "layoutX": 824, | ||
43 | + "layoutY": 52 | ||
44 | + }, | ||
45 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", | ||
46 | + "name": "Save Client Attributes", | ||
47 | + "debugMode": false, | ||
48 | + "configuration": { | ||
49 | + "scope": "CLIENT_SCOPE" | ||
50 | + } | ||
51 | + }, | ||
52 | + { | ||
53 | + "additionalInfo": { | ||
54 | + "layoutX": 347, | ||
55 | + "layoutY": 149 | ||
56 | + }, | ||
57 | + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode", | ||
58 | + "name": "Message Type Switch", | ||
59 | + "debugMode": false, | ||
60 | + "configuration": { | ||
61 | + "version": 0 | ||
62 | + } | ||
63 | + }, | ||
64 | + { | ||
65 | + "additionalInfo": { | ||
66 | + "layoutX": 825, | ||
67 | + "layoutY": 266 | ||
68 | + }, | ||
69 | + "type": "org.thingsboard.rule.engine.action.TbLogNode", | ||
70 | + "name": "Log RPC from Device", | ||
71 | + "debugMode": false, | ||
72 | + "configuration": { | ||
73 | + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" | ||
74 | + } | ||
75 | + }, | ||
76 | + { | ||
77 | + "additionalInfo": { | ||
78 | + "layoutX": 824, | ||
79 | + "layoutY": 378 | ||
80 | + }, | ||
81 | + "type": "org.thingsboard.rule.engine.action.TbLogNode", | ||
82 | + "name": "Log Other", | ||
83 | + "debugMode": false, | ||
84 | + "configuration": { | ||
85 | + "jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);" | ||
86 | + } | ||
87 | + }, | ||
88 | + { | ||
89 | + "additionalInfo": { | ||
90 | + "layoutX": 824, | ||
91 | + "layoutY": 466 | ||
92 | + }, | ||
93 | + "type": "org.thingsboard.rule.engine.rpc.TbSendRPCRequestNode", | ||
94 | + "name": "RPC Call Request", | ||
95 | + "debugMode": false, | ||
96 | + "configuration": { | ||
97 | + "timeoutInSeconds": 60 | ||
98 | + } | ||
99 | + }, | ||
100 | + { | ||
101 | + "additionalInfo": { | ||
102 | + "layoutX": 1134, | ||
103 | + "layoutY": 132 | ||
104 | + }, | ||
105 | + "type": "org.thingsboard.rule.engine.edge.TbMsgPushToCloudNode", | ||
106 | + "name": "Push to cloud", | ||
107 | + "debugMode": false, | ||
108 | + "configuration": { | ||
109 | + "version": 0 | ||
110 | + } | ||
111 | + } | ||
112 | + ], | ||
113 | + "connections": [ | ||
114 | + { | ||
115 | + "fromIndex": 0, | ||
116 | + "toIndex": 3, | ||
117 | + "type": "Success" | ||
118 | + }, | ||
119 | + { | ||
120 | + "fromIndex": 1, | ||
121 | + "toIndex": 7, | ||
122 | + "type": "Success" | ||
123 | + }, | ||
124 | + { | ||
125 | + "fromIndex": 2, | ||
126 | + "toIndex": 7, | ||
127 | + "type": "Success" | ||
128 | + }, | ||
129 | + { | ||
130 | + "fromIndex": 3, | ||
131 | + "toIndex": 6, | ||
132 | + "type": "RPC Request to Device" | ||
133 | + }, | ||
134 | + { | ||
135 | + "fromIndex": 3, | ||
136 | + "toIndex": 5, | ||
137 | + "type": "Other" | ||
138 | + }, | ||
139 | + { | ||
140 | + "fromIndex": 3, | ||
141 | + "toIndex": 2, | ||
142 | + "type": "Post attributes" | ||
143 | + }, | ||
144 | + { | ||
145 | + "fromIndex": 3, | ||
146 | + "toIndex": 1, | ||
147 | + "type": "Post telemetry" | ||
148 | + }, | ||
149 | + { | ||
150 | + "fromIndex": 3, | ||
151 | + "toIndex": 4, | ||
152 | + "type": "RPC Request from Device" | ||
153 | + }, | ||
154 | + { | ||
155 | + "fromIndex": 4, | ||
156 | + "toIndex": 7, | ||
157 | + "type": "Success" | ||
158 | + } | ||
159 | + ], | ||
160 | + "ruleChainConnections": null | ||
161 | + } | ||
162 | +} |
@@ -2,6 +2,7 @@ | @@ -2,6 +2,7 @@ | ||
2 | "ruleChain": { | 2 | "ruleChain": { |
3 | "additionalInfo": null, | 3 | "additionalInfo": null, |
4 | "name": "Root Rule Chain", | 4 | "name": "Root Rule Chain", |
5 | + "type": "CORE", | ||
5 | "firstRuleNodeId": null, | 6 | "firstRuleNodeId": null, |
6 | "root": true, | 7 | "root": true, |
7 | "debugMode": false, | 8 | "debugMode": false, |
1 | +-- | ||
2 | +-- Copyright © 2016-2021 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 edge ( | ||
18 | + id uuid NOT NULL CONSTRAINT edge_pkey PRIMARY KEY, | ||
19 | + created_time bigint NOT NULL, | ||
20 | + additional_info varchar, | ||
21 | + customer_id uuid, | ||
22 | + root_rule_chain_id uuid, | ||
23 | + type varchar(255), | ||
24 | + name varchar(255), | ||
25 | + label varchar(255), | ||
26 | + routing_key varchar(255), | ||
27 | + secret varchar(255), | ||
28 | + edge_license_key varchar(30), | ||
29 | + cloud_endpoint varchar(255), | ||
30 | + search_text varchar(255), | ||
31 | + tenant_id uuid, | ||
32 | + CONSTRAINT edge_name_unq_key UNIQUE (tenant_id, name), | ||
33 | + CONSTRAINT edge_routing_key_unq_key UNIQUE (routing_key) | ||
34 | +); | ||
35 | + | ||
36 | +CREATE TABLE IF NOT EXISTS edge_event ( | ||
37 | + id uuid NOT NULL CONSTRAINT edge_event_pkey PRIMARY KEY, | ||
38 | + created_time bigint NOT NULL, | ||
39 | + edge_id uuid, | ||
40 | + edge_event_type varchar(255), | ||
41 | + edge_event_uid varchar(255), | ||
42 | + entity_id uuid, | ||
43 | + edge_event_action varchar(255), | ||
44 | + body varchar(10000000), | ||
45 | + tenant_id uuid, | ||
46 | + ts bigint NOT NULL | ||
47 | +); |
1 | +-- | ||
2 | +-- Copyright © 2016-2021 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 OR REPLACE PROCEDURE cleanup_edge_events_by_ttl(IN ttl bigint, INOUT deleted bigint) | ||
18 | + LANGUAGE plpgsql AS | ||
19 | +$$ | ||
20 | +DECLARE | ||
21 | + ttl_ts bigint; | ||
22 | + ttl_deleted_count bigint DEFAULT 0; | ||
23 | +BEGIN | ||
24 | + IF ttl > 0 THEN | ||
25 | + ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint; | ||
26 | + EXECUTE format( | ||
27 | + 'WITH deleted AS (DELETE FROM edge_event WHERE ts < %L::bigint RETURNING *) SELECT count(*) FROM deleted', ttl_ts) into ttl_deleted_count; | ||
28 | + END IF; | ||
29 | + RAISE NOTICE 'Edge events removed by ttl: %', ttl_deleted_count; | ||
30 | + deleted := ttl_deleted_count; | ||
31 | +END | ||
32 | +$$; |
@@ -46,6 +46,7 @@ import org.thingsboard.server.common.msg.TbMsg; | @@ -46,6 +46,7 @@ import org.thingsboard.server.common.msg.TbMsg; | ||
46 | import org.thingsboard.server.common.msg.queue.ServiceType; | 46 | import org.thingsboard.server.common.msg.queue.ServiceType; |
47 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 47 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
48 | import org.thingsboard.server.common.msg.tools.TbRateLimits; | 48 | import org.thingsboard.server.common.msg.tools.TbRateLimits; |
49 | +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | ||
49 | import org.thingsboard.server.dao.asset.AssetService; | 50 | import org.thingsboard.server.dao.asset.AssetService; |
50 | import org.thingsboard.server.dao.attributes.AttributesService; | 51 | import org.thingsboard.server.dao.attributes.AttributesService; |
51 | import org.thingsboard.server.dao.audit.AuditLogService; | 52 | import org.thingsboard.server.dao.audit.AuditLogService; |
@@ -54,6 +55,8 @@ import org.thingsboard.server.dao.customer.CustomerService; | @@ -54,6 +55,8 @@ import org.thingsboard.server.dao.customer.CustomerService; | ||
54 | import org.thingsboard.server.dao.dashboard.DashboardService; | 55 | import org.thingsboard.server.dao.dashboard.DashboardService; |
55 | import org.thingsboard.server.dao.device.ClaimDevicesService; | 56 | import org.thingsboard.server.dao.device.ClaimDevicesService; |
56 | import org.thingsboard.server.dao.device.DeviceService; | 57 | import org.thingsboard.server.dao.device.DeviceService; |
58 | +import org.thingsboard.server.dao.edge.EdgeEventService; | ||
59 | +import org.thingsboard.server.dao.edge.EdgeService; | ||
57 | import org.thingsboard.server.dao.entityview.EntityViewService; | 60 | import org.thingsboard.server.dao.entityview.EntityViewService; |
58 | import org.thingsboard.server.dao.event.EventService; | 61 | import org.thingsboard.server.dao.event.EventService; |
59 | import org.thingsboard.server.dao.nosql.CassandraBufferedRateExecutor; | 62 | import org.thingsboard.server.dao.nosql.CassandraBufferedRateExecutor; |
@@ -69,7 +72,7 @@ import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | @@ -69,7 +72,7 @@ import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | ||
69 | import org.thingsboard.server.queue.usagestats.TbApiUsageClient; | 72 | import org.thingsboard.server.queue.usagestats.TbApiUsageClient; |
70 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 73 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
71 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 74 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
72 | -import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | 75 | +import org.thingsboard.server.service.edge.rpc.EdgeRpcService; |
73 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; | 76 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
74 | import org.thingsboard.server.service.executors.ExternalCallExecutorService; | 77 | import org.thingsboard.server.service.executors.ExternalCallExecutorService; |
75 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; | 78 | import org.thingsboard.server.service.executors.SharedEventLoopGroupService; |
@@ -296,6 +299,18 @@ public class ActorSystemContext { | @@ -296,6 +299,18 @@ public class ActorSystemContext { | ||
296 | @Getter | 299 | @Getter |
297 | private TbCoreDeviceRpcService tbCoreDeviceRpcService; | 300 | private TbCoreDeviceRpcService tbCoreDeviceRpcService; |
298 | 301 | ||
302 | + @Lazy | ||
303 | + @Autowired(required = false) | ||
304 | + @Getter private EdgeService edgeService; | ||
305 | + | ||
306 | + @Lazy | ||
307 | + @Autowired(required = false) | ||
308 | + @Getter private EdgeEventService edgeEventService; | ||
309 | + | ||
310 | + @Lazy | ||
311 | + @Autowired(required = false) | ||
312 | + @Getter private EdgeRpcService edgeRpcService; | ||
313 | + | ||
299 | @Value("${actors.session.max_concurrent_sessions_per_device:1}") | 314 | @Value("${actors.session.max_concurrent_sessions_per_device:1}") |
300 | @Getter | 315 | @Getter |
301 | private long maxConcurrentSessionsPerDevice; | 316 | private long maxConcurrentSessionsPerDevice; |
@@ -320,6 +335,9 @@ public class ActorSystemContext { | @@ -320,6 +335,9 @@ public class ActorSystemContext { | ||
320 | @Getter | 335 | @Getter |
321 | private long statisticsPersistFrequency; | 336 | private long statisticsPersistFrequency; |
322 | 337 | ||
338 | + @Value("${edges.enabled}") | ||
339 | + @Getter | ||
340 | + private boolean edgesEnabled; | ||
323 | 341 | ||
324 | @Scheduled(fixedDelayString = "${actors.statistics.js_print_interval_ms}") | 342 | @Scheduled(fixedDelayString = "${actors.statistics.js_print_interval_ms}") |
325 | public void printStats() { | 343 | public void printStats() { |
@@ -35,10 +35,12 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | @@ -35,10 +35,12 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
35 | import org.thingsboard.server.common.msg.MsgType; | 35 | import org.thingsboard.server.common.msg.MsgType; |
36 | import org.thingsboard.server.common.msg.TbActorMsg; | 36 | import org.thingsboard.server.common.msg.TbActorMsg; |
37 | import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | 37 | import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
38 | +import org.thingsboard.server.common.msg.edge.EdgeEventUpdateMsg; | ||
38 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 39 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
39 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; | 40 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
40 | import org.thingsboard.server.common.msg.queue.RuleEngineException; | 41 | import org.thingsboard.server.common.msg.queue.RuleEngineException; |
41 | import org.thingsboard.server.common.msg.queue.ServiceType; | 42 | import org.thingsboard.server.common.msg.queue.ServiceType; |
43 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
42 | import org.thingsboard.server.dao.tenant.TenantService; | 44 | import org.thingsboard.server.dao.tenant.TenantService; |
43 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | 45 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
44 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | 46 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
@@ -89,10 +91,15 @@ public class AppActor extends ContextAwareActor { | @@ -89,10 +91,15 @@ public class AppActor extends ContextAwareActor { | ||
89 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | 91 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
90 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | 92 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
91 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | 93 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
94 | + case DEVICE_EDGE_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
92 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | 95 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
96 | + case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | ||
93 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | 97 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: |
94 | onToDeviceActorMsg((TenantAwareMsg) msg, true); | 98 | onToDeviceActorMsg((TenantAwareMsg) msg, true); |
95 | break; | 99 | break; |
100 | + case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG: | ||
101 | + onToTenantActorMsg((EdgeEventUpdateMsg) msg); | ||
102 | + break; | ||
96 | default: | 103 | default: |
97 | return false; | 104 | return false; |
98 | } | 105 | } |
@@ -192,6 +199,20 @@ public class AppActor extends ContextAwareActor { | @@ -192,6 +199,20 @@ public class AppActor extends ContextAwareActor { | ||
192 | () -> new TenantActor.ActorCreator(systemContext, tenantId)); | 199 | () -> new TenantActor.ActorCreator(systemContext, tenantId)); |
193 | } | 200 | } |
194 | 201 | ||
202 | + private void onToTenantActorMsg(EdgeEventUpdateMsg msg) { | ||
203 | + TbActorRef target = null; | ||
204 | + if (ModelConstants.SYSTEM_TENANT.equals(msg.getTenantId())) { | ||
205 | + log.warn("Message has system tenant id: {}", msg); | ||
206 | + } else { | ||
207 | + target = getOrCreateTenantActor(msg.getTenantId()); | ||
208 | + } | ||
209 | + if (target != null) { | ||
210 | + target.tellWithHighPriority(msg); | ||
211 | + } else { | ||
212 | + log.debug("[{}] Invalid edge event update msg: {}", msg.getTenantId(), msg); | ||
213 | + } | ||
214 | + } | ||
215 | + | ||
195 | public static class ActorCreator extends ContextBasedCreator { | 216 | public static class ActorCreator extends ContextBasedCreator { |
196 | 217 | ||
197 | public ActorCreator(ActorSystemContext context) { | 218 | public ActorCreator(ActorSystemContext context) { |
@@ -17,6 +17,7 @@ package org.thingsboard.server.actors.device; | @@ -17,6 +17,7 @@ package org.thingsboard.server.actors.device; | ||
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; | 19 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
20 | +import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg; | ||
20 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | 21 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
21 | import org.thingsboard.server.actors.ActorSystemContext; | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | import org.thingsboard.server.actors.TbActorCtx; | 23 | import org.thingsboard.server.actors.TbActorCtx; |
@@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.id.DeviceId; | @@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.id.DeviceId; | ||
26 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | import org.thingsboard.server.common.msg.TbActorMsg; | 28 | import org.thingsboard.server.common.msg.TbActorMsg; |
28 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; | 29 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
30 | +import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; | ||
29 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | 31 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
30 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | 32 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
31 | 33 | ||
@@ -70,12 +72,18 @@ public class DeviceActor extends ContextAwareActor { | @@ -70,12 +72,18 @@ public class DeviceActor extends ContextAwareActor { | ||
70 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | 72 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
71 | processor.processRpcRequest(ctx, (ToDeviceRpcRequestActorMsg) msg); | 73 | processor.processRpcRequest(ctx, (ToDeviceRpcRequestActorMsg) msg); |
72 | break; | 74 | break; |
75 | + case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | ||
76 | + processor.processRpcResponsesFromEdge(ctx, (FromDeviceRpcResponseActorMsg) msg); | ||
77 | + break; | ||
73 | case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: | 78 | case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: |
74 | processor.processServerSideRpcTimeout(ctx, (DeviceActorServerSideRpcTimeoutMsg) msg); | 79 | processor.processServerSideRpcTimeout(ctx, (DeviceActorServerSideRpcTimeoutMsg) msg); |
75 | break; | 80 | break; |
76 | case SESSION_TIMEOUT_MSG: | 81 | case SESSION_TIMEOUT_MSG: |
77 | processor.checkSessionsTimeout(); | 82 | processor.checkSessionsTimeout(); |
78 | break; | 83 | break; |
84 | + case DEVICE_EDGE_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
85 | + processor.processEdgeUpdate((DeviceEdgeUpdateMsg) msg); | ||
86 | + break; | ||
79 | default: | 87 | default: |
80 | return false; | 88 | return false; |
81 | } | 89 | } |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.actors.device; | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
18 | import com.google.common.util.concurrent.FutureCallback; | 19 | import com.google.common.util.concurrent.FutureCallback; |
19 | import com.google.common.util.concurrent.Futures; | 20 | import com.google.common.util.concurrent.Futures; |
20 | import com.google.common.util.concurrent.ListenableFuture; | 21 | import com.google.common.util.concurrent.ListenableFuture; |
@@ -24,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; | @@ -24,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; | ||
24 | import org.apache.commons.collections.CollectionUtils; | 25 | import org.apache.commons.collections.CollectionUtils; |
25 | import org.thingsboard.rule.engine.api.RpcError; | 26 | import org.thingsboard.rule.engine.api.RpcError; |
26 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; | 27 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
28 | +import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg; | ||
27 | import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; | 29 | import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; |
28 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | 30 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
29 | import org.thingsboard.server.actors.ActorSystemContext; | 31 | import org.thingsboard.server.actors.ActorSystemContext; |
@@ -31,11 +33,17 @@ import org.thingsboard.server.actors.TbActorCtx; | @@ -31,11 +33,17 @@ import org.thingsboard.server.actors.TbActorCtx; | ||
31 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; | 33 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
32 | import org.thingsboard.server.common.data.DataConstants; | 34 | import org.thingsboard.server.common.data.DataConstants; |
33 | import org.thingsboard.server.common.data.Device; | 35 | import org.thingsboard.server.common.data.Device; |
36 | +import org.thingsboard.server.common.data.edge.EdgeEvent; | ||
37 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
38 | +import org.thingsboard.server.common.data.edge.EdgeEventType; | ||
34 | import org.thingsboard.server.common.data.id.DeviceId; | 39 | import org.thingsboard.server.common.data.id.DeviceId; |
40 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
35 | import org.thingsboard.server.common.data.id.TenantId; | 41 | import org.thingsboard.server.common.data.id.TenantId; |
36 | import org.thingsboard.server.common.data.kv.AttributeKey; | 42 | import org.thingsboard.server.common.data.kv.AttributeKey; |
37 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 43 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
38 | import org.thingsboard.server.common.data.kv.KvEntry; | 44 | import org.thingsboard.server.common.data.kv.KvEntry; |
45 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
46 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
39 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | 47 | import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; |
40 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 48 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
41 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; | 49 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
@@ -68,6 +76,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceAct | @@ -68,6 +76,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceAct | ||
68 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; | 76 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; |
69 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; | 77 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
70 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; | 78 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
79 | +import org.thingsboard.server.service.rpc.FromDeviceRpcResponseActorMsg; | ||
71 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; | 80 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
72 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | 81 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
73 | 82 | ||
@@ -103,6 +112,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -103,6 +112,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
103 | private String deviceName; | 112 | private String deviceName; |
104 | private String deviceType; | 113 | private String deviceType; |
105 | private TbMsgMetaData defaultMetaData; | 114 | private TbMsgMetaData defaultMetaData; |
115 | + private EdgeId edgeId; | ||
106 | 116 | ||
107 | DeviceActorMessageProcessor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { | 117 | DeviceActorMessageProcessor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { |
108 | super(systemContext); | 118 | super(systemContext); |
@@ -125,12 +135,32 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -125,12 +135,32 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
125 | this.defaultMetaData = new TbMsgMetaData(); | 135 | this.defaultMetaData = new TbMsgMetaData(); |
126 | this.defaultMetaData.putValue("deviceName", deviceName); | 136 | this.defaultMetaData.putValue("deviceName", deviceName); |
127 | this.defaultMetaData.putValue("deviceType", deviceType); | 137 | this.defaultMetaData.putValue("deviceType", deviceType); |
138 | + if (systemContext.isEdgesEnabled()) { | ||
139 | + this.edgeId = findRelatedEdgeId(); | ||
140 | + } | ||
128 | return true; | 141 | return true; |
129 | } else { | 142 | } else { |
130 | return false; | 143 | return false; |
131 | } | 144 | } |
132 | } | 145 | } |
133 | 146 | ||
147 | + private EdgeId findRelatedEdgeId() { | ||
148 | + List<EntityRelation> result = | ||
149 | + systemContext.getRelationService().findByToAndType(tenantId, deviceId, EntityRelation.EDGE_TYPE, RelationTypeGroup.COMMON); | ||
150 | + if (result != null && result.size() > 0) { | ||
151 | + EntityRelation relationToEdge = result.get(0); | ||
152 | + if (relationToEdge.getFrom() != null && relationToEdge.getFrom().getId() != null) { | ||
153 | + log.trace("[{}][{}] found edge [{}] for device", tenantId, deviceId, relationToEdge.getFrom().getId()); | ||
154 | + return new EdgeId(relationToEdge.getFrom().getId()); | ||
155 | + } else { | ||
156 | + log.trace("[{}][{}] edge relation is empty {}", tenantId, deviceId, relationToEdge); | ||
157 | + } | ||
158 | + } else { | ||
159 | + log.trace("[{}][{}] device doesn't have any related edge", tenantId, deviceId); | ||
160 | + } | ||
161 | + return null; | ||
162 | + } | ||
163 | + | ||
134 | void processRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg) { | 164 | void processRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg) { |
135 | ToDeviceRpcRequest request = msg.getMsg(); | 165 | ToDeviceRpcRequest request = msg.getMsg(); |
136 | ToDeviceRpcRequestBody body = request.getBody(); | 166 | ToDeviceRpcRequestBody body = request.getBody(); |
@@ -143,15 +173,22 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -143,15 +173,22 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
143 | return; | 173 | return; |
144 | } | 174 | } |
145 | 175 | ||
146 | - boolean sent = rpcSubscriptions.size() > 0; | ||
147 | - Set<UUID> syncSessionSet = new HashSet<>(); | ||
148 | - rpcSubscriptions.forEach((key, value) -> { | ||
149 | - sendToTransport(rpcRequest, key, value.getNodeId()); | ||
150 | - if (SessionType.SYNC == value.getType()) { | ||
151 | - syncSessionSet.add(key); | ||
152 | - } | ||
153 | - }); | ||
154 | - syncSessionSet.forEach(rpcSubscriptions::remove); | 176 | + boolean sent; |
177 | + if (systemContext.isEdgesEnabled() && edgeId != null) { | ||
178 | + log.debug("[{}][{}] device is related to edge [{}]. Saving RPC request to edge queue", tenantId, deviceId, edgeId.getId()); | ||
179 | + saveRpcRequestToEdgeQueue(request, rpcRequest.getRequestId()); | ||
180 | + sent = true; | ||
181 | + } else { | ||
182 | + sent = rpcSubscriptions.size() > 0; | ||
183 | + Set<UUID> syncSessionSet = new HashSet<>(); | ||
184 | + rpcSubscriptions.forEach((key, value) -> { | ||
185 | + sendToTransport(rpcRequest, key, value.getNodeId()); | ||
186 | + if (SessionType.SYNC == value.getType()) { | ||
187 | + syncSessionSet.add(key); | ||
188 | + } | ||
189 | + }); | ||
190 | + syncSessionSet.forEach(rpcSubscriptions::remove); | ||
191 | + } | ||
155 | 192 | ||
156 | if (request.isOneway() && sent) { | 193 | if (request.isOneway() && sent) { |
157 | log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); | 194 | log.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); |
@@ -166,6 +203,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -166,6 +203,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
166 | } | 203 | } |
167 | } | 204 | } |
168 | 205 | ||
206 | + void processRpcResponsesFromEdge(TbActorCtx context, FromDeviceRpcResponseActorMsg responseMsg) { | ||
207 | + log.debug("[{}] Processing rpc command response from edge session", deviceId); | ||
208 | + ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); | ||
209 | + boolean success = requestMd != null; | ||
210 | + if (success) { | ||
211 | + systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(responseMsg.getMsg()); | ||
212 | + } else { | ||
213 | + log.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); | ||
214 | + } | ||
215 | + } | ||
216 | + | ||
169 | private void registerPendingRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { | 217 | private void registerPendingRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { |
170 | toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); | 218 | toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); |
171 | DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); | 219 | DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); |
@@ -498,6 +546,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -498,6 +546,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
498 | this.defaultMetaData.putValue("deviceType", deviceType); | 546 | this.defaultMetaData.putValue("deviceType", deviceType); |
499 | } | 547 | } |
500 | 548 | ||
549 | + void processEdgeUpdate(DeviceEdgeUpdateMsg msg) { | ||
550 | + log.trace("[{}] Processing edge update {}", deviceId, msg); | ||
551 | + this.edgeId = msg.getEdgeId(); | ||
552 | + } | ||
553 | + | ||
501 | private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { | 554 | private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { |
502 | ToTransportMsg msg = ToTransportMsg.newBuilder() | 555 | ToTransportMsg msg = ToTransportMsg.newBuilder() |
503 | .setSessionIdMSB(sessionInfo.getSessionIdMSB()) | 556 | .setSessionIdMSB(sessionInfo.getSessionIdMSB()) |
@@ -530,6 +583,36 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -530,6 +583,36 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
530 | systemContext.getTbCoreToTransportService().process(nodeId, msg); | 583 | systemContext.getTbCoreToTransportService().process(nodeId, msg); |
531 | } | 584 | } |
532 | 585 | ||
586 | + private void saveRpcRequestToEdgeQueue(ToDeviceRpcRequest msg, Integer requestId) { | ||
587 | + EdgeEvent edgeEvent = new EdgeEvent(); | ||
588 | + edgeEvent.setTenantId(tenantId); | ||
589 | + edgeEvent.setAction(EdgeEventActionType.RPC_CALL); | ||
590 | + edgeEvent.setEntityId(deviceId.getId()); | ||
591 | + edgeEvent.setType(EdgeEventType.DEVICE); | ||
592 | + | ||
593 | + ObjectNode body = mapper.createObjectNode(); | ||
594 | + body.put("requestId", requestId); | ||
595 | + body.put("requestUUID", msg.getId().toString()); | ||
596 | + body.put("oneway", msg.isOneway()); | ||
597 | + body.put("expirationTime", msg.getExpirationTime()); | ||
598 | + body.put("method", msg.getBody().getMethod()); | ||
599 | + body.put("params", msg.getBody().getParams()); | ||
600 | + edgeEvent.setBody(body); | ||
601 | + | ||
602 | + edgeEvent.setEdgeId(edgeId); | ||
603 | + ListenableFuture<EdgeEvent> future = systemContext.getEdgeEventService().saveAsync(edgeEvent); | ||
604 | + Futures.addCallback(future, new FutureCallback<EdgeEvent>() { | ||
605 | + @Override | ||
606 | + public void onSuccess( EdgeEvent result) { | ||
607 | + systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId); | ||
608 | + } | ||
609 | + | ||
610 | + @Override | ||
611 | + public void onFailure(Throwable t) { | ||
612 | + log.warn("[{}] Can't save edge event [{}] for edge [{}]", tenantId.getId(), edgeEvent, edgeId.getId(), t); | ||
613 | + } | ||
614 | + }, systemContext.getDbCallbackExecutor()); | ||
615 | + } | ||
533 | 616 | ||
534 | private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) { | 617 | private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) { |
535 | List<TsKvProto> clientAttributes; | 618 | List<TsKvProto> clientAttributes; |
@@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.TenantProfile; | @@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.TenantProfile; | ||
42 | import org.thingsboard.server.common.data.alarm.Alarm; | 42 | import org.thingsboard.server.common.data.alarm.Alarm; |
43 | import org.thingsboard.server.common.data.asset.Asset; | 43 | import org.thingsboard.server.common.data.asset.Asset; |
44 | import org.thingsboard.server.common.data.id.DeviceId; | 44 | import org.thingsboard.server.common.data.id.DeviceId; |
45 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
45 | import org.thingsboard.server.common.data.id.EntityId; | 46 | import org.thingsboard.server.common.data.id.EntityId; |
46 | import org.thingsboard.server.common.data.id.RuleChainId; | 47 | import org.thingsboard.server.common.data.id.RuleChainId; |
47 | import org.thingsboard.server.common.data.id.RuleNodeId; | 48 | import org.thingsboard.server.common.data.id.RuleNodeId; |
@@ -62,6 +63,8 @@ import org.thingsboard.server.dao.cassandra.CassandraCluster; | @@ -62,6 +63,8 @@ import org.thingsboard.server.dao.cassandra.CassandraCluster; | ||
62 | import org.thingsboard.server.dao.customer.CustomerService; | 63 | import org.thingsboard.server.dao.customer.CustomerService; |
63 | import org.thingsboard.server.dao.dashboard.DashboardService; | 64 | import org.thingsboard.server.dao.dashboard.DashboardService; |
64 | import org.thingsboard.server.dao.device.DeviceService; | 65 | import org.thingsboard.server.dao.device.DeviceService; |
66 | +import org.thingsboard.server.dao.edge.EdgeEventService; | ||
67 | +import org.thingsboard.server.dao.edge.EdgeService; | ||
65 | import org.thingsboard.server.dao.entityview.EntityViewService; | 68 | import org.thingsboard.server.dao.entityview.EntityViewService; |
66 | import org.thingsboard.server.dao.nosql.CassandraStatementTask; | 69 | import org.thingsboard.server.dao.nosql.CassandraStatementTask; |
67 | import org.thingsboard.server.dao.nosql.TbResultSetFuture; | 70 | import org.thingsboard.server.dao.nosql.TbResultSetFuture; |
@@ -319,6 +322,11 @@ class DefaultTbContext implements TbContext { | @@ -319,6 +322,11 @@ class DefaultTbContext implements TbContext { | ||
319 | return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueName, ruleChainId); | 322 | return entityActionMsg(alarm, alarm.getId(), ruleNodeId, action, queueName, ruleChainId); |
320 | } | 323 | } |
321 | 324 | ||
325 | + @Override | ||
326 | + public void onEdgeEventUpdate(TenantId tenantId, EdgeId edgeId) { | ||
327 | + mainCtx.getClusterService().onEdgeEventUpdate(tenantId, edgeId); | ||
328 | + } | ||
329 | + | ||
322 | public <E, I extends EntityId> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action) { | 330 | public <E, I extends EntityId> TbMsg entityActionMsg(E entity, I id, RuleNodeId ruleNodeId, String action) { |
323 | return entityActionMsg(entity, id, ruleNodeId, action, ServiceQueue.MAIN, null); | 331 | return entityActionMsg(entity, id, ruleNodeId, action, ServiceQueue.MAIN, null); |
324 | } | 332 | } |
@@ -478,6 +486,16 @@ class DefaultTbContext implements TbContext { | @@ -478,6 +486,16 @@ class DefaultTbContext implements TbContext { | ||
478 | } | 486 | } |
479 | 487 | ||
480 | @Override | 488 | @Override |
489 | + public EdgeService getEdgeService() { | ||
490 | + return mainCtx.getEdgeService(); | ||
491 | + } | ||
492 | + | ||
493 | + @Override | ||
494 | + public EdgeEventService getEdgeEventService() { | ||
495 | + return mainCtx.getEdgeEventService(); | ||
496 | + } | ||
497 | + | ||
498 | + @Override | ||
481 | public EventLoopGroup getSharedEventLoop() { | 499 | public EventLoopGroup getSharedEventLoop() { |
482 | return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); | 500 | return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); |
483 | } | 501 | } |
@@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
32 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | 32 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
33 | import org.thingsboard.server.common.data.relation.EntityRelation; | 33 | import org.thingsboard.server.common.data.relation.EntityRelation; |
34 | import org.thingsboard.server.common.data.rule.RuleChain; | 34 | import org.thingsboard.server.common.data.rule.RuleChain; |
35 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
35 | import org.thingsboard.server.common.data.rule.RuleNode; | 36 | import org.thingsboard.server.common.data.rule.RuleNode; |
36 | import org.thingsboard.server.common.msg.TbMsg; | 37 | import org.thingsboard.server.common.msg.TbMsg; |
37 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 38 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
@@ -99,7 +100,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -99,7 +100,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
99 | public void start(TbActorCtx context) { | 100 | public void start(TbActorCtx context) { |
100 | if (!started) { | 101 | if (!started) { |
101 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); | 102 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); |
102 | - if (ruleChain != null) { | 103 | + if (ruleChain != null && RuleChainType.CORE.equals(ruleChain.getType())) { |
103 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); | 104 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); |
104 | log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | 105 | log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); |
105 | // Creating and starting the actors; | 106 | // Creating and starting the actors; |
@@ -119,7 +120,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | @@ -119,7 +120,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh | ||
119 | @Override | 120 | @Override |
120 | public void onUpdate(TbActorCtx context) { | 121 | public void onUpdate(TbActorCtx context) { |
121 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); | 122 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); |
122 | - if (ruleChain != null) { | 123 | + if (ruleChain != null && RuleChainType.CORE.equals(ruleChain.getType())) { |
123 | ruleChainName = ruleChain.getName(); | 124 | ruleChainName = ruleChain.getName(); |
124 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); | 125 | List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId); |
125 | log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); | 126 | log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size()); |
@@ -23,13 +23,13 @@ import org.thingsboard.server.actors.TbEntityActorId; | @@ -23,13 +23,13 @@ import org.thingsboard.server.actors.TbEntityActorId; | ||
23 | import org.thingsboard.server.actors.TbEntityTypeActorIdPredicate; | 23 | import org.thingsboard.server.actors.TbEntityTypeActorIdPredicate; |
24 | import org.thingsboard.server.actors.service.ContextAwareActor; | 24 | import org.thingsboard.server.actors.service.ContextAwareActor; |
25 | import org.thingsboard.server.actors.service.DefaultActorService; | 25 | import org.thingsboard.server.actors.service.DefaultActorService; |
26 | -import org.thingsboard.server.actors.tenant.TenantActor; | ||
27 | import org.thingsboard.server.common.data.EntityType; | 26 | import org.thingsboard.server.common.data.EntityType; |
28 | import org.thingsboard.server.common.data.id.EntityId; | 27 | import org.thingsboard.server.common.data.id.EntityId; |
29 | import org.thingsboard.server.common.data.id.RuleChainId; | 28 | import org.thingsboard.server.common.data.id.RuleChainId; |
30 | import org.thingsboard.server.common.data.id.TenantId; | 29 | import org.thingsboard.server.common.data.id.TenantId; |
31 | import org.thingsboard.server.common.data.page.PageDataIterable; | 30 | import org.thingsboard.server.common.data.page.PageDataIterable; |
32 | import org.thingsboard.server.common.data.rule.RuleChain; | 31 | import org.thingsboard.server.common.data.rule.RuleChain; |
32 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
33 | import org.thingsboard.server.common.msg.TbActorMsg; | 33 | import org.thingsboard.server.common.msg.TbActorMsg; |
34 | import org.thingsboard.server.dao.rule.RuleChainService; | 34 | import org.thingsboard.server.dao.rule.RuleChainService; |
35 | 35 | ||
@@ -55,7 +55,7 @@ public abstract class RuleChainManagerActor extends ContextAwareActor { | @@ -55,7 +55,7 @@ public abstract class RuleChainManagerActor extends ContextAwareActor { | ||
55 | } | 55 | } |
56 | 56 | ||
57 | protected void initRuleChains() { | 57 | protected void initRuleChains() { |
58 | - for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChains(tenantId, link), ContextAwareActor.ENTITY_PACK_LIMIT)) { | 58 | + for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, link), ContextAwareActor.ENTITY_PACK_LIMIT)) { |
59 | RuleChainId ruleChainId = ruleChain.getId(); | 59 | RuleChainId ruleChainId = ruleChain.getId(); |
60 | log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId()); | 60 | log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId()); |
61 | TbActorRef actorRef = getOrCreateActor(ruleChainId, id -> ruleChain); | 61 | TbActorRef actorRef = getOrCreateActor(ruleChainId, id -> ruleChain); |
@@ -65,13 +65,13 @@ public abstract class RuleChainManagerActor extends ContextAwareActor { | @@ -65,13 +65,13 @@ public abstract class RuleChainManagerActor extends ContextAwareActor { | ||
65 | } | 65 | } |
66 | 66 | ||
67 | protected void destroyRuleChains() { | 67 | protected void destroyRuleChains() { |
68 | - for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChains(tenantId, link), ContextAwareActor.ENTITY_PACK_LIMIT)) { | 68 | + for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, link), ContextAwareActor.ENTITY_PACK_LIMIT)) { |
69 | ctx.stop(new TbEntityActorId(ruleChain.getId())); | 69 | ctx.stop(new TbEntityActorId(ruleChain.getId())); |
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | protected void visit(RuleChain entity, TbActorRef actorRef) { | 73 | protected void visit(RuleChain entity, TbActorRef actorRef) { |
74 | - if (entity != null && entity.isRoot()) { | 74 | + if (entity != null && entity.isRoot() && entity.getType().equals(RuleChainType.CORE)) { |
75 | rootChain = entity; | 75 | rootChain = entity; |
76 | rootChainActor = actorRef; | 76 | rootChainActor = actorRef; |
77 | } | 77 | } |
@@ -33,21 +33,27 @@ import org.thingsboard.server.common.data.ApiUsageState; | @@ -33,21 +33,27 @@ import org.thingsboard.server.common.data.ApiUsageState; | ||
33 | import org.thingsboard.server.common.data.EntityType; | 33 | import org.thingsboard.server.common.data.EntityType; |
34 | import org.thingsboard.server.common.data.Tenant; | 34 | import org.thingsboard.server.common.data.Tenant; |
35 | import org.thingsboard.server.common.data.TenantProfile; | 35 | import org.thingsboard.server.common.data.TenantProfile; |
36 | +import org.thingsboard.server.common.data.edge.Edge; | ||
36 | import org.thingsboard.server.common.data.id.DeviceId; | 37 | import org.thingsboard.server.common.data.id.DeviceId; |
38 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
37 | import org.thingsboard.server.common.data.id.EntityId; | 39 | import org.thingsboard.server.common.data.id.EntityId; |
38 | import org.thingsboard.server.common.data.id.RuleChainId; | 40 | import org.thingsboard.server.common.data.id.RuleChainId; |
39 | import org.thingsboard.server.common.data.id.TenantId; | 41 | import org.thingsboard.server.common.data.id.TenantId; |
42 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
40 | import org.thingsboard.server.common.data.rule.RuleChain; | 43 | import org.thingsboard.server.common.data.rule.RuleChain; |
44 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
41 | import org.thingsboard.server.common.msg.MsgType; | 45 | import org.thingsboard.server.common.msg.MsgType; |
42 | import org.thingsboard.server.common.msg.TbActorMsg; | 46 | import org.thingsboard.server.common.msg.TbActorMsg; |
43 | import org.thingsboard.server.common.msg.TbMsg; | 47 | import org.thingsboard.server.common.msg.TbMsg; |
44 | import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; | 48 | import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; |
45 | import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; | 49 | import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; |
50 | +import org.thingsboard.server.common.msg.edge.EdgeEventUpdateMsg; | ||
46 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | 51 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
47 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; | 52 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
48 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; | 53 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
49 | import org.thingsboard.server.common.msg.queue.RuleEngineException; | 54 | import org.thingsboard.server.common.msg.queue.RuleEngineException; |
50 | import org.thingsboard.server.common.msg.queue.ServiceType; | 55 | import org.thingsboard.server.common.msg.queue.ServiceType; |
56 | +import org.thingsboard.server.service.edge.rpc.EdgeRpcService; | ||
51 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; | 57 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
52 | 58 | ||
53 | import java.util.List; | 59 | import java.util.List; |
@@ -155,13 +161,18 @@ public class TenantActor extends RuleChainManagerActor { | @@ -155,13 +161,18 @@ public class TenantActor extends RuleChainManagerActor { | ||
155 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | 161 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
156 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | 162 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
157 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | 163 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
164 | + case DEVICE_EDGE_UPDATE_TO_DEVICE_ACTOR_MSG: | ||
158 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | 165 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
166 | + case DEVICE_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | ||
159 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: | 167 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: |
160 | onToDeviceActorMsg((DeviceAwareMsg) msg, true); | 168 | onToDeviceActorMsg((DeviceAwareMsg) msg, true); |
161 | break; | 169 | break; |
162 | case RULE_CHAIN_TO_RULE_CHAIN_MSG: | 170 | case RULE_CHAIN_TO_RULE_CHAIN_MSG: |
163 | onRuleChainMsg((RuleChainAwareMsg) msg); | 171 | onRuleChainMsg((RuleChainAwareMsg) msg); |
164 | break; | 172 | break; |
173 | + case EDGE_EVENT_UPDATE_TO_EDGE_SESSION_MSG: | ||
174 | + onToEdgeSessionMsg((EdgeEventUpdateMsg) msg); | ||
175 | + break; | ||
165 | default: | 176 | default: |
166 | return false; | 177 | return false; |
167 | } | 178 | } |
@@ -230,14 +241,26 @@ public class TenantActor extends RuleChainManagerActor { | @@ -230,14 +241,26 @@ public class TenantActor extends RuleChainManagerActor { | ||
230 | log.info("[{}] Received API state update. Going to ENABLE Rule Engine execution.", tenantId); | 241 | log.info("[{}] Received API state update. Going to ENABLE Rule Engine execution.", tenantId); |
231 | initRuleChains(); | 242 | initRuleChains(); |
232 | } | 243 | } |
233 | - } | ||
234 | - if (isRuleEngineForCurrentTenant) { | 244 | + } else if (msg.getEntityId().getEntityType() == EntityType.EDGE) { |
245 | + EdgeId edgeId = new EdgeId(msg.getEntityId().getId()); | ||
246 | + EdgeRpcService edgeRpcService = systemContext.getEdgeRpcService(); | ||
247 | + if (msg.getEvent() == ComponentLifecycleEvent.DELETED) { | ||
248 | + edgeRpcService.deleteEdge(edgeId); | ||
249 | + } else { | ||
250 | + Edge edge = systemContext.getEdgeService().findEdgeById(tenantId, edgeId); | ||
251 | + if (msg.getEvent() == ComponentLifecycleEvent.UPDATED) { | ||
252 | + edgeRpcService.updateEdge(edge); | ||
253 | + } | ||
254 | + } | ||
255 | + } else if (isRuleEngineForCurrentTenant) { | ||
235 | TbActorRef target = getEntityActorRef(msg.getEntityId()); | 256 | TbActorRef target = getEntityActorRef(msg.getEntityId()); |
236 | if (target != null) { | 257 | if (target != null) { |
237 | if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { | 258 | if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { |
238 | RuleChain ruleChain = systemContext.getRuleChainService(). | 259 | RuleChain ruleChain = systemContext.getRuleChainService(). |
239 | findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); | 260 | findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); |
240 | - visit(ruleChain, target); | 261 | + if (ruleChain != null && RuleChainType.CORE.equals(ruleChain.getType())) { |
262 | + visit(ruleChain, target); | ||
263 | + } | ||
241 | } | 264 | } |
242 | target.tellWithHighPriority(msg); | 265 | target.tellWithHighPriority(msg); |
243 | } else { | 266 | } else { |
@@ -252,6 +275,11 @@ public class TenantActor extends RuleChainManagerActor { | @@ -252,6 +275,11 @@ public class TenantActor extends RuleChainManagerActor { | ||
252 | () -> new DeviceActorCreator(systemContext, tenantId, deviceId)); | 275 | () -> new DeviceActorCreator(systemContext, tenantId, deviceId)); |
253 | } | 276 | } |
254 | 277 | ||
278 | + private void onToEdgeSessionMsg(EdgeEventUpdateMsg msg) { | ||
279 | + log.trace("[{}] onToEdgeSessionMsg [{}]", msg.getTenantId(), msg); | ||
280 | + systemContext.getEdgeRpcService().onEdgeEvent(msg.getEdgeId()); | ||
281 | + } | ||
282 | + | ||
255 | public static class ActorCreator extends ContextBasedCreator { | 283 | public static class ActorCreator extends ContextBasedCreator { |
256 | 284 | ||
257 | private final TenantId tenantId; | 285 | private final TenantId tenantId; |
@@ -71,7 +71,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt | @@ -71,7 +71,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt | ||
71 | public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; | 71 | public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; |
72 | public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public"; | 72 | public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public"; |
73 | public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; | 73 | public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; |
74 | - protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**"}; | 74 | + protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**"}; |
75 | public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; | 75 | public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; |
76 | public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; | 76 | public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; |
77 | 77 |
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | ||
34 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 34 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
35 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 35 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
36 | import org.thingsboard.server.common.data.audit.ActionType; | 36 | import org.thingsboard.server.common.data.audit.ActionType; |
37 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
37 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 38 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
38 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 39 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
39 | import org.thingsboard.server.common.data.id.AlarmId; | 40 | import org.thingsboard.server.common.data.id.AlarmId; |
@@ -93,6 +94,9 @@ public class AlarmController extends BaseController { | @@ -93,6 +94,9 @@ public class AlarmController extends BaseController { | ||
93 | logEntityAction(savedAlarm.getOriginator(), savedAlarm, | 94 | logEntityAction(savedAlarm.getOriginator(), savedAlarm, |
94 | getCurrentUser().getCustomerId(), | 95 | getCurrentUser().getCustomerId(), |
95 | alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | 96 | alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
97 | + | ||
98 | + sendEntityNotificationMsg(getTenantId(), savedAlarm.getId(), alarm.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); | ||
99 | + | ||
96 | return savedAlarm; | 100 | return savedAlarm; |
97 | } catch (Exception e) { | 101 | } catch (Exception e) { |
98 | logEntityAction(emptyId(EntityType.ALARM), alarm, | 102 | logEntityAction(emptyId(EntityType.ALARM), alarm, |
@@ -109,8 +113,11 @@ public class AlarmController extends BaseController { | @@ -109,8 +113,11 @@ public class AlarmController extends BaseController { | ||
109 | try { | 113 | try { |
110 | AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); | 114 | AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); |
111 | checkAlarmId(alarmId, Operation.WRITE); | 115 | checkAlarmId(alarmId, Operation.WRITE); |
116 | + | ||
117 | + sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.DELETED); | ||
118 | + | ||
112 | return alarmService.deleteAlarm(getTenantId(), alarmId); | 119 | return alarmService.deleteAlarm(getTenantId(), alarmId); |
113 | - } catch (Exception e) { | 120 | + } catch (Exception e) { |
114 | throw handleException(e); | 121 | throw handleException(e); |
115 | } | 122 | } |
116 | } | 123 | } |
@@ -128,6 +135,8 @@ public class AlarmController extends BaseController { | @@ -128,6 +135,8 @@ public class AlarmController extends BaseController { | ||
128 | alarm.setAckTs(ackTs); | 135 | alarm.setAckTs(ackTs); |
129 | alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK); | 136 | alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK); |
130 | logEntityAction(alarm.getOriginator(), alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null); | 137 | logEntityAction(alarm.getOriginator(), alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null); |
138 | + | ||
139 | + sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.ALARM_ACK); | ||
131 | } catch (Exception e) { | 140 | } catch (Exception e) { |
132 | throw handleException(e); | 141 | throw handleException(e); |
133 | } | 142 | } |
@@ -146,6 +155,8 @@ public class AlarmController extends BaseController { | @@ -146,6 +155,8 @@ public class AlarmController extends BaseController { | ||
146 | alarm.setClearTs(clearTs); | 155 | alarm.setClearTs(clearTs); |
147 | alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK); | 156 | alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK); |
148 | logEntityAction(alarm.getOriginator(), alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null); | 157 | logEntityAction(alarm.getOriginator(), alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null); |
158 | + | ||
159 | + sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.ALARM_CLEAR); | ||
149 | } catch (Exception e) { | 160 | } catch (Exception e) { |
150 | throw handleException(e); | 161 | throw handleException(e); |
151 | } | 162 | } |
@@ -33,14 +33,18 @@ import org.thingsboard.server.common.data.asset.Asset; | @@ -33,14 +33,18 @@ import org.thingsboard.server.common.data.asset.Asset; | ||
33 | import org.thingsboard.server.common.data.asset.AssetInfo; | 33 | import org.thingsboard.server.common.data.asset.AssetInfo; |
34 | import org.thingsboard.server.common.data.asset.AssetSearchQuery; | 34 | import org.thingsboard.server.common.data.asset.AssetSearchQuery; |
35 | import org.thingsboard.server.common.data.audit.ActionType; | 35 | import org.thingsboard.server.common.data.audit.ActionType; |
36 | +import org.thingsboard.server.common.data.edge.Edge; | ||
37 | +import org.thingsboard.server.common.data.edge.EdgeEventType; | ||
36 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 38 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
39 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
37 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 40 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
38 | import org.thingsboard.server.common.data.id.AssetId; | 41 | import org.thingsboard.server.common.data.id.AssetId; |
39 | import org.thingsboard.server.common.data.id.CustomerId; | 42 | import org.thingsboard.server.common.data.id.CustomerId; |
43 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
40 | import org.thingsboard.server.common.data.id.TenantId; | 44 | import org.thingsboard.server.common.data.id.TenantId; |
41 | import org.thingsboard.server.common.data.page.PageData; | 45 | import org.thingsboard.server.common.data.page.PageData; |
42 | import org.thingsboard.server.common.data.page.PageLink; | 46 | import org.thingsboard.server.common.data.page.PageLink; |
43 | -import org.thingsboard.server.common.data.security.Authority; | 47 | +import org.thingsboard.server.common.data.page.TimePageLink; |
44 | import org.thingsboard.server.dao.exception.IncorrectParameterException; | 48 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
45 | import org.thingsboard.server.dao.model.ModelConstants; | 49 | import org.thingsboard.server.dao.model.ModelConstants; |
46 | import org.thingsboard.server.queue.util.TbCoreComponent; | 50 | import org.thingsboard.server.queue.util.TbCoreComponent; |
@@ -54,6 +58,8 @@ import java.util.stream.Collectors; | @@ -54,6 +58,8 @@ import java.util.stream.Collectors; | ||
54 | 58 | ||
55 | import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; | 59 | import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; |
56 | 60 | ||
61 | +import static org.thingsboard.server.controller.EdgeController.EDGE_ID; | ||
62 | + | ||
57 | @RestController | 63 | @RestController |
58 | @TbCoreComponent | 64 | @TbCoreComponent |
59 | @RequestMapping("/api") | 65 | @RequestMapping("/api") |
@@ -98,7 +104,7 @@ public class AssetController extends BaseController { | @@ -98,7 +104,7 @@ public class AssetController extends BaseController { | ||
98 | 104 | ||
99 | asset.setTenantId(getCurrentUser().getTenantId()); | 105 | asset.setTenantId(getCurrentUser().getTenantId()); |
100 | 106 | ||
101 | - checkEntity(asset.getId(), asset, Resource.ASSET); | 107 | + checkEntity(asset.getId(), asset, Resource.ASSET); |
102 | 108 | ||
103 | Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); | 109 | Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); |
104 | 110 | ||
@@ -106,6 +112,10 @@ public class AssetController extends BaseController { | @@ -106,6 +112,10 @@ public class AssetController extends BaseController { | ||
106 | savedAsset.getCustomerId(), | 112 | savedAsset.getCustomerId(), |
107 | asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | 113 | asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
108 | 114 | ||
115 | + if (asset.getId() != null) { | ||
116 | + sendEntityNotificationMsg(savedAsset.getTenantId(), savedAsset.getId(), EdgeEventActionType.UPDATED); | ||
117 | + } | ||
118 | + | ||
109 | return savedAsset; | 119 | return savedAsset; |
110 | } catch (Exception e) { | 120 | } catch (Exception e) { |
111 | logEntityAction(emptyId(EntityType.ASSET), asset, | 121 | logEntityAction(emptyId(EntityType.ASSET), asset, |
@@ -122,12 +132,16 @@ public class AssetController extends BaseController { | @@ -122,12 +132,16 @@ public class AssetController extends BaseController { | ||
122 | try { | 132 | try { |
123 | AssetId assetId = new AssetId(toUUID(strAssetId)); | 133 | AssetId assetId = new AssetId(toUUID(strAssetId)); |
124 | Asset asset = checkAssetId(assetId, Operation.DELETE); | 134 | Asset asset = checkAssetId(assetId, Operation.DELETE); |
135 | + | ||
136 | + List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(getTenantId(), assetId); | ||
137 | + | ||
125 | assetService.deleteAsset(getTenantId(), assetId); | 138 | assetService.deleteAsset(getTenantId(), assetId); |
126 | 139 | ||
127 | logEntityAction(assetId, asset, | 140 | logEntityAction(assetId, asset, |
128 | asset.getCustomerId(), | 141 | asset.getCustomerId(), |
129 | ActionType.DELETED, null, strAssetId); | 142 | ActionType.DELETED, null, strAssetId); |
130 | 143 | ||
144 | + sendDeleteNotificationMsg(getTenantId(), assetId, relatedEdgeIds); | ||
131 | } catch (Exception e) { | 145 | } catch (Exception e) { |
132 | logEntityAction(emptyId(EntityType.ASSET), | 146 | logEntityAction(emptyId(EntityType.ASSET), |
133 | null, | 147 | null, |
@@ -157,6 +171,9 @@ public class AssetController extends BaseController { | @@ -157,6 +171,9 @@ public class AssetController extends BaseController { | ||
157 | savedAsset.getCustomerId(), | 171 | savedAsset.getCustomerId(), |
158 | ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName()); | 172 | ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName()); |
159 | 173 | ||
174 | + sendEntityAssignToCustomerNotificationMsg(savedAsset.getTenantId(), savedAsset.getId(), | ||
175 | + customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); | ||
176 | + | ||
160 | return savedAsset; | 177 | return savedAsset; |
161 | } catch (Exception e) { | 178 | } catch (Exception e) { |
162 | 179 | ||
@@ -188,6 +205,9 @@ public class AssetController extends BaseController { | @@ -188,6 +205,9 @@ public class AssetController extends BaseController { | ||
188 | asset.getCustomerId(), | 205 | asset.getCustomerId(), |
189 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strAssetId, customer.getId().toString(), customer.getName()); | 206 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strAssetId, customer.getId().toString(), customer.getName()); |
190 | 207 | ||
208 | + sendEntityAssignToCustomerNotificationMsg(savedAsset.getTenantId(), savedAsset.getId(), | ||
209 | + customer.getId(), EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); | ||
210 | + | ||
191 | return savedAsset; | 211 | return savedAsset; |
192 | } catch (Exception e) { | 212 | } catch (Exception e) { |
193 | 213 | ||
@@ -401,4 +421,113 @@ public class AssetController extends BaseController { | @@ -401,4 +421,113 @@ public class AssetController extends BaseController { | ||
401 | throw handleException(e); | 421 | throw handleException(e); |
402 | } | 422 | } |
403 | } | 423 | } |
424 | + | ||
425 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
426 | + @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST) | ||
427 | + @ResponseBody | ||
428 | + public Asset assignAssetToEdge(@PathVariable(EDGE_ID) String strEdgeId, | ||
429 | + @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { | ||
430 | + checkParameter(EDGE_ID, strEdgeId); | ||
431 | + checkParameter(ASSET_ID, strAssetId); | ||
432 | + try { | ||
433 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
434 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
435 | + | ||
436 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | ||
437 | + checkAssetId(assetId, Operation.ASSIGN_TO_EDGE); | ||
438 | + | ||
439 | + Asset savedAsset = checkNotNull(assetService.assignAssetToEdge(getTenantId(), assetId, edgeId)); | ||
440 | + | ||
441 | + logEntityAction(assetId, savedAsset, | ||
442 | + savedAsset.getCustomerId(), | ||
443 | + ActionType.ASSIGNED_TO_EDGE, null, strAssetId, strEdgeId, edge.getName()); | ||
444 | + | ||
445 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedAsset.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); | ||
446 | + | ||
447 | + return savedAsset; | ||
448 | + } catch (Exception e) { | ||
449 | + | ||
450 | + logEntityAction(emptyId(EntityType.ASSET), null, | ||
451 | + null, | ||
452 | + ActionType.ASSIGNED_TO_EDGE, e, strAssetId, strEdgeId); | ||
453 | + | ||
454 | + throw handleException(e); | ||
455 | + } | ||
456 | + } | ||
457 | + | ||
458 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
459 | + @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.DELETE) | ||
460 | + @ResponseBody | ||
461 | + public Asset unassignAssetFromEdge(@PathVariable(EDGE_ID) String strEdgeId, | ||
462 | + @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { | ||
463 | + checkParameter(EDGE_ID, strEdgeId); | ||
464 | + checkParameter(ASSET_ID, strAssetId); | ||
465 | + try { | ||
466 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
467 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
468 | + | ||
469 | + AssetId assetId = new AssetId(toUUID(strAssetId)); | ||
470 | + Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_EDGE); | ||
471 | + | ||
472 | + Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId, edgeId)); | ||
473 | + | ||
474 | + logEntityAction(assetId, asset, | ||
475 | + asset.getCustomerId(), | ||
476 | + ActionType.UNASSIGNED_FROM_EDGE, null, strAssetId, strEdgeId, edge.getName()); | ||
477 | + | ||
478 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedAsset.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE); | ||
479 | + | ||
480 | + return savedAsset; | ||
481 | + } catch (Exception e) { | ||
482 | + | ||
483 | + logEntityAction(emptyId(EntityType.ASSET), null, | ||
484 | + null, | ||
485 | + ActionType.UNASSIGNED_FROM_EDGE, e, strAssetId, strEdgeId); | ||
486 | + | ||
487 | + throw handleException(e); | ||
488 | + } | ||
489 | + } | ||
490 | + | ||
491 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
492 | + @RequestMapping(value = "/edge/{edgeId}/assets", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
493 | + @ResponseBody | ||
494 | + public PageData<Asset> getEdgeAssets( | ||
495 | + @PathVariable(EDGE_ID) String strEdgeId, | ||
496 | + @RequestParam int pageSize, | ||
497 | + @RequestParam int page, | ||
498 | + @RequestParam(required = false) String type, | ||
499 | + @RequestParam(required = false) String textSearch, | ||
500 | + @RequestParam(required = false) String sortProperty, | ||
501 | + @RequestParam(required = false) String sortOrder, | ||
502 | + @RequestParam(required = false) Long startTime, | ||
503 | + @RequestParam(required = false) Long endTime) throws ThingsboardException { | ||
504 | + checkParameter(EDGE_ID, strEdgeId); | ||
505 | + try { | ||
506 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
507 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
508 | + checkEdgeId(edgeId, Operation.READ); | ||
509 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | ||
510 | + PageData<Asset> nonFilteredResult; | ||
511 | + if (type != null && type.trim().length() > 0) { | ||
512 | + nonFilteredResult = assetService.findAssetsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink); | ||
513 | + } else { | ||
514 | + nonFilteredResult = assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); | ||
515 | + } | ||
516 | + List<Asset> filteredAssets = nonFilteredResult.getData().stream().filter(asset -> { | ||
517 | + try { | ||
518 | + accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, Operation.READ, asset.getId(), asset); | ||
519 | + return true; | ||
520 | + } catch (ThingsboardException e) { | ||
521 | + return false; | ||
522 | + } | ||
523 | + }).collect(Collectors.toList()); | ||
524 | + PageData<Asset> filteredResult = new PageData<>(filteredAssets, | ||
525 | + nonFilteredResult.getTotalPages(), | ||
526 | + nonFilteredResult.getTotalElements(), | ||
527 | + nonFilteredResult.hasNext()); | ||
528 | + return checkNotNull(filteredResult); | ||
529 | + } catch (Exception e) { | ||
530 | + throw handleException(e); | ||
531 | + } | ||
532 | + } | ||
404 | } | 533 | } |
@@ -37,6 +37,7 @@ import org.thingsboard.common.util.JacksonUtil; | @@ -37,6 +37,7 @@ import org.thingsboard.common.util.JacksonUtil; | ||
37 | import org.thingsboard.rule.engine.api.MailService; | 37 | import org.thingsboard.rule.engine.api.MailService; |
38 | import org.thingsboard.server.common.data.User; | 38 | import org.thingsboard.server.common.data.User; |
39 | import org.thingsboard.server.common.data.audit.ActionType; | 39 | import org.thingsboard.server.common.data.audit.ActionType; |
40 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
40 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 41 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
41 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 42 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
42 | import org.thingsboard.server.common.data.id.TenantId; | 43 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -110,6 +111,8 @@ public class AuthController extends BaseController { | @@ -110,6 +111,8 @@ public class AuthController extends BaseController { | ||
110 | userCredentials.setPassword(passwordEncoder.encode(newPassword)); | 111 | userCredentials.setPassword(passwordEncoder.encode(newPassword)); |
111 | userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials); | 112 | userService.replaceUserCredentials(securityUser.getTenantId(), userCredentials); |
112 | 113 | ||
114 | + sendEntityNotificationMsg(getTenantId(), userCredentials.getUserId(), EdgeEventActionType.CREDENTIALS_UPDATED); | ||
115 | + | ||
113 | eventPublisher.publishEvent(new UserAuthDataChangedEvent(securityUser.getId())); | 116 | eventPublisher.publishEvent(new UserAuthDataChangedEvent(securityUser.getId())); |
114 | ObjectNode response = JacksonUtil.newObjectNode(); | 117 | ObjectNode response = JacksonUtil.newObjectNode(); |
115 | response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken()); | 118 | response.put("token", tokenFactory.createAccessJwtToken(securityUser).getToken()); |
@@ -224,6 +227,8 @@ public class AuthController extends BaseController { | @@ -224,6 +227,8 @@ public class AuthController extends BaseController { | ||
224 | } | 227 | } |
225 | } | 228 | } |
226 | 229 | ||
230 | + sendEntityNotificationMsg(user.getTenantId(), user.getId(), EdgeEventActionType.CREDENTIALS_UPDATED); | ||
231 | + | ||
227 | JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); | 232 | JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); |
228 | JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); | 233 | JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); |
229 | 234 |
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.DataConstants; | @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.DataConstants; | ||
34 | import org.thingsboard.server.common.data.Device; | 34 | import org.thingsboard.server.common.data.Device; |
35 | import org.thingsboard.server.common.data.DeviceInfo; | 35 | import org.thingsboard.server.common.data.DeviceInfo; |
36 | import org.thingsboard.server.common.data.DeviceProfile; | 36 | import org.thingsboard.server.common.data.DeviceProfile; |
37 | +import org.thingsboard.server.common.data.EdgeUtils; | ||
37 | import org.thingsboard.server.common.data.EntityType; | 38 | import org.thingsboard.server.common.data.EntityType; |
38 | import org.thingsboard.server.common.data.EntityView; | 39 | import org.thingsboard.server.common.data.EntityView; |
39 | import org.thingsboard.server.common.data.EntityViewInfo; | 40 | import org.thingsboard.server.common.data.EntityViewInfo; |
@@ -50,6 +51,10 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; | @@ -50,6 +51,10 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo; | ||
50 | import org.thingsboard.server.common.data.asset.Asset; | 51 | import org.thingsboard.server.common.data.asset.Asset; |
51 | import org.thingsboard.server.common.data.asset.AssetInfo; | 52 | import org.thingsboard.server.common.data.asset.AssetInfo; |
52 | import org.thingsboard.server.common.data.audit.ActionType; | 53 | import org.thingsboard.server.common.data.audit.ActionType; |
54 | +import org.thingsboard.server.common.data.edge.Edge; | ||
55 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
56 | +import org.thingsboard.server.common.data.edge.EdgeEventType; | ||
57 | +import org.thingsboard.server.common.data.edge.EdgeInfo; | ||
53 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 58 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
54 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 59 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
55 | import org.thingsboard.server.common.data.id.AlarmId; | 60 | import org.thingsboard.server.common.data.id.AlarmId; |
@@ -58,6 +63,7 @@ import org.thingsboard.server.common.data.id.CustomerId; | @@ -58,6 +63,7 @@ import org.thingsboard.server.common.data.id.CustomerId; | ||
58 | import org.thingsboard.server.common.data.id.DashboardId; | 63 | import org.thingsboard.server.common.data.id.DashboardId; |
59 | import org.thingsboard.server.common.data.id.DeviceId; | 64 | import org.thingsboard.server.common.data.id.DeviceId; |
60 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 65 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
66 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
61 | import org.thingsboard.server.common.data.id.EntityId; | 67 | import org.thingsboard.server.common.data.id.EntityId; |
62 | import org.thingsboard.server.common.data.id.EntityIdFactory; | 68 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
63 | import org.thingsboard.server.common.data.id.EntityViewId; | 69 | import org.thingsboard.server.common.data.id.EntityViewId; |
@@ -78,7 +84,9 @@ import org.thingsboard.server.common.data.page.SortOrder; | @@ -78,7 +84,9 @@ import org.thingsboard.server.common.data.page.SortOrder; | ||
78 | import org.thingsboard.server.common.data.page.TimePageLink; | 84 | import org.thingsboard.server.common.data.page.TimePageLink; |
79 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | 85 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
80 | import org.thingsboard.server.common.data.plugin.ComponentType; | 86 | import org.thingsboard.server.common.data.plugin.ComponentType; |
87 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
81 | import org.thingsboard.server.common.data.rule.RuleChain; | 88 | import org.thingsboard.server.common.data.rule.RuleChain; |
89 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
82 | import org.thingsboard.server.common.data.rule.RuleNode; | 90 | import org.thingsboard.server.common.data.rule.RuleNode; |
83 | import org.thingsboard.server.common.data.widget.WidgetTypeDetails; | 91 | import org.thingsboard.server.common.data.widget.WidgetTypeDetails; |
84 | import org.thingsboard.server.common.data.widget.WidgetsBundle; | 92 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
@@ -94,6 +102,7 @@ import org.thingsboard.server.dao.device.ClaimDevicesService; | @@ -94,6 +102,7 @@ import org.thingsboard.server.dao.device.ClaimDevicesService; | ||
94 | import org.thingsboard.server.dao.device.DeviceCredentialsService; | 102 | import org.thingsboard.server.dao.device.DeviceCredentialsService; |
95 | import org.thingsboard.server.dao.device.DeviceProfileService; | 103 | import org.thingsboard.server.dao.device.DeviceProfileService; |
96 | import org.thingsboard.server.dao.device.DeviceService; | 104 | import org.thingsboard.server.dao.device.DeviceService; |
105 | +import org.thingsboard.server.dao.edge.EdgeService; | ||
97 | import org.thingsboard.server.dao.entityview.EntityViewService; | 106 | import org.thingsboard.server.dao.entityview.EntityViewService; |
98 | import org.thingsboard.server.dao.exception.DataValidationException; | 107 | import org.thingsboard.server.dao.exception.DataValidationException; |
99 | import org.thingsboard.server.dao.exception.IncorrectParameterException; | 108 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
@@ -110,10 +119,14 @@ import org.thingsboard.server.dao.user.UserService; | @@ -110,10 +119,14 @@ import org.thingsboard.server.dao.user.UserService; | ||
110 | import org.thingsboard.server.dao.widget.WidgetTypeService; | 119 | import org.thingsboard.server.dao.widget.WidgetTypeService; |
111 | import org.thingsboard.server.dao.widget.WidgetsBundleService; | 120 | import org.thingsboard.server.dao.widget.WidgetsBundleService; |
112 | import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; | 121 | import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; |
122 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
113 | import org.thingsboard.server.queue.discovery.PartitionService; | 123 | import org.thingsboard.server.queue.discovery.PartitionService; |
114 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; | 124 | import org.thingsboard.server.queue.provider.TbQueueProducerProvider; |
115 | import org.thingsboard.server.queue.util.TbCoreComponent; | 125 | import org.thingsboard.server.queue.util.TbCoreComponent; |
116 | import org.thingsboard.server.service.component.ComponentDiscoveryService; | 126 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
127 | +import org.thingsboard.server.service.edge.EdgeNotificationService; | ||
128 | +import org.thingsboard.server.service.edge.rpc.EdgeGrpcService; | ||
129 | +import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService; | ||
117 | import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository; | 130 | import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository; |
118 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; | 131 | import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
119 | import org.thingsboard.server.service.queue.TbClusterService; | 132 | import org.thingsboard.server.service.queue.TbClusterService; |
@@ -244,10 +257,25 @@ public abstract class BaseController { | @@ -244,10 +257,25 @@ public abstract class BaseController { | ||
244 | @Autowired | 257 | @Autowired |
245 | protected LwM2MModelsRepository lwM2MModelsRepository; | 258 | protected LwM2MModelsRepository lwM2MModelsRepository; |
246 | 259 | ||
260 | + @Autowired(required = false) | ||
261 | + protected EdgeService edgeService; | ||
262 | + | ||
263 | + @Autowired(required = false) | ||
264 | + protected EdgeNotificationService edgeNotificationService; | ||
265 | + | ||
266 | + @Autowired(required = false) | ||
267 | + protected SyncEdgeService syncEdgeService; | ||
268 | + | ||
269 | + @Autowired(required = false) | ||
270 | + protected EdgeGrpcService edgeGrpcService; | ||
271 | + | ||
247 | @Value("${server.log_controller_error_stack_trace}") | 272 | @Value("${server.log_controller_error_stack_trace}") |
248 | @Getter | 273 | @Getter |
249 | private boolean logControllerErrorStackTrace; | 274 | private boolean logControllerErrorStackTrace; |
250 | 275 | ||
276 | + @Value("${edges.enabled}") | ||
277 | + @Getter | ||
278 | + protected boolean edgesEnabled; | ||
251 | 279 | ||
252 | @ExceptionHandler(ThingsboardException.class) | 280 | @ExceptionHandler(ThingsboardException.class) |
253 | public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { | 281 | public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { |
@@ -461,6 +489,9 @@ public abstract class BaseController { | @@ -461,6 +489,9 @@ public abstract class BaseController { | ||
461 | case ENTITY_VIEW: | 489 | case ENTITY_VIEW: |
462 | checkEntityViewId(new EntityViewId(entityId.getId()), operation); | 490 | checkEntityViewId(new EntityViewId(entityId.getId()), operation); |
463 | return; | 491 | return; |
492 | + case EDGE: | ||
493 | + checkEdgeId(new EdgeId(entityId.getId()), operation); | ||
494 | + return; | ||
464 | case WIDGETS_BUNDLE: | 495 | case WIDGETS_BUNDLE: |
465 | checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation); | 496 | checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation); |
466 | return; | 497 | return; |
@@ -622,6 +653,30 @@ public abstract class BaseController { | @@ -622,6 +653,30 @@ public abstract class BaseController { | ||
622 | } | 653 | } |
623 | } | 654 | } |
624 | 655 | ||
656 | + Edge checkEdgeId(EdgeId edgeId, Operation operation) throws ThingsboardException { | ||
657 | + try { | ||
658 | + validateId(edgeId, "Incorrect edgeId " + edgeId); | ||
659 | + Edge edge = edgeService.findEdgeById(getTenantId(), edgeId); | ||
660 | + checkNotNull(edge); | ||
661 | + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge); | ||
662 | + return edge; | ||
663 | + } catch (Exception e) { | ||
664 | + throw handleException(e, false); | ||
665 | + } | ||
666 | + } | ||
667 | + | ||
668 | + EdgeInfo checkEdgeInfoId(EdgeId edgeId, Operation operation) throws ThingsboardException { | ||
669 | + try { | ||
670 | + validateId(edgeId, "Incorrect edgeId " + edgeId); | ||
671 | + EdgeInfo edge = edgeService.findEdgeInfoById(getCurrentUser().getTenantId(), edgeId); | ||
672 | + checkNotNull(edge); | ||
673 | + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge); | ||
674 | + return edge; | ||
675 | + } catch (Exception e) { | ||
676 | + throw handleException(e, false); | ||
677 | + } | ||
678 | + } | ||
679 | + | ||
625 | DashboardInfo checkDashboardInfoId(DashboardId dashboardId, Operation operation) throws ThingsboardException { | 680 | DashboardInfo checkDashboardInfoId(DashboardId dashboardId, Operation operation) throws ThingsboardException { |
626 | try { | 681 | try { |
627 | validateId(dashboardId, "Incorrect dashboardId " + dashboardId); | 682 | validateId(dashboardId, "Incorrect dashboardId " + dashboardId); |
@@ -643,19 +698,19 @@ public abstract class BaseController { | @@ -643,19 +698,19 @@ public abstract class BaseController { | ||
643 | } | 698 | } |
644 | } | 699 | } |
645 | 700 | ||
646 | - List<ComponentDescriptor> checkComponentDescriptorsByType(ComponentType type) throws ThingsboardException { | 701 | + List<ComponentDescriptor> checkComponentDescriptorsByType(ComponentType type, RuleChainType ruleChainType) throws ThingsboardException { |
647 | try { | 702 | try { |
648 | log.debug("[{}] Lookup component descriptors", type); | 703 | log.debug("[{}] Lookup component descriptors", type); |
649 | - return componentDescriptorService.getComponents(type); | 704 | + return componentDescriptorService.getComponents(type, ruleChainType); |
650 | } catch (Exception e) { | 705 | } catch (Exception e) { |
651 | throw handleException(e, false); | 706 | throw handleException(e, false); |
652 | } | 707 | } |
653 | } | 708 | } |
654 | 709 | ||
655 | - List<ComponentDescriptor> checkComponentDescriptorsByTypes(Set<ComponentType> types) throws ThingsboardException { | 710 | + List<ComponentDescriptor> checkComponentDescriptorsByTypes(Set<ComponentType> types, RuleChainType ruleChainType) throws ThingsboardException { |
656 | try { | 711 | try { |
657 | log.debug("[{}] Lookup component descriptors", types); | 712 | log.debug("[{}] Lookup component descriptors", types); |
658 | - return componentDescriptorService.getComponents(types); | 713 | + return componentDescriptorService.getComponents(types, ruleChainType); |
659 | } catch (Exception e) { | 714 | } catch (Exception e) { |
660 | throw handleException(e, false); | 715 | throw handleException(e, false); |
661 | } | 716 | } |
@@ -776,6 +831,12 @@ public abstract class BaseController { | @@ -776,6 +831,12 @@ public abstract class BaseController { | ||
776 | case TIMESERIES_DELETED: | 831 | case TIMESERIES_DELETED: |
777 | msgType = DataConstants.TIMESERIES_DELETED; | 832 | msgType = DataConstants.TIMESERIES_DELETED; |
778 | break; | 833 | break; |
834 | + case ASSIGNED_TO_EDGE: | ||
835 | + msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE; | ||
836 | + break; | ||
837 | + case UNASSIGNED_FROM_EDGE: | ||
838 | + msgType = DataConstants.ENTITY_UNASSIGNED_FROM_EDGE; | ||
839 | + break; | ||
779 | } | 840 | } |
780 | if (!StringUtils.isEmpty(msgType)) { | 841 | if (!StringUtils.isEmpty(msgType)) { |
781 | try { | 842 | try { |
@@ -805,6 +866,16 @@ public abstract class BaseController { | @@ -805,6 +866,16 @@ public abstract class BaseController { | ||
805 | String strTenantName = extractParameter(String.class, 1, additionalInfo); | 866 | String strTenantName = extractParameter(String.class, 1, additionalInfo); |
806 | metaData.putValue("assignedToTenantId", strTenantId); | 867 | metaData.putValue("assignedToTenantId", strTenantId); |
807 | metaData.putValue("assignedToTenantName", strTenantName); | 868 | metaData.putValue("assignedToTenantName", strTenantName); |
869 | + } else if (actionType == ActionType.ASSIGNED_TO_EDGE) { | ||
870 | + String strEdgeId = extractParameter(String.class, 1, additionalInfo); | ||
871 | + String strEdgeName = extractParameter(String.class, 2, additionalInfo); | ||
872 | + metaData.putValue("assignedEdgeId", strEdgeId); | ||
873 | + metaData.putValue("assignedEdgeName", strEdgeName); | ||
874 | + } else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) { | ||
875 | + String strEdgeId = extractParameter(String.class, 1, additionalInfo); | ||
876 | + String strEdgeName = extractParameter(String.class, 2, additionalInfo); | ||
877 | + metaData.putValue("unassignedEdgeId", strEdgeId); | ||
878 | + metaData.putValue("unassignedEdgeName", strEdgeName); | ||
808 | } | 879 | } |
809 | ObjectNode entityNode; | 880 | ObjectNode entityNode; |
810 | if (entity != null) { | 881 | if (entity != null) { |
@@ -898,6 +969,93 @@ public abstract class BaseController { | @@ -898,6 +969,93 @@ public abstract class BaseController { | ||
898 | return null; | 969 | return null; |
899 | } | 970 | } |
900 | 971 | ||
972 | + protected void sendRelationNotificationMsg(TenantId tenantId, EntityRelation relation, EdgeEventActionType action) { | ||
973 | + try { | ||
974 | + if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && | ||
975 | + !relation.getTo().getEntityType().equals(EntityType.EDGE)) { | ||
976 | + sendNotificationMsgToEdgeService(tenantId, null, null, json.writeValueAsString(relation), EdgeEventType.RELATION, action); | ||
977 | + } | ||
978 | + } catch (Exception e) { | ||
979 | + log.warn("Failed to push relation to core: {}", relation, e); | ||
980 | + } | ||
981 | + } | ||
982 | + | ||
983 | + protected void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds) { | ||
984 | + if (edgeIds != null && !edgeIds.isEmpty()) { | ||
985 | + for (EdgeId edgeId : edgeIds) { | ||
986 | + sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, null, EdgeEventActionType.DELETED); | ||
987 | + } | ||
988 | + } | ||
989 | + } | ||
990 | + | ||
991 | + protected void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) { | ||
992 | + try { | ||
993 | + sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action); | ||
994 | + } catch (Exception e) { | ||
995 | + log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, e); | ||
996 | + } | ||
997 | + } | ||
998 | + | ||
999 | + protected void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) { | ||
1000 | + sendNotificationMsgToEdgeService(tenantId, null, entityId, null, null, action); | ||
1001 | + } | ||
1002 | + | ||
1003 | + protected void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) { | ||
1004 | + sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, null, action); | ||
1005 | + } | ||
1006 | + | ||
1007 | + private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) { | ||
1008 | + if (!edgesEnabled) { | ||
1009 | + return; | ||
1010 | + } | ||
1011 | + if (type == null) { | ||
1012 | + if (entityId != null) { | ||
1013 | + type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType()); | ||
1014 | + } else { | ||
1015 | + log.trace("[{}] entity id and type are null. Ignoring this notification", tenantId); | ||
1016 | + return; | ||
1017 | + } | ||
1018 | + if (type == null) { | ||
1019 | + log.trace("[{}] edge event type is null. Ignoring this notification [{}]", tenantId, entityId); | ||
1020 | + return; | ||
1021 | + } | ||
1022 | + } | ||
1023 | + TransportProtos.EdgeNotificationMsgProto.Builder builder = TransportProtos.EdgeNotificationMsgProto.newBuilder(); | ||
1024 | + builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); | ||
1025 | + builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()); | ||
1026 | + builder.setType(type.name()); | ||
1027 | + builder.setAction(action.name()); | ||
1028 | + if (entityId != null) { | ||
1029 | + builder.setEntityIdMSB(entityId.getId().getMostSignificantBits()); | ||
1030 | + builder.setEntityIdLSB(entityId.getId().getLeastSignificantBits()); | ||
1031 | + builder.setEntityType(entityId.getEntityType().name()); | ||
1032 | + } | ||
1033 | + if (edgeId != null) { | ||
1034 | + builder.setEdgeIdMSB(edgeId.getId().getMostSignificantBits()); | ||
1035 | + builder.setEdgeIdLSB(edgeId.getId().getLeastSignificantBits()); | ||
1036 | + } | ||
1037 | + if (body != null) { | ||
1038 | + builder.setBody(body); | ||
1039 | + } | ||
1040 | + TransportProtos.EdgeNotificationMsgProto msg = builder.build(); | ||
1041 | + log.trace("[{}] sending notification to edge service {}", tenantId.getId(), msg); | ||
1042 | + tbClusterService.pushMsgToCore(tenantId, entityId != null ? entityId : tenantId, | ||
1043 | + TransportProtos.ToCoreMsg.newBuilder().setEdgeNotificationMsg(msg).build(), null); | ||
1044 | + } | ||
1045 | + | ||
1046 | + protected List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) { | ||
1047 | + if (!edgesEnabled) { | ||
1048 | + return null; | ||
1049 | + } | ||
1050 | + List<EdgeId> result = null; | ||
1051 | + try { | ||
1052 | + result = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId).get(); | ||
1053 | + } catch (Exception e) { | ||
1054 | + log.error("[{}] can't find related edge ids for entity [{}]", tenantId, entityId, e); | ||
1055 | + } | ||
1056 | + return result; | ||
1057 | + } | ||
1058 | + | ||
901 | private void addTimeseries(ObjectNode entityNode, List<TsKvEntry> timeseries) throws Exception { | 1059 | private void addTimeseries(ObjectNode entityNode, List<TsKvEntry> timeseries) throws Exception { |
902 | if (timeseries != null && !timeseries.isEmpty()) { | 1060 | if (timeseries != null && !timeseries.isEmpty()) { |
903 | ArrayNode result = entityNode.putArray("timeseries"); | 1061 | ArrayNode result = entityNode.putArray("timeseries"); |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | +import org.apache.commons.lang3.StringUtils; | ||
18 | import org.springframework.security.access.prepost.PreAuthorize; | 19 | import org.springframework.security.access.prepost.PreAuthorize; |
19 | import org.springframework.web.bind.annotation.PathVariable; | 20 | import org.springframework.web.bind.annotation.PathVariable; |
20 | import org.springframework.web.bind.annotation.RequestMapping; | 21 | import org.springframework.web.bind.annotation.RequestMapping; |
@@ -25,6 +26,7 @@ import org.springframework.web.bind.annotation.RestController; | @@ -25,6 +26,7 @@ import org.springframework.web.bind.annotation.RestController; | ||
25 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 26 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
26 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | 27 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
27 | import org.thingsboard.server.common.data.plugin.ComponentType; | 28 | import org.thingsboard.server.common.data.plugin.ComponentType; |
29 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
28 | import org.thingsboard.server.queue.util.TbCoreComponent; | 30 | import org.thingsboard.server.queue.util.TbCoreComponent; |
29 | 31 | ||
30 | import java.util.HashSet; | 32 | import java.util.HashSet; |
@@ -51,10 +53,11 @@ public class ComponentDescriptorController extends BaseController { | @@ -51,10 +53,11 @@ public class ComponentDescriptorController extends BaseController { | ||
51 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") | 53 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") |
52 | @RequestMapping(value = "/components/{componentType}", method = RequestMethod.GET) | 54 | @RequestMapping(value = "/components/{componentType}", method = RequestMethod.GET) |
53 | @ResponseBody | 55 | @ResponseBody |
54 | - public List<ComponentDescriptor> getComponentDescriptorsByType(@PathVariable("componentType") String strComponentType) throws ThingsboardException { | 56 | + public List<ComponentDescriptor> getComponentDescriptorsByType(@PathVariable("componentType") String strComponentType, |
57 | + @RequestParam(value = "ruleChainType", required = false) String strRuleChainType) throws ThingsboardException { | ||
55 | checkParameter("componentType", strComponentType); | 58 | checkParameter("componentType", strComponentType); |
56 | try { | 59 | try { |
57 | - return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType)); | 60 | + return checkComponentDescriptorsByType(ComponentType.valueOf(strComponentType), getRuleChainType(strRuleChainType)); |
58 | } catch (Exception e) { | 61 | } catch (Exception e) { |
59 | throw handleException(e); | 62 | throw handleException(e); |
60 | } | 63 | } |
@@ -63,17 +66,28 @@ public class ComponentDescriptorController extends BaseController { | @@ -63,17 +66,28 @@ public class ComponentDescriptorController extends BaseController { | ||
63 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") | 66 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") |
64 | @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET) | 67 | @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET) |
65 | @ResponseBody | 68 | @ResponseBody |
66 | - public List<ComponentDescriptor> getComponentDescriptorsByTypes(@RequestParam("componentTypes") String[] strComponentTypes) throws ThingsboardException { | 69 | + public List<ComponentDescriptor> getComponentDescriptorsByTypes(@RequestParam("componentTypes") String[] strComponentTypes, |
70 | + @RequestParam(value = "ruleChainType", required = false) String strRuleChainType) throws ThingsboardException { | ||
67 | checkArrayParameter("componentTypes", strComponentTypes); | 71 | checkArrayParameter("componentTypes", strComponentTypes); |
68 | try { | 72 | try { |
69 | Set<ComponentType> componentTypes = new HashSet<>(); | 73 | Set<ComponentType> componentTypes = new HashSet<>(); |
70 | for (String strComponentType : strComponentTypes) { | 74 | for (String strComponentType : strComponentTypes) { |
71 | componentTypes.add(ComponentType.valueOf(strComponentType)); | 75 | componentTypes.add(ComponentType.valueOf(strComponentType)); |
72 | } | 76 | } |
73 | - return checkComponentDescriptorsByTypes(componentTypes); | 77 | + return checkComponentDescriptorsByTypes(componentTypes, getRuleChainType(strRuleChainType)); |
74 | } catch (Exception e) { | 78 | } catch (Exception e) { |
75 | throw handleException(e); | 79 | throw handleException(e); |
76 | } | 80 | } |
77 | } | 81 | } |
78 | 82 | ||
83 | + private RuleChainType getRuleChainType(String strRuleChainType) { | ||
84 | + RuleChainType ruleChainType; | ||
85 | + if (StringUtils.isEmpty(strRuleChainType)) { | ||
86 | + ruleChainType = RuleChainType.CORE; | ||
87 | + } else { | ||
88 | + ruleChainType = RuleChainType.valueOf(strRuleChainType); | ||
89 | + } | ||
90 | + return ruleChainType; | ||
91 | + } | ||
92 | + | ||
79 | } | 93 | } |
@@ -31,8 +31,10 @@ import org.springframework.web.bind.annotation.RestController; | @@ -31,8 +31,10 @@ import org.springframework.web.bind.annotation.RestController; | ||
31 | import org.thingsboard.server.common.data.Customer; | 31 | import org.thingsboard.server.common.data.Customer; |
32 | import org.thingsboard.server.common.data.EntityType; | 32 | import org.thingsboard.server.common.data.EntityType; |
33 | import org.thingsboard.server.common.data.audit.ActionType; | 33 | import org.thingsboard.server.common.data.audit.ActionType; |
34 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
34 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 35 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
35 | import org.thingsboard.server.common.data.id.CustomerId; | 36 | import org.thingsboard.server.common.data.id.CustomerId; |
37 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
36 | import org.thingsboard.server.common.data.id.TenantId; | 38 | import org.thingsboard.server.common.data.id.TenantId; |
37 | import org.thingsboard.server.common.data.page.PageData; | 39 | import org.thingsboard.server.common.data.page.PageData; |
38 | import org.thingsboard.server.common.data.page.PageLink; | 40 | import org.thingsboard.server.common.data.page.PageLink; |
@@ -40,6 +42,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; | @@ -40,6 +42,8 @@ import org.thingsboard.server.queue.util.TbCoreComponent; | ||
40 | import org.thingsboard.server.service.security.permission.Operation; | 42 | import org.thingsboard.server.service.security.permission.Operation; |
41 | import org.thingsboard.server.service.security.permission.Resource; | 43 | import org.thingsboard.server.service.security.permission.Resource; |
42 | 44 | ||
45 | +import java.util.List; | ||
46 | + | ||
43 | @RestController | 47 | @RestController |
44 | @TbCoreComponent | 48 | @TbCoreComponent |
45 | @RequestMapping("/api") | 49 | @RequestMapping("/api") |
@@ -112,6 +116,10 @@ public class CustomerController extends BaseController { | @@ -112,6 +116,10 @@ public class CustomerController extends BaseController { | ||
112 | savedCustomer.getId(), | 116 | savedCustomer.getId(), |
113 | customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | 117 | customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
114 | 118 | ||
119 | + if (customer.getId() != null) { | ||
120 | + sendEntityNotificationMsg(savedCustomer.getTenantId(), savedCustomer.getId(), EdgeEventActionType.UPDATED); | ||
121 | + } | ||
122 | + | ||
115 | return savedCustomer; | 123 | return savedCustomer; |
116 | } catch (Exception e) { | 124 | } catch (Exception e) { |
117 | 125 | ||
@@ -130,12 +138,16 @@ public class CustomerController extends BaseController { | @@ -130,12 +138,16 @@ public class CustomerController extends BaseController { | ||
130 | try { | 138 | try { |
131 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | 139 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
132 | Customer customer = checkCustomerId(customerId, Operation.DELETE); | 140 | Customer customer = checkCustomerId(customerId, Operation.DELETE); |
141 | + | ||
142 | + List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(getTenantId(), customerId); | ||
143 | + | ||
133 | customerService.deleteCustomer(getTenantId(), customerId); | 144 | customerService.deleteCustomer(getTenantId(), customerId); |
134 | 145 | ||
135 | logEntityAction(customerId, customer, | 146 | logEntityAction(customerId, customer, |
136 | customer.getId(), | 147 | customer.getId(), |
137 | ActionType.DELETED, null, strCustomerId); | 148 | ActionType.DELETED, null, strCustomerId); |
138 | 149 | ||
150 | + sendDeleteNotificationMsg(getTenantId(), customerId, relatedEdgeIds); | ||
139 | } catch (Exception e) { | 151 | } catch (Exception e) { |
140 | 152 | ||
141 | logEntityAction(emptyId(EntityType.CUSTOMER), | 153 | logEntityAction(emptyId(EntityType.CUSTOMER), |
@@ -38,20 +38,26 @@ import org.thingsboard.server.common.data.ShortCustomerInfo; | @@ -38,20 +38,26 @@ import org.thingsboard.server.common.data.ShortCustomerInfo; | ||
38 | import org.thingsboard.server.common.data.Tenant; | 38 | import org.thingsboard.server.common.data.Tenant; |
39 | import org.thingsboard.server.common.data.User; | 39 | import org.thingsboard.server.common.data.User; |
40 | import org.thingsboard.server.common.data.audit.ActionType; | 40 | import org.thingsboard.server.common.data.audit.ActionType; |
41 | +import org.thingsboard.server.common.data.edge.Edge; | ||
42 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
41 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 43 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
42 | import org.thingsboard.server.common.data.id.CustomerId; | 44 | import org.thingsboard.server.common.data.id.CustomerId; |
43 | import org.thingsboard.server.common.data.id.DashboardId; | 45 | import org.thingsboard.server.common.data.id.DashboardId; |
46 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
44 | import org.thingsboard.server.common.data.id.TenantId; | 47 | import org.thingsboard.server.common.data.id.TenantId; |
45 | import org.thingsboard.server.common.data.page.PageData; | 48 | import org.thingsboard.server.common.data.page.PageData; |
46 | import org.thingsboard.server.common.data.page.PageLink; | 49 | import org.thingsboard.server.common.data.page.PageLink; |
47 | import org.thingsboard.common.util.JacksonUtil; | 50 | import org.thingsboard.common.util.JacksonUtil; |
51 | +import org.thingsboard.server.common.data.page.TimePageLink; | ||
48 | import org.thingsboard.server.queue.util.TbCoreComponent; | 52 | import org.thingsboard.server.queue.util.TbCoreComponent; |
49 | import org.thingsboard.server.service.security.model.SecurityUser; | 53 | import org.thingsboard.server.service.security.model.SecurityUser; |
50 | import org.thingsboard.server.service.security.permission.Operation; | 54 | import org.thingsboard.server.service.security.permission.Operation; |
51 | import org.thingsboard.server.service.security.permission.Resource; | 55 | import org.thingsboard.server.service.security.permission.Resource; |
52 | 56 | ||
53 | import java.util.HashSet; | 57 | import java.util.HashSet; |
58 | +import java.util.List; | ||
54 | import java.util.Set; | 59 | import java.util.Set; |
60 | +import java.util.stream.Collectors; | ||
55 | 61 | ||
56 | @RestController | 62 | @RestController |
57 | @TbCoreComponent | 63 | @TbCoreComponent |
@@ -122,6 +128,10 @@ public class DashboardController extends BaseController { | @@ -122,6 +128,10 @@ public class DashboardController extends BaseController { | ||
122 | null, | 128 | null, |
123 | dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | 129 | dashboard.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
124 | 130 | ||
131 | + if (dashboard.getId() != null) { | ||
132 | + sendEntityNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), EdgeEventActionType.UPDATED); | ||
133 | + } | ||
134 | + | ||
125 | return savedDashboard; | 135 | return savedDashboard; |
126 | } catch (Exception e) { | 136 | } catch (Exception e) { |
127 | logEntityAction(emptyId(EntityType.DASHBOARD), dashboard, | 137 | logEntityAction(emptyId(EntityType.DASHBOARD), dashboard, |
@@ -139,12 +149,16 @@ public class DashboardController extends BaseController { | @@ -139,12 +149,16 @@ public class DashboardController extends BaseController { | ||
139 | try { | 149 | try { |
140 | DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | 150 | DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); |
141 | Dashboard dashboard = checkDashboardId(dashboardId, Operation.DELETE); | 151 | Dashboard dashboard = checkDashboardId(dashboardId, Operation.DELETE); |
152 | + | ||
153 | + List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(getTenantId(), dashboardId); | ||
154 | + | ||
142 | dashboardService.deleteDashboard(getCurrentUser().getTenantId(), dashboardId); | 155 | dashboardService.deleteDashboard(getCurrentUser().getTenantId(), dashboardId); |
143 | 156 | ||
144 | logEntityAction(dashboardId, dashboard, | 157 | logEntityAction(dashboardId, dashboard, |
145 | null, | 158 | null, |
146 | ActionType.DELETED, null, strDashboardId); | 159 | ActionType.DELETED, null, strDashboardId); |
147 | 160 | ||
161 | + sendDeleteNotificationMsg(getTenantId(), dashboardId, relatedEdgeIds); | ||
148 | } catch (Exception e) { | 162 | } catch (Exception e) { |
149 | 163 | ||
150 | logEntityAction(emptyId(EntityType.DASHBOARD), | 164 | logEntityAction(emptyId(EntityType.DASHBOARD), |
@@ -176,6 +190,7 @@ public class DashboardController extends BaseController { | @@ -176,6 +190,7 @@ public class DashboardController extends BaseController { | ||
176 | customerId, | 190 | customerId, |
177 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, strCustomerId, customer.getName()); | 191 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, strCustomerId, customer.getName()); |
178 | 192 | ||
193 | + sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); | ||
179 | 194 | ||
180 | return savedDashboard; | 195 | return savedDashboard; |
181 | } catch (Exception e) { | 196 | } catch (Exception e) { |
@@ -207,6 +222,8 @@ public class DashboardController extends BaseController { | @@ -207,6 +222,8 @@ public class DashboardController extends BaseController { | ||
207 | customerId, | 222 | customerId, |
208 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customer.getId().toString(), customer.getName()); | 223 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customer.getId().toString(), customer.getName()); |
209 | 224 | ||
225 | + sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); | ||
226 | + | ||
210 | return savedDashboard; | 227 | return savedDashboard; |
211 | } catch (Exception e) { | 228 | } catch (Exception e) { |
212 | 229 | ||
@@ -262,6 +279,7 @@ public class DashboardController extends BaseController { | @@ -262,6 +279,7 @@ public class DashboardController extends BaseController { | ||
262 | logEntityAction(dashboardId, savedDashboard, | 279 | logEntityAction(dashboardId, savedDashboard, |
263 | customerId, | 280 | customerId, |
264 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); | 281 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); |
282 | + sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); | ||
265 | } | 283 | } |
266 | for (CustomerId customerId : removedCustomerIds) { | 284 | for (CustomerId customerId : removedCustomerIds) { |
267 | ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); | 285 | ShortCustomerInfo customerInfo = dashboard.getAssignedCustomerInfo(customerId); |
@@ -269,7 +287,7 @@ public class DashboardController extends BaseController { | @@ -269,7 +287,7 @@ public class DashboardController extends BaseController { | ||
269 | logEntityAction(dashboardId, dashboard, | 287 | logEntityAction(dashboardId, dashboard, |
270 | customerId, | 288 | customerId, |
271 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); | 289 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); |
272 | - | 290 | + sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); |
273 | } | 291 | } |
274 | return savedDashboard; | 292 | return savedDashboard; |
275 | } | 293 | } |
@@ -313,6 +331,7 @@ public class DashboardController extends BaseController { | @@ -313,6 +331,7 @@ public class DashboardController extends BaseController { | ||
313 | logEntityAction(dashboardId, savedDashboard, | 331 | logEntityAction(dashboardId, savedDashboard, |
314 | customerId, | 332 | customerId, |
315 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); | 333 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); |
334 | + sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); | ||
316 | } | 335 | } |
317 | return savedDashboard; | 336 | return savedDashboard; |
318 | } | 337 | } |
@@ -356,7 +375,7 @@ public class DashboardController extends BaseController { | @@ -356,7 +375,7 @@ public class DashboardController extends BaseController { | ||
356 | logEntityAction(dashboardId, dashboard, | 375 | logEntityAction(dashboardId, dashboard, |
357 | customerId, | 376 | customerId, |
358 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); | 377 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDashboardId, customerId.toString(), customerInfo.getTitle()); |
359 | - | 378 | + sendEntityAssignToCustomerNotificationMsg(savedDashboard.getTenantId(), savedDashboard.getId(), customerId, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); |
360 | } | 379 | } |
361 | return savedDashboard; | 380 | return savedDashboard; |
362 | } | 381 | } |
@@ -578,4 +597,106 @@ public class DashboardController extends BaseController { | @@ -578,4 +597,106 @@ public class DashboardController extends BaseController { | ||
578 | } catch (Exception e) {} | 597 | } catch (Exception e) {} |
579 | return null; | 598 | return null; |
580 | } | 599 | } |
600 | + | ||
601 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
602 | + @RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.POST) | ||
603 | + @ResponseBody | ||
604 | + public Dashboard assignDashboardToEdge(@PathVariable("edgeId") String strEdgeId, | ||
605 | + @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | ||
606 | + checkParameter("edgeId", strEdgeId); | ||
607 | + checkParameter(DASHBOARD_ID, strDashboardId); | ||
608 | + try { | ||
609 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
610 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
611 | + | ||
612 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | ||
613 | + checkDashboardId(dashboardId, Operation.ASSIGN_TO_EDGE); | ||
614 | + | ||
615 | + Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToEdge(getCurrentUser().getTenantId(), dashboardId, edgeId)); | ||
616 | + | ||
617 | + logEntityAction(dashboardId, savedDashboard, | ||
618 | + null, | ||
619 | + ActionType.ASSIGNED_TO_EDGE, null, strDashboardId, strEdgeId, edge.getName()); | ||
620 | + | ||
621 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDashboard.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); | ||
622 | + | ||
623 | + return savedDashboard; | ||
624 | + } catch (Exception e) { | ||
625 | + | ||
626 | + logEntityAction(emptyId(EntityType.DASHBOARD), null, | ||
627 | + null, | ||
628 | + ActionType.ASSIGNED_TO_EDGE, e, strDashboardId, strEdgeId); | ||
629 | + | ||
630 | + throw handleException(e); | ||
631 | + } | ||
632 | + } | ||
633 | + | ||
634 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
635 | + @RequestMapping(value = "/edge/{edgeId}/dashboard/{dashboardId}", method = RequestMethod.DELETE) | ||
636 | + @ResponseBody | ||
637 | + public Dashboard unassignDashboardFromEdge(@PathVariable("edgeId") String strEdgeId, | ||
638 | + @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | ||
639 | + checkParameter("edgeId", strEdgeId); | ||
640 | + checkParameter(DASHBOARD_ID, strDashboardId); | ||
641 | + try { | ||
642 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
643 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
644 | + DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); | ||
645 | + Dashboard dashboard = checkDashboardId(dashboardId, Operation.UNASSIGN_FROM_EDGE); | ||
646 | + | ||
647 | + Dashboard savedDashboard = checkNotNull(dashboardService.unassignDashboardFromEdge(getCurrentUser().getTenantId(), dashboardId, edgeId)); | ||
648 | + | ||
649 | + logEntityAction(dashboardId, dashboard, | ||
650 | + null, | ||
651 | + ActionType.UNASSIGNED_FROM_EDGE, null, strDashboardId, strEdgeId, edge.getName()); | ||
652 | + | ||
653 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDashboard.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE); | ||
654 | + | ||
655 | + return savedDashboard; | ||
656 | + } catch (Exception e) { | ||
657 | + | ||
658 | + logEntityAction(emptyId(EntityType.DASHBOARD), null, | ||
659 | + null, | ||
660 | + ActionType.UNASSIGNED_FROM_EDGE, e, strDashboardId, strEdgeId); | ||
661 | + | ||
662 | + throw handleException(e); | ||
663 | + } | ||
664 | + } | ||
665 | + | ||
666 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
667 | + @RequestMapping(value = "/edge/{edgeId}/dashboards", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
668 | + @ResponseBody | ||
669 | + public PageData<DashboardInfo> getEdgeDashboards( | ||
670 | + @PathVariable("edgeId") String strEdgeId, | ||
671 | + @RequestParam int pageSize, | ||
672 | + @RequestParam int page, | ||
673 | + @RequestParam(required = false) String textSearch, | ||
674 | + @RequestParam(required = false) String sortProperty, | ||
675 | + @RequestParam(required = false) String sortOrder, | ||
676 | + @RequestParam(required = false) Long startTime, | ||
677 | + @RequestParam(required = false) Long endTime) throws ThingsboardException { | ||
678 | + checkParameter("edgeId", strEdgeId); | ||
679 | + try { | ||
680 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
681 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
682 | + checkEdgeId(edgeId, Operation.READ); | ||
683 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | ||
684 | + PageData<DashboardInfo> nonFilteredResult = dashboardService.findDashboardsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); | ||
685 | + List<DashboardInfo> filteredDashboards = nonFilteredResult.getData().stream().filter(dashboardInfo -> { | ||
686 | + try { | ||
687 | + accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, Operation.READ, dashboardInfo.getId(), dashboardInfo); | ||
688 | + return true; | ||
689 | + } catch (ThingsboardException e) { | ||
690 | + return false; | ||
691 | + } | ||
692 | + }).collect(Collectors.toList()); | ||
693 | + PageData<DashboardInfo> filteredResult = new PageData<>(filteredDashboards, | ||
694 | + nonFilteredResult.getTotalPages(), | ||
695 | + nonFilteredResult.getTotalElements(), | ||
696 | + nonFilteredResult.hasNext()); | ||
697 | + return checkNotNull(filteredResult); | ||
698 | + } catch (Exception e) { | ||
699 | + throw handleException(e); | ||
700 | + } | ||
701 | + } | ||
581 | } | 702 | } |
@@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; | @@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; | ||
32 | import org.springframework.web.bind.annotation.RestController; | 32 | import org.springframework.web.bind.annotation.RestController; |
33 | import org.springframework.web.context.request.async.DeferredResult; | 33 | import org.springframework.web.context.request.async.DeferredResult; |
34 | import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; | 34 | import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; |
35 | +import org.thingsboard.rule.engine.api.msg.DeviceEdgeUpdateMsg; | ||
35 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | 36 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
36 | import org.thingsboard.server.common.data.ClaimRequest; | 37 | import org.thingsboard.server.common.data.ClaimRequest; |
37 | import org.thingsboard.server.common.data.Customer; | 38 | import org.thingsboard.server.common.data.Customer; |
@@ -43,14 +44,18 @@ import org.thingsboard.server.common.data.EntityType; | @@ -43,14 +44,18 @@ import org.thingsboard.server.common.data.EntityType; | ||
43 | import org.thingsboard.server.common.data.Tenant; | 44 | import org.thingsboard.server.common.data.Tenant; |
44 | import org.thingsboard.server.common.data.audit.ActionType; | 45 | import org.thingsboard.server.common.data.audit.ActionType; |
45 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; | 46 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
47 | +import org.thingsboard.server.common.data.edge.Edge; | ||
48 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
46 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 49 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
47 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 50 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
48 | import org.thingsboard.server.common.data.id.CustomerId; | 51 | import org.thingsboard.server.common.data.id.CustomerId; |
49 | import org.thingsboard.server.common.data.id.DeviceId; | 52 | import org.thingsboard.server.common.data.id.DeviceId; |
50 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 53 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
54 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
51 | import org.thingsboard.server.common.data.id.TenantId; | 55 | import org.thingsboard.server.common.data.id.TenantId; |
52 | import org.thingsboard.server.common.data.page.PageData; | 56 | import org.thingsboard.server.common.data.page.PageData; |
53 | import org.thingsboard.server.common.data.page.PageLink; | 57 | import org.thingsboard.server.common.data.page.PageLink; |
58 | +import org.thingsboard.server.common.data.page.TimePageLink; | ||
54 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | 59 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
55 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 60 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
56 | import org.thingsboard.server.common.msg.TbMsg; | 61 | import org.thingsboard.server.common.msg.TbMsg; |
@@ -72,6 +77,8 @@ import java.util.ArrayList; | @@ -72,6 +77,8 @@ import java.util.ArrayList; | ||
72 | import java.util.List; | 77 | import java.util.List; |
73 | import java.util.stream.Collectors; | 78 | import java.util.stream.Collectors; |
74 | 79 | ||
80 | +import static org.thingsboard.server.controller.EdgeController.EDGE_ID; | ||
81 | + | ||
75 | @RestController | 82 | @RestController |
76 | @TbCoreComponent | 83 | @TbCoreComponent |
77 | @RequestMapping("/api") | 84 | @RequestMapping("/api") |
@@ -125,6 +132,10 @@ public class DeviceController extends BaseController { | @@ -125,6 +132,10 @@ public class DeviceController extends BaseController { | ||
125 | tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), | 132 | tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(), |
126 | device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | 133 | device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
127 | 134 | ||
135 | + if (device.getId() != null) { | ||
136 | + sendEntityNotificationMsg(savedDevice.getTenantId(), savedDevice.getId(), EdgeEventActionType.UPDATED); | ||
137 | + } | ||
138 | + | ||
128 | logEntityAction(savedDevice.getId(), savedDevice, | 139 | logEntityAction(savedDevice.getId(), savedDevice, |
129 | savedDevice.getCustomerId(), | 140 | savedDevice.getCustomerId(), |
130 | device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | 141 | device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
@@ -150,6 +161,9 @@ public class DeviceController extends BaseController { | @@ -150,6 +161,9 @@ public class DeviceController extends BaseController { | ||
150 | try { | 161 | try { |
151 | DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | 162 | DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); |
152 | Device device = checkDeviceId(deviceId, Operation.DELETE); | 163 | Device device = checkDeviceId(deviceId, Operation.DELETE); |
164 | + | ||
165 | + List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(getTenantId(), deviceId); | ||
166 | + | ||
153 | deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId); | 167 | deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId); |
154 | 168 | ||
155 | tbClusterService.onDeviceDeleted(device, null); | 169 | tbClusterService.onDeviceDeleted(device, null); |
@@ -159,6 +173,8 @@ public class DeviceController extends BaseController { | @@ -159,6 +173,8 @@ public class DeviceController extends BaseController { | ||
159 | device.getCustomerId(), | 173 | device.getCustomerId(), |
160 | ActionType.DELETED, null, strDeviceId); | 174 | ActionType.DELETED, null, strDeviceId); |
161 | 175 | ||
176 | + sendDeleteNotificationMsg(getTenantId(), deviceId, relatedEdgeIds); | ||
177 | + | ||
162 | deviceStateService.onDeviceDeleted(device); | 178 | deviceStateService.onDeviceDeleted(device); |
163 | } catch (Exception e) { | 179 | } catch (Exception e) { |
164 | logEntityAction(emptyId(EntityType.DEVICE), | 180 | logEntityAction(emptyId(EntityType.DEVICE), |
@@ -189,6 +205,9 @@ public class DeviceController extends BaseController { | @@ -189,6 +205,9 @@ public class DeviceController extends BaseController { | ||
189 | savedDevice.getCustomerId(), | 205 | savedDevice.getCustomerId(), |
190 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDeviceId, strCustomerId, customer.getName()); | 206 | ActionType.ASSIGNED_TO_CUSTOMER, null, strDeviceId, strCustomerId, customer.getName()); |
191 | 207 | ||
208 | + sendEntityAssignToCustomerNotificationMsg(savedDevice.getTenantId(), savedDevice.getId(), | ||
209 | + customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); | ||
210 | + | ||
192 | return savedDevice; | 211 | return savedDevice; |
193 | } catch (Exception e) { | 212 | } catch (Exception e) { |
194 | logEntityAction(emptyId(EntityType.DEVICE), null, | 213 | logEntityAction(emptyId(EntityType.DEVICE), null, |
@@ -217,6 +236,9 @@ public class DeviceController extends BaseController { | @@ -217,6 +236,9 @@ public class DeviceController extends BaseController { | ||
217 | device.getCustomerId(), | 236 | device.getCustomerId(), |
218 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDeviceId, customer.getId().toString(), customer.getName()); | 237 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDeviceId, customer.getId().toString(), customer.getName()); |
219 | 238 | ||
239 | + sendEntityAssignToCustomerNotificationMsg(savedDevice.getTenantId(), savedDevice.getId(), | ||
240 | + customer.getId(), EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); | ||
241 | + | ||
220 | return savedDevice; | 242 | return savedDevice; |
221 | } catch (Exception e) { | 243 | } catch (Exception e) { |
222 | logEntityAction(emptyId(EntityType.DEVICE), null, | 244 | logEntityAction(emptyId(EntityType.DEVICE), null, |
@@ -280,6 +302,9 @@ public class DeviceController extends BaseController { | @@ -280,6 +302,9 @@ public class DeviceController extends BaseController { | ||
280 | Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS); | 302 | Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS); |
281 | DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials)); | 303 | DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials)); |
282 | tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null); | 304 | tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null); |
305 | + | ||
306 | + sendEntityNotificationMsg(getTenantId(), device.getId(), EdgeEventActionType.CREDENTIALS_UPDATED); | ||
307 | + | ||
283 | logEntityAction(device.getId(), device, | 308 | logEntityAction(device.getId(), device, |
284 | device.getCustomerId(), | 309 | device.getCustomerId(), |
285 | ActionType.CREDENTIALS_UPDATED, null, deviceCredentials); | 310 | ActionType.CREDENTIALS_UPDATED, null, deviceCredentials); |
@@ -631,4 +656,115 @@ public class DeviceController extends BaseController { | @@ -631,4 +656,115 @@ public class DeviceController extends BaseController { | ||
631 | metaData.putValue("assignedFromTenantName", tenant.getName()); | 656 | metaData.putValue("assignedFromTenantName", tenant.getName()); |
632 | return metaData; | 657 | return metaData; |
633 | } | 658 | } |
659 | + | ||
660 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
661 | + @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST) | ||
662 | + @ResponseBody | ||
663 | + public Device assignDeviceToEdge(@PathVariable(EDGE_ID) String strEdgeId, | ||
664 | + @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { | ||
665 | + checkParameter(EDGE_ID, strEdgeId); | ||
666 | + checkParameter(DEVICE_ID, strDeviceId); | ||
667 | + try { | ||
668 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
669 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
670 | + | ||
671 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | ||
672 | + checkDeviceId(deviceId, Operation.ASSIGN_TO_EDGE); | ||
673 | + | ||
674 | + Device savedDevice = checkNotNull(deviceService.assignDeviceToEdge(getCurrentUser().getTenantId(), deviceId, edgeId)); | ||
675 | + | ||
676 | + tbClusterService.pushMsgToCore(new DeviceEdgeUpdateMsg(savedDevice.getTenantId(), | ||
677 | + savedDevice.getId(), edgeId), null); | ||
678 | + | ||
679 | + logEntityAction(deviceId, savedDevice, | ||
680 | + savedDevice.getCustomerId(), | ||
681 | + ActionType.ASSIGNED_TO_EDGE, null, strDeviceId, strEdgeId, edge.getName()); | ||
682 | + | ||
683 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDevice.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); | ||
684 | + | ||
685 | + return savedDevice; | ||
686 | + } catch (Exception e) { | ||
687 | + logEntityAction(emptyId(EntityType.DEVICE), null, | ||
688 | + null, | ||
689 | + ActionType.ASSIGNED_TO_EDGE, e, strDeviceId, strEdgeId); | ||
690 | + throw handleException(e); | ||
691 | + } | ||
692 | + } | ||
693 | + | ||
694 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
695 | + @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE) | ||
696 | + @ResponseBody | ||
697 | + public Device unassignDeviceFromEdge(@PathVariable(EDGE_ID) String strEdgeId, | ||
698 | + @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { | ||
699 | + checkParameter(EDGE_ID, strEdgeId); | ||
700 | + checkParameter(DEVICE_ID, strDeviceId); | ||
701 | + try { | ||
702 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
703 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
704 | + | ||
705 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | ||
706 | + Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_EDGE); | ||
707 | + | ||
708 | + Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId, edgeId)); | ||
709 | + | ||
710 | + tbClusterService.pushMsgToCore(new DeviceEdgeUpdateMsg(savedDevice.getTenantId(), | ||
711 | + savedDevice.getId(), null), null); | ||
712 | + | ||
713 | + logEntityAction(deviceId, device, | ||
714 | + device.getCustomerId(), | ||
715 | + ActionType.UNASSIGNED_FROM_EDGE, null, strDeviceId, strEdgeId, edge.getName()); | ||
716 | + | ||
717 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDevice.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE); | ||
718 | + | ||
719 | + return savedDevice; | ||
720 | + } catch (Exception e) { | ||
721 | + logEntityAction(emptyId(EntityType.DEVICE), null, | ||
722 | + null, | ||
723 | + ActionType.UNASSIGNED_FROM_EDGE, e, strDeviceId, strEdgeId); | ||
724 | + throw handleException(e); | ||
725 | + } | ||
726 | + } | ||
727 | + | ||
728 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
729 | + @RequestMapping(value = "/edge/{edgeId}/devices", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
730 | + @ResponseBody | ||
731 | + public PageData<Device> getEdgeDevices( | ||
732 | + @PathVariable(EDGE_ID) String strEdgeId, | ||
733 | + @RequestParam int pageSize, | ||
734 | + @RequestParam int page, | ||
735 | + @RequestParam(required = false) String type, | ||
736 | + @RequestParam(required = false) String textSearch, | ||
737 | + @RequestParam(required = false) String sortProperty, | ||
738 | + @RequestParam(required = false) String sortOrder, | ||
739 | + @RequestParam(required = false) Long startTime, | ||
740 | + @RequestParam(required = false) Long endTime) throws ThingsboardException { | ||
741 | + checkParameter(EDGE_ID, strEdgeId); | ||
742 | + try { | ||
743 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
744 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
745 | + checkEdgeId(edgeId, Operation.READ); | ||
746 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | ||
747 | + PageData<Device> nonFilteredResult; | ||
748 | + if (type != null && type.trim().length() > 0) { | ||
749 | + nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink); | ||
750 | + } else { | ||
751 | + nonFilteredResult = deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink); | ||
752 | + } | ||
753 | + List<Device> filteredDevices = nonFilteredResult.getData().stream().filter(device -> { | ||
754 | + try { | ||
755 | + accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, Operation.READ, device.getId(), device); | ||
756 | + return true; | ||
757 | + } catch (ThingsboardException e) { | ||
758 | + return false; | ||
759 | + } | ||
760 | + }).collect(Collectors.toList()); | ||
761 | + PageData<Device> filteredResult = new PageData<>(filteredDevices, | ||
762 | + nonFilteredResult.getTotalPages(), | ||
763 | + nonFilteredResult.getTotalElements(), | ||
764 | + nonFilteredResult.hasNext()); | ||
765 | + return checkNotNull(filteredResult); | ||
766 | + } catch (Exception e) { | ||
767 | + throw handleException(e); | ||
768 | + } | ||
769 | + } | ||
634 | } | 770 | } |
@@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.DeviceProfile; | @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.DeviceProfile; | ||
32 | import org.thingsboard.server.common.data.DeviceProfileInfo; | 32 | import org.thingsboard.server.common.data.DeviceProfileInfo; |
33 | import org.thingsboard.server.common.data.EntityType; | 33 | import org.thingsboard.server.common.data.EntityType; |
34 | import org.thingsboard.server.common.data.audit.ActionType; | 34 | import org.thingsboard.server.common.data.audit.ActionType; |
35 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
35 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 36 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
36 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 37 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
37 | import org.thingsboard.server.common.data.page.PageData; | 38 | import org.thingsboard.server.common.data.page.PageData; |
@@ -153,6 +154,9 @@ public class DeviceProfileController extends BaseController { | @@ -153,6 +154,9 @@ public class DeviceProfileController extends BaseController { | ||
153 | null, | 154 | null, |
154 | created ? ActionType.ADDED : ActionType.UPDATED, null); | 155 | created ? ActionType.ADDED : ActionType.UPDATED, null); |
155 | 156 | ||
157 | + sendEntityNotificationMsg(getTenantId(), savedDeviceProfile.getId(), | ||
158 | + deviceProfile.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); | ||
159 | + | ||
156 | return savedDeviceProfile; | 160 | return savedDeviceProfile; |
157 | } catch (Exception e) { | 161 | } catch (Exception e) { |
158 | logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile, | 162 | logEntityAction(emptyId(EntityType.DEVICE_PROFILE), deviceProfile, |
@@ -178,6 +182,7 @@ public class DeviceProfileController extends BaseController { | @@ -178,6 +182,7 @@ public class DeviceProfileController extends BaseController { | ||
178 | null, | 182 | null, |
179 | ActionType.DELETED, null, strDeviceProfileId); | 183 | ActionType.DELETED, null, strDeviceProfileId); |
180 | 184 | ||
185 | + sendEntityNotificationMsg(getTenantId(), deviceProfile.getId(), EdgeEventActionType.DELETED); | ||
181 | } catch (Exception e) { | 186 | } catch (Exception e) { |
182 | logEntityAction(emptyId(EntityType.DEVICE_PROFILE), | 187 | logEntityAction(emptyId(EntityType.DEVICE_PROFILE), |
183 | null, | 188 | null, |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.controller; | ||
17 | + | ||
18 | +import com.google.common.util.concurrent.ListenableFuture; | ||
19 | +import org.springframework.http.HttpStatus; | ||
20 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
21 | +import org.springframework.web.bind.annotation.PathVariable; | ||
22 | +import org.springframework.web.bind.annotation.RequestBody; | ||
23 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
24 | +import org.springframework.web.bind.annotation.RequestMethod; | ||
25 | +import org.springframework.web.bind.annotation.RequestParam; | ||
26 | +import org.springframework.web.bind.annotation.ResponseBody; | ||
27 | +import org.springframework.web.bind.annotation.ResponseStatus; | ||
28 | +import org.springframework.web.bind.annotation.RestController; | ||
29 | +import org.thingsboard.server.common.data.Customer; | ||
30 | +import org.thingsboard.server.common.data.EntitySubtype; | ||
31 | +import org.thingsboard.server.common.data.EntityType; | ||
32 | +import org.thingsboard.server.common.data.audit.ActionType; | ||
33 | +import org.thingsboard.server.common.data.edge.Edge; | ||
34 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
35 | +import org.thingsboard.server.common.data.edge.EdgeInfo; | ||
36 | +import org.thingsboard.server.common.data.edge.EdgeSearchQuery; | ||
37 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | ||
38 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | ||
39 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
40 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
41 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
42 | +import org.thingsboard.server.common.data.id.TenantId; | ||
43 | +import org.thingsboard.server.common.data.page.PageData; | ||
44 | +import org.thingsboard.server.common.data.page.PageLink; | ||
45 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | ||
46 | +import org.thingsboard.server.common.data.rule.RuleChain; | ||
47 | +import org.thingsboard.server.common.data.security.Authority; | ||
48 | +import org.thingsboard.server.dao.exception.DataValidationException; | ||
49 | +import org.thingsboard.server.dao.exception.IncorrectParameterException; | ||
50 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
51 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
52 | +import org.thingsboard.server.service.edge.rpc.EdgeGrpcSession; | ||
53 | +import org.thingsboard.server.service.security.model.SecurityUser; | ||
54 | +import org.thingsboard.server.service.security.permission.Operation; | ||
55 | +import org.thingsboard.server.service.security.permission.Resource; | ||
56 | + | ||
57 | +import java.util.ArrayList; | ||
58 | +import java.util.List; | ||
59 | +import java.util.stream.Collectors; | ||
60 | + | ||
61 | +@RestController | ||
62 | +@TbCoreComponent | ||
63 | +@RequestMapping("/api") | ||
64 | +public class EdgeController extends BaseController { | ||
65 | + | ||
66 | + public static final String EDGE_ID = "edgeId"; | ||
67 | + | ||
68 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | ||
69 | + @RequestMapping(value = "/edges/enabled", method = RequestMethod.GET) | ||
70 | + @ResponseBody | ||
71 | + public boolean isEdgesSupportEnabled() { | ||
72 | + return edgesEnabled; | ||
73 | + } | ||
74 | + | ||
75 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
76 | + @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.GET) | ||
77 | + @ResponseBody | ||
78 | + public Edge getEdgeById(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { | ||
79 | + checkParameter(EDGE_ID, strEdgeId); | ||
80 | + try { | ||
81 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
82 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
83 | + if (Authority.CUSTOMER_USER.equals(getCurrentUser().getAuthority())) { | ||
84 | + cleanUpSensitiveData(edge); | ||
85 | + } | ||
86 | + return edge; | ||
87 | + } catch (Exception e) { | ||
88 | + throw handleException(e); | ||
89 | + } | ||
90 | + } | ||
91 | + | ||
92 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
93 | + @RequestMapping(value = "/edge/info/{edgeId}", method = RequestMethod.GET) | ||
94 | + @ResponseBody | ||
95 | + public EdgeInfo getEdgeInfoById(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { | ||
96 | + checkParameter(EDGE_ID, strEdgeId); | ||
97 | + try { | ||
98 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
99 | + EdgeInfo edgeInfo = checkEdgeInfoId(edgeId, Operation.READ); | ||
100 | + if (Authority.CUSTOMER_USER.equals(getCurrentUser().getAuthority())) { | ||
101 | + cleanUpSensitiveData(edgeInfo); | ||
102 | + } | ||
103 | + return edgeInfo; | ||
104 | + } catch (Exception e) { | ||
105 | + throw handleException(e); | ||
106 | + } | ||
107 | + } | ||
108 | + | ||
109 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
110 | + @RequestMapping(value = "/edge", method = RequestMethod.POST) | ||
111 | + @ResponseBody | ||
112 | + public Edge saveEdge(@RequestBody Edge edge) throws ThingsboardException { | ||
113 | + try { | ||
114 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
115 | + edge.setTenantId(tenantId); | ||
116 | + boolean created = edge.getId() == null; | ||
117 | + | ||
118 | + RuleChain edgeTemplateRootRuleChain = null; | ||
119 | + if (created) { | ||
120 | + edgeTemplateRootRuleChain = ruleChainService.getEdgeTemplateRootRuleChain(tenantId); | ||
121 | + if (edgeTemplateRootRuleChain == null) { | ||
122 | + throw new DataValidationException("Root edge rule chain is not available!"); | ||
123 | + } | ||
124 | + } | ||
125 | + | ||
126 | + Operation operation = created ? Operation.CREATE : Operation.WRITE; | ||
127 | + | ||
128 | + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, | ||
129 | + edge.getId(), edge); | ||
130 | + | ||
131 | + Edge savedEdge = checkNotNull(edgeService.saveEdge(edge)); | ||
132 | + | ||
133 | + if (created) { | ||
134 | + ruleChainService.assignRuleChainToEdge(tenantId, edgeTemplateRootRuleChain.getId(), savedEdge.getId()); | ||
135 | + edgeNotificationService.setEdgeRootRuleChain(tenantId, savedEdge, edgeTemplateRootRuleChain.getId()); | ||
136 | + edgeService.assignDefaultRuleChainsToEdge(tenantId, savedEdge.getId()); | ||
137 | + } | ||
138 | + | ||
139 | + tbClusterService.onEntityStateChange(savedEdge.getTenantId(), savedEdge.getId(), | ||
140 | + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | ||
141 | + | ||
142 | + logEntityAction(savedEdge.getId(), savedEdge, null, created ? ActionType.ADDED : ActionType.UPDATED, null); | ||
143 | + return savedEdge; | ||
144 | + } catch (Exception e) { | ||
145 | + logEntityAction(emptyId(EntityType.EDGE), edge, | ||
146 | + null, edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); | ||
147 | + throw handleException(e); | ||
148 | + } | ||
149 | + } | ||
150 | + | ||
151 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
152 | + @RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE) | ||
153 | + @ResponseStatus(value = HttpStatus.OK) | ||
154 | + public void deleteEdge(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { | ||
155 | + checkParameter(EDGE_ID, strEdgeId); | ||
156 | + try { | ||
157 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
158 | + Edge edge = checkEdgeId(edgeId, Operation.DELETE); | ||
159 | + edgeService.deleteEdge(getTenantId(), edgeId); | ||
160 | + | ||
161 | + tbClusterService.onEntityStateChange(getTenantId(), edgeId, | ||
162 | + ComponentLifecycleEvent.DELETED); | ||
163 | + | ||
164 | + logEntityAction(edgeId, edge, | ||
165 | + null, | ||
166 | + ActionType.DELETED, null, strEdgeId); | ||
167 | + | ||
168 | + } catch (Exception e) { | ||
169 | + | ||
170 | + logEntityAction(emptyId(EntityType.EDGE), | ||
171 | + null, | ||
172 | + null, | ||
173 | + ActionType.DELETED, e, strEdgeId); | ||
174 | + | ||
175 | + throw handleException(e); | ||
176 | + } | ||
177 | + } | ||
178 | + | ||
179 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
180 | + @RequestMapping(value = "/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
181 | + @ResponseBody | ||
182 | + public PageData<Edge> getEdges(@RequestParam int pageSize, | ||
183 | + @RequestParam int page, | ||
184 | + @RequestParam(required = false) String textSearch, | ||
185 | + @RequestParam(required = false) String sortProperty, | ||
186 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
187 | + try { | ||
188 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
189 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
190 | + return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink)); | ||
191 | + } catch (Exception e) { | ||
192 | + throw handleException(e); | ||
193 | + } | ||
194 | + } | ||
195 | + | ||
196 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
197 | + @RequestMapping(value = "/customer/{customerId}/edge/{edgeId}", method = RequestMethod.POST) | ||
198 | + @ResponseBody | ||
199 | + public Edge assignEdgeToCustomer(@PathVariable("customerId") String strCustomerId, | ||
200 | + @PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { | ||
201 | + checkParameter("customerId", strCustomerId); | ||
202 | + checkParameter(EDGE_ID, strEdgeId); | ||
203 | + try { | ||
204 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | ||
205 | + Customer customer = checkCustomerId(customerId, Operation.READ); | ||
206 | + | ||
207 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
208 | + checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER); | ||
209 | + | ||
210 | + Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId)); | ||
211 | + | ||
212 | + tbClusterService.onEntityStateChange(getTenantId(), edgeId, | ||
213 | + ComponentLifecycleEvent.UPDATED); | ||
214 | + | ||
215 | + logEntityAction(edgeId, savedEdge, | ||
216 | + savedEdge.getCustomerId(), | ||
217 | + ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, strCustomerId, customer.getName()); | ||
218 | + | ||
219 | + sendEntityAssignToCustomerNotificationMsg(savedEdge.getTenantId(), savedEdge.getId(), | ||
220 | + customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); | ||
221 | + | ||
222 | + return savedEdge; | ||
223 | + } catch (Exception e) { | ||
224 | + logEntityAction(emptyId(EntityType.EDGE), null, | ||
225 | + null, | ||
226 | + ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId, strCustomerId); | ||
227 | + throw handleException(e); | ||
228 | + } | ||
229 | + } | ||
230 | + | ||
231 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
232 | + @RequestMapping(value = "/customer/edge/{edgeId}", method = RequestMethod.DELETE) | ||
233 | + @ResponseBody | ||
234 | + public Edge unassignEdgeFromCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { | ||
235 | + checkParameter(EDGE_ID, strEdgeId); | ||
236 | + try { | ||
237 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
238 | + Edge edge = checkEdgeId(edgeId, Operation.UNASSIGN_FROM_CUSTOMER); | ||
239 | + if (edge.getCustomerId() == null || edge.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) { | ||
240 | + throw new IncorrectParameterException("Edge isn't assigned to any customer!"); | ||
241 | + } | ||
242 | + Customer customer = checkCustomerId(edge.getCustomerId(), Operation.READ); | ||
243 | + | ||
244 | + Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId)); | ||
245 | + | ||
246 | + tbClusterService.onEntityStateChange(getTenantId(), edgeId, | ||
247 | + ComponentLifecycleEvent.UPDATED); | ||
248 | + | ||
249 | + logEntityAction(edgeId, edge, | ||
250 | + edge.getCustomerId(), | ||
251 | + ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEdgeId, customer.getId().toString(), customer.getName()); | ||
252 | + | ||
253 | + sendEntityAssignToCustomerNotificationMsg(savedEdge.getTenantId(), savedEdge.getId(), | ||
254 | + customer.getId(), EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); | ||
255 | + | ||
256 | + return savedEdge; | ||
257 | + } catch (Exception e) { | ||
258 | + logEntityAction(emptyId(EntityType.EDGE), null, | ||
259 | + null, | ||
260 | + ActionType.UNASSIGNED_FROM_CUSTOMER, e, strEdgeId); | ||
261 | + throw handleException(e); | ||
262 | + } | ||
263 | + } | ||
264 | + | ||
265 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
266 | + @RequestMapping(value = "/customer/public/edge/{edgeId}", method = RequestMethod.POST) | ||
267 | + @ResponseBody | ||
268 | + public Edge assignEdgeToPublicCustomer(@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException { | ||
269 | + checkParameter(EDGE_ID, strEdgeId); | ||
270 | + try { | ||
271 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
272 | + Edge edge = checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER); | ||
273 | + Customer publicCustomer = customerService.findOrCreatePublicCustomer(edge.getTenantId()); | ||
274 | + Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, publicCustomer.getId())); | ||
275 | + | ||
276 | + tbClusterService.onEntityStateChange(getTenantId(), edgeId, | ||
277 | + ComponentLifecycleEvent.UPDATED); | ||
278 | + | ||
279 | + logEntityAction(edgeId, savedEdge, | ||
280 | + savedEdge.getCustomerId(), | ||
281 | + ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, publicCustomer.getId().toString(), publicCustomer.getName()); | ||
282 | + | ||
283 | + return savedEdge; | ||
284 | + } catch (Exception e) { | ||
285 | + logEntityAction(emptyId(EntityType.EDGE), null, | ||
286 | + null, | ||
287 | + ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId); | ||
288 | + throw handleException(e); | ||
289 | + } | ||
290 | + } | ||
291 | + | ||
292 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
293 | + @RequestMapping(value = "/tenant/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
294 | + @ResponseBody | ||
295 | + public PageData<Edge> getTenantEdges( | ||
296 | + @RequestParam int pageSize, | ||
297 | + @RequestParam int page, | ||
298 | + @RequestParam(required = false) String type, | ||
299 | + @RequestParam(required = false) String textSearch, | ||
300 | + @RequestParam(required = false) String sortProperty, | ||
301 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
302 | + try { | ||
303 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
304 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
305 | + if (type != null && type.trim().length() > 0) { | ||
306 | + return checkNotNull(edgeService.findEdgesByTenantIdAndType(tenantId, type, pageLink)); | ||
307 | + } else { | ||
308 | + return checkNotNull(edgeService.findEdgesByTenantId(tenantId, pageLink)); | ||
309 | + } | ||
310 | + } catch (Exception e) { | ||
311 | + throw handleException(e); | ||
312 | + } | ||
313 | + } | ||
314 | + | ||
315 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
316 | + @RequestMapping(value = "/tenant/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
317 | + @ResponseBody | ||
318 | + public PageData<EdgeInfo> getTenantEdgeInfos( | ||
319 | + @RequestParam int pageSize, | ||
320 | + @RequestParam int page, | ||
321 | + @RequestParam(required = false) String type, | ||
322 | + @RequestParam(required = false) String textSearch, | ||
323 | + @RequestParam(required = false) String sortProperty, | ||
324 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
325 | + try { | ||
326 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
327 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
328 | + if (type != null && type.trim().length() > 0) { | ||
329 | + return checkNotNull(edgeService.findEdgeInfosByTenantIdAndType(tenantId, type, pageLink)); | ||
330 | + } else { | ||
331 | + return checkNotNull(edgeService.findEdgeInfosByTenantId(tenantId, pageLink)); | ||
332 | + } | ||
333 | + } catch (Exception e) { | ||
334 | + throw handleException(e); | ||
335 | + } | ||
336 | + } | ||
337 | + | ||
338 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
339 | + @RequestMapping(value = "/tenant/edges", params = {"edgeName"}, method = RequestMethod.GET) | ||
340 | + @ResponseBody | ||
341 | + public Edge getTenantEdge(@RequestParam String edgeName) throws ThingsboardException { | ||
342 | + try { | ||
343 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
344 | + return checkNotNull(edgeService.findEdgeByTenantIdAndName(tenantId, edgeName)); | ||
345 | + } catch (Exception e) { | ||
346 | + throw handleException(e); | ||
347 | + } | ||
348 | + } | ||
349 | + | ||
350 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
351 | + @RequestMapping(value = "/edge/{edgeId}/{ruleChainId}/root", method = RequestMethod.POST) | ||
352 | + @ResponseBody | ||
353 | + public Edge setRootRuleChain(@PathVariable(EDGE_ID) String strEdgeId, | ||
354 | + @PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException { | ||
355 | + checkParameter(EDGE_ID, strEdgeId); | ||
356 | + checkParameter("ruleChainId", strRuleChainId); | ||
357 | + try { | ||
358 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | ||
359 | + checkRuleChain(ruleChainId, Operation.WRITE); | ||
360 | + | ||
361 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
362 | + Edge edge = checkEdgeId(edgeId, Operation.WRITE); | ||
363 | + accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.WRITE, | ||
364 | + edge.getId(), edge); | ||
365 | + | ||
366 | + Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId); | ||
367 | + | ||
368 | + tbClusterService.onEntityStateChange(updatedEdge.getTenantId(), updatedEdge.getId(), ComponentLifecycleEvent.UPDATED); | ||
369 | + | ||
370 | + logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null); | ||
371 | + | ||
372 | + return updatedEdge; | ||
373 | + } catch (Exception e) { | ||
374 | + logEntityAction(emptyId(EntityType.EDGE), | ||
375 | + null, | ||
376 | + null, | ||
377 | + ActionType.UPDATED, e, strEdgeId); | ||
378 | + throw handleException(e); | ||
379 | + } | ||
380 | + } | ||
381 | + | ||
382 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
383 | + @RequestMapping(value = "/customer/{customerId}/edges", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
384 | + @ResponseBody | ||
385 | + public PageData<Edge> getCustomerEdges( | ||
386 | + @PathVariable("customerId") String strCustomerId, | ||
387 | + @RequestParam int pageSize, | ||
388 | + @RequestParam int page, | ||
389 | + @RequestParam(required = false) String type, | ||
390 | + @RequestParam(required = false) String textSearch, | ||
391 | + @RequestParam(required = false) String sortProperty, | ||
392 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
393 | + checkParameter("customerId", strCustomerId); | ||
394 | + try { | ||
395 | + SecurityUser user = getCurrentUser(); | ||
396 | + TenantId tenantId = user.getTenantId(); | ||
397 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | ||
398 | + checkCustomerId(customerId, Operation.READ); | ||
399 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
400 | + PageData<Edge> result; | ||
401 | + if (type != null && type.trim().length() > 0) { | ||
402 | + result = edgeService.findEdgesByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink); | ||
403 | + } else { | ||
404 | + result = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); | ||
405 | + } | ||
406 | + if (Authority.CUSTOMER_USER.equals(user.getAuthority())) { | ||
407 | + for (Edge edge : result.getData()) { | ||
408 | + cleanUpSensitiveData(edge); | ||
409 | + } | ||
410 | + } | ||
411 | + return checkNotNull(result); | ||
412 | + } catch (Exception e) { | ||
413 | + throw handleException(e); | ||
414 | + } | ||
415 | + } | ||
416 | + | ||
417 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
418 | + @RequestMapping(value = "/customer/{customerId}/edgeInfos", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
419 | + @ResponseBody | ||
420 | + public PageData<EdgeInfo> getCustomerEdgeInfos( | ||
421 | + @PathVariable("customerId") String strCustomerId, | ||
422 | + @RequestParam int pageSize, | ||
423 | + @RequestParam int page, | ||
424 | + @RequestParam(required = false) String type, | ||
425 | + @RequestParam(required = false) String textSearch, | ||
426 | + @RequestParam(required = false) String sortProperty, | ||
427 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
428 | + checkParameter("customerId", strCustomerId); | ||
429 | + try { | ||
430 | + SecurityUser user = getCurrentUser(); | ||
431 | + TenantId tenantId = user.getTenantId(); | ||
432 | + CustomerId customerId = new CustomerId(toUUID(strCustomerId)); | ||
433 | + checkCustomerId(customerId, Operation.READ); | ||
434 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
435 | + PageData<EdgeInfo> result; | ||
436 | + if (type != null && type.trim().length() > 0) { | ||
437 | + result = edgeService.findEdgeInfosByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink); | ||
438 | + } else { | ||
439 | + result = edgeService.findEdgeInfosByTenantIdAndCustomerId(tenantId, customerId, pageLink); | ||
440 | + } | ||
441 | + if (Authority.CUSTOMER_USER.equals(user.getAuthority())) { | ||
442 | + for (Edge edge : result.getData()) { | ||
443 | + cleanUpSensitiveData(edge); | ||
444 | + } | ||
445 | + } | ||
446 | + return checkNotNull(result); | ||
447 | + } catch (Exception e) { | ||
448 | + throw handleException(e); | ||
449 | + } | ||
450 | + } | ||
451 | + | ||
452 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
453 | + @RequestMapping(value = "/edges", params = {"edgeIds"}, method = RequestMethod.GET) | ||
454 | + @ResponseBody | ||
455 | + public List<Edge> getEdgesByIds( | ||
456 | + @RequestParam("edgeIds") String[] strEdgeIds) throws ThingsboardException { | ||
457 | + checkArrayParameter("edgeIds", strEdgeIds); | ||
458 | + try { | ||
459 | + SecurityUser user = getCurrentUser(); | ||
460 | + TenantId tenantId = user.getTenantId(); | ||
461 | + CustomerId customerId = user.getCustomerId(); | ||
462 | + List<EdgeId> edgeIds = new ArrayList<>(); | ||
463 | + for (String strEdgeId : strEdgeIds) { | ||
464 | + edgeIds.add(new EdgeId(toUUID(strEdgeId))); | ||
465 | + } | ||
466 | + ListenableFuture<List<Edge>> edgesFuture; | ||
467 | + if (customerId == null || customerId.isNullUid()) { | ||
468 | + edgesFuture = edgeService.findEdgesByTenantIdAndIdsAsync(tenantId, edgeIds); | ||
469 | + } else { | ||
470 | + edgesFuture = edgeService.findEdgesByTenantIdCustomerIdAndIdsAsync(tenantId, customerId, edgeIds); | ||
471 | + } | ||
472 | + List<Edge> edges = edgesFuture.get(); | ||
473 | + if (Authority.CUSTOMER_USER.equals(user.getAuthority())) { | ||
474 | + for (Edge edge : edges) { | ||
475 | + cleanUpSensitiveData(edge); | ||
476 | + } | ||
477 | + } | ||
478 | + return checkNotNull(edges); | ||
479 | + } catch (Exception e) { | ||
480 | + throw handleException(e); | ||
481 | + } | ||
482 | + } | ||
483 | + | ||
484 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
485 | + @RequestMapping(value = "/edges", method = RequestMethod.POST) | ||
486 | + @ResponseBody | ||
487 | + public List<Edge> findByQuery(@RequestBody EdgeSearchQuery query) throws ThingsboardException { | ||
488 | + checkNotNull(query); | ||
489 | + checkNotNull(query.getParameters()); | ||
490 | + checkNotNull(query.getEdgeTypes()); | ||
491 | + checkEntityId(query.getParameters().getEntityId(), Operation.READ); | ||
492 | + try { | ||
493 | + SecurityUser user = getCurrentUser(); | ||
494 | + TenantId tenantId = user.getTenantId(); | ||
495 | + List<Edge> edges = checkNotNull(edgeService.findEdgesByQuery(tenantId, query).get()); | ||
496 | + edges = edges.stream().filter(edge -> { | ||
497 | + try { | ||
498 | + accessControlService.checkPermission(user, Resource.EDGE, Operation.READ, edge.getId(), edge); | ||
499 | + return true; | ||
500 | + } catch (ThingsboardException e) { | ||
501 | + return false; | ||
502 | + } | ||
503 | + }).collect(Collectors.toList()); | ||
504 | + if (Authority.CUSTOMER_USER.equals(user.getAuthority())) { | ||
505 | + for (Edge edge : edges) { | ||
506 | + cleanUpSensitiveData(edge); | ||
507 | + } | ||
508 | + } | ||
509 | + return edges; | ||
510 | + } catch (Exception e) { | ||
511 | + throw handleException(e); | ||
512 | + } | ||
513 | + } | ||
514 | + | ||
515 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
516 | + @RequestMapping(value = "/edge/types", method = RequestMethod.GET) | ||
517 | + @ResponseBody | ||
518 | + public List<EntitySubtype> getEdgeTypes() throws ThingsboardException { | ||
519 | + try { | ||
520 | + SecurityUser user = getCurrentUser(); | ||
521 | + TenantId tenantId = user.getTenantId(); | ||
522 | + ListenableFuture<List<EntitySubtype>> edgeTypes = edgeService.findEdgeTypesByTenantId(tenantId); | ||
523 | + return checkNotNull(edgeTypes.get()); | ||
524 | + } catch (Exception e) { | ||
525 | + throw handleException(e); | ||
526 | + } | ||
527 | + } | ||
528 | + | ||
529 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
530 | + @RequestMapping(value = "/edge/sync/{edgeId}", method = RequestMethod.POST) | ||
531 | + public void syncEdge(@PathVariable("edgeId") String strEdgeId) throws ThingsboardException { | ||
532 | + checkParameter("edgeId", strEdgeId); | ||
533 | + try { | ||
534 | + if (isEdgesEnabled()) { | ||
535 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
536 | + edgeId = checkNotNull(edgeId); | ||
537 | + SecurityUser user = getCurrentUser(); | ||
538 | + TenantId tenantId = user.getTenantId(); | ||
539 | + EdgeGrpcSession session = edgeGrpcService.getEdgeGrpcSessionById(tenantId, edgeId); | ||
540 | + Edge edge = session.getEdge(); | ||
541 | + syncEdgeService.sync(tenantId, edge); | ||
542 | + } else { | ||
543 | + throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL); | ||
544 | + } | ||
545 | + } catch (Exception e) { | ||
546 | + throw handleException(e); | ||
547 | + } | ||
548 | + } | ||
549 | + | ||
550 | + @RequestMapping(value = "/license/checkInstance", method = RequestMethod.POST) | ||
551 | + @ResponseBody | ||
552 | + public Object checkInstance(@RequestBody Object request) throws ThingsboardException { | ||
553 | + try { | ||
554 | + return edgeService.checkInstance(request); | ||
555 | + } catch (Exception e) { | ||
556 | + throw new ThingsboardException(e, ThingsboardErrorCode.SUBSCRIPTION_VIOLATION); | ||
557 | + } | ||
558 | + } | ||
559 | + | ||
560 | + @RequestMapping(value = "/license/activateInstance", params = {"licenseSecret", "releaseDate"}, method = RequestMethod.POST) | ||
561 | + @ResponseBody | ||
562 | + public Object activateInstance(@RequestParam String licenseSecret, | ||
563 | + @RequestParam String releaseDate) throws ThingsboardException { | ||
564 | + try { | ||
565 | + return edgeService.activateInstance(licenseSecret, releaseDate); | ||
566 | + } catch (Exception e) { | ||
567 | + throw new ThingsboardException(e, ThingsboardErrorCode.SUBSCRIPTION_VIOLATION); | ||
568 | + } | ||
569 | + } | ||
570 | + | ||
571 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
572 | + @RequestMapping(value = "/edge/missingToRelatedRuleChains/{edgeId}", method = RequestMethod.GET) | ||
573 | + @ResponseBody | ||
574 | + public String findMissingToRelatedRuleChains(@PathVariable("edgeId") String strEdgeId) throws ThingsboardException { | ||
575 | + try { | ||
576 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
577 | + edgeId = checkNotNull(edgeId); | ||
578 | + SecurityUser user = getCurrentUser(); | ||
579 | + TenantId tenantId = user.getTenantId(); | ||
580 | + return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId); | ||
581 | + } catch (Exception e) { | ||
582 | + throw handleException(e); | ||
583 | + } | ||
584 | + } | ||
585 | + | ||
586 | + private void cleanUpSensitiveData(Edge edge) { | ||
587 | + edge.setEdgeLicenseKey(null); | ||
588 | + edge.setRoutingKey(null); | ||
589 | + edge.setSecret(null); | ||
590 | + edge.setCloudEndpoint(null); | ||
591 | + edge.setRootRuleChainId(null); | ||
592 | + } | ||
593 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.controller; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.springframework.beans.factory.annotation.Autowired; | ||
20 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
21 | +import org.springframework.web.bind.annotation.PathVariable; | ||
22 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
23 | +import org.springframework.web.bind.annotation.RequestMethod; | ||
24 | +import org.springframework.web.bind.annotation.RequestParam; | ||
25 | +import org.springframework.web.bind.annotation.ResponseBody; | ||
26 | +import org.springframework.web.bind.annotation.RestController; | ||
27 | +import org.thingsboard.server.common.data.edge.EdgeEvent; | ||
28 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | ||
29 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
30 | +import org.thingsboard.server.common.data.id.TenantId; | ||
31 | +import org.thingsboard.server.common.data.page.PageData; | ||
32 | +import org.thingsboard.server.common.data.page.TimePageLink; | ||
33 | +import org.thingsboard.server.dao.edge.EdgeEventService; | ||
34 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
35 | +import org.thingsboard.server.service.security.permission.Operation; | ||
36 | + | ||
37 | +@Slf4j | ||
38 | +@RestController | ||
39 | +@TbCoreComponent | ||
40 | +@RequestMapping("/api") | ||
41 | +public class EdgeEventController extends BaseController { | ||
42 | + | ||
43 | + @Autowired | ||
44 | + private EdgeEventService edgeEventService; | ||
45 | + | ||
46 | + public static final String EDGE_ID = "edgeId"; | ||
47 | + | ||
48 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
49 | + @RequestMapping(value = "/edge/{edgeId}/events", method = RequestMethod.GET) | ||
50 | + @ResponseBody | ||
51 | + public PageData<EdgeEvent> getEdgeEvents( | ||
52 | + @PathVariable(EDGE_ID) String strEdgeId, | ||
53 | + @RequestParam int pageSize, | ||
54 | + @RequestParam int page, | ||
55 | + @RequestParam(required = false) String textSearch, | ||
56 | + @RequestParam(required = false) String sortProperty, | ||
57 | + @RequestParam(required = false) String sortOrder, | ||
58 | + @RequestParam(required = false) Long startTime, | ||
59 | + @RequestParam(required = false) Long endTime) throws ThingsboardException { | ||
60 | + checkParameter(EDGE_ID, strEdgeId); | ||
61 | + try { | ||
62 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
63 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
64 | + checkEdgeId(edgeId, Operation.READ); | ||
65 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | ||
66 | + return checkNotNull(edgeEventService.findEdgeEvents(tenantId, edgeId, pageLink, false)); | ||
67 | + } catch (Exception e) { | ||
68 | + throw handleException(e); | ||
69 | + } | ||
70 | + } | ||
71 | +} |
@@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.ResponseBody; | @@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.ResponseBody; | ||
25 | import org.springframework.web.bind.annotation.ResponseStatus; | 25 | import org.springframework.web.bind.annotation.ResponseStatus; |
26 | import org.springframework.web.bind.annotation.RestController; | 26 | import org.springframework.web.bind.annotation.RestController; |
27 | import org.thingsboard.server.common.data.audit.ActionType; | 27 | import org.thingsboard.server.common.data.audit.ActionType; |
28 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
28 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 29 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
29 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 30 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
30 | import org.thingsboard.server.common.data.id.EntityId; | 31 | import org.thingsboard.server.common.data.id.EntityId; |
@@ -63,10 +64,13 @@ public class EntityRelationController extends BaseController { | @@ -63,10 +64,13 @@ public class EntityRelationController extends BaseController { | ||
63 | relation.setTypeGroup(RelationTypeGroup.COMMON); | 64 | relation.setTypeGroup(RelationTypeGroup.COMMON); |
64 | } | 65 | } |
65 | relationService.saveRelation(getTenantId(), relation); | 66 | relationService.saveRelation(getTenantId(), relation); |
67 | + | ||
66 | logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), | 68 | logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), |
67 | ActionType.RELATION_ADD_OR_UPDATE, null, relation); | 69 | ActionType.RELATION_ADD_OR_UPDATE, null, relation); |
68 | logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), | 70 | logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), |
69 | ActionType.RELATION_ADD_OR_UPDATE, null, relation); | 71 | ActionType.RELATION_ADD_OR_UPDATE, null, relation); |
72 | + | ||
73 | + sendRelationNotificationMsg(getTenantId(), relation, EdgeEventActionType.RELATION_ADD_OR_UPDATE); | ||
70 | } catch (Exception e) { | 74 | } catch (Exception e) { |
71 | logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), | 75 | logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), |
72 | ActionType.RELATION_ADD_OR_UPDATE, e, relation); | 76 | ActionType.RELATION_ADD_OR_UPDATE, e, relation); |
@@ -104,6 +108,8 @@ public class EntityRelationController extends BaseController { | @@ -104,6 +108,8 @@ public class EntityRelationController extends BaseController { | ||
104 | ActionType.RELATION_DELETED, null, relation); | 108 | ActionType.RELATION_DELETED, null, relation); |
105 | logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), | 109 | logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), |
106 | ActionType.RELATION_DELETED, null, relation); | 110 | ActionType.RELATION_DELETED, null, relation); |
111 | + | ||
112 | + sendRelationNotificationMsg(getTenantId(), relation, EdgeEventActionType.RELATION_DELETED); | ||
107 | } catch (Exception e) { | 113 | } catch (Exception e) { |
108 | logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), | 114 | logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), |
109 | ActionType.RELATION_DELETED, e, relation); | 115 | ActionType.RELATION_DELETED, e, relation); |
@@ -32,11 +32,20 @@ import org.springframework.web.bind.annotation.RequestParam; | @@ -32,11 +32,20 @@ import org.springframework.web.bind.annotation.RequestParam; | ||
32 | import org.springframework.web.bind.annotation.ResponseBody; | 32 | import org.springframework.web.bind.annotation.ResponseBody; |
33 | import org.springframework.web.bind.annotation.ResponseStatus; | 33 | import org.springframework.web.bind.annotation.ResponseStatus; |
34 | import org.springframework.web.bind.annotation.RestController; | 34 | import org.springframework.web.bind.annotation.RestController; |
35 | -import org.thingsboard.server.common.data.*; | 35 | +import org.thingsboard.server.common.data.Customer; |
36 | +import org.thingsboard.server.common.data.DataConstants; | ||
37 | +import org.thingsboard.server.common.data.EntitySubtype; | ||
38 | +import org.thingsboard.server.common.data.EntityType; | ||
39 | +import org.thingsboard.server.common.data.EntityView; | ||
40 | +import org.thingsboard.server.common.data.EntityViewInfo; | ||
41 | +import org.thingsboard.server.common.data.asset.Asset; | ||
36 | import org.thingsboard.server.common.data.audit.ActionType; | 42 | import org.thingsboard.server.common.data.audit.ActionType; |
43 | +import org.thingsboard.server.common.data.edge.Edge; | ||
44 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
37 | import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; | 45 | import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; |
38 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 46 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
39 | import org.thingsboard.server.common.data.id.CustomerId; | 47 | import org.thingsboard.server.common.data.id.CustomerId; |
48 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
40 | import org.thingsboard.server.common.data.id.EntityId; | 49 | import org.thingsboard.server.common.data.id.EntityId; |
41 | import org.thingsboard.server.common.data.id.EntityViewId; | 50 | import org.thingsboard.server.common.data.id.EntityViewId; |
42 | import org.thingsboard.server.common.data.id.TenantId; | 51 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -47,6 +56,7 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; | @@ -47,6 +56,7 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; | ||
47 | import org.thingsboard.server.common.data.kv.TsKvEntry; | 56 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
48 | import org.thingsboard.server.common.data.page.PageData; | 57 | import org.thingsboard.server.common.data.page.PageData; |
49 | import org.thingsboard.server.common.data.page.PageLink; | 58 | import org.thingsboard.server.common.data.page.PageLink; |
59 | +import org.thingsboard.server.common.data.page.TimePageLink; | ||
50 | import org.thingsboard.server.dao.exception.IncorrectParameterException; | 60 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
51 | import org.thingsboard.server.dao.model.ModelConstants; | 61 | import org.thingsboard.server.dao.model.ModelConstants; |
52 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 62 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
@@ -65,6 +75,7 @@ import java.util.stream.Collectors; | @@ -65,6 +75,7 @@ import java.util.stream.Collectors; | ||
65 | 75 | ||
66 | import static org.apache.commons.lang3.StringUtils.isBlank; | 76 | import static org.apache.commons.lang3.StringUtils.isBlank; |
67 | import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; | 77 | import static org.thingsboard.server.controller.CustomerController.CUSTOMER_ID; |
78 | +import static org.thingsboard.server.controller.EdgeController.EDGE_ID; | ||
68 | 79 | ||
69 | /** | 80 | /** |
70 | * Created by Victor Basanets on 8/28/2017. | 81 | * Created by Victor Basanets on 8/28/2017. |
@@ -150,6 +161,11 @@ public class EntityViewController extends BaseController { | @@ -150,6 +161,11 @@ public class EntityViewController extends BaseController { | ||
150 | 161 | ||
151 | logEntityAction(savedEntityView.getId(), savedEntityView, null, | 162 | logEntityAction(savedEntityView.getId(), savedEntityView, null, |
152 | entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | 163 | entityView.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
164 | + | ||
165 | + if (entityView.getId() != null) { | ||
166 | + sendEntityNotificationMsg(savedEntityView.getTenantId(), savedEntityView.getId(), EdgeEventActionType.UPDATED); | ||
167 | + } | ||
168 | + | ||
153 | return savedEntityView; | 169 | return savedEntityView; |
154 | } catch (Exception e) { | 170 | } catch (Exception e) { |
155 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, | 171 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), entityView, null, |
@@ -243,7 +259,7 @@ public class EntityViewController extends BaseController { | @@ -243,7 +259,7 @@ public class EntityViewController extends BaseController { | ||
243 | private ListenableFuture<List<Void>> copyLatestFromEntityToEntityView(EntityView entityView, SecurityUser user) { | 259 | private ListenableFuture<List<Void>> copyLatestFromEntityToEntityView(EntityView entityView, SecurityUser user) { |
244 | EntityViewId entityId = entityView.getId(); | 260 | EntityViewId entityId = entityView.getId(); |
245 | List<String> keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ? | 261 | List<String> keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ? |
246 | - entityView.getKeys().getTimeseries() : Collections.emptyList(); | 262 | + entityView.getKeys().getTimeseries() : Collections.emptyList(); |
247 | long startTs = entityView.getStartTimeMs(); | 263 | long startTs = entityView.getStartTimeMs(); |
248 | long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs(); | 264 | long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs(); |
249 | ListenableFuture<List<String>> keysFuture; | 265 | ListenableFuture<List<String>> keysFuture; |
@@ -345,9 +361,14 @@ public class EntityViewController extends BaseController { | @@ -345,9 +361,14 @@ public class EntityViewController extends BaseController { | ||
345 | try { | 361 | try { |
346 | EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); | 362 | EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); |
347 | EntityView entityView = checkEntityViewId(entityViewId, Operation.DELETE); | 363 | EntityView entityView = checkEntityViewId(entityViewId, Operation.DELETE); |
364 | + | ||
365 | + List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(getTenantId(), entityViewId); | ||
366 | + | ||
348 | entityViewService.deleteEntityView(getTenantId(), entityViewId); | 367 | entityViewService.deleteEntityView(getTenantId(), entityViewId); |
349 | logEntityAction(entityViewId, entityView, entityView.getCustomerId(), | 368 | logEntityAction(entityViewId, entityView, entityView.getCustomerId(), |
350 | ActionType.DELETED, null, strEntityViewId); | 369 | ActionType.DELETED, null, strEntityViewId); |
370 | + | ||
371 | + sendDeleteNotificationMsg(getTenantId(), entityViewId, relatedEdgeIds); | ||
351 | } catch (Exception e) { | 372 | } catch (Exception e) { |
352 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), | 373 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), |
353 | null, | 374 | null, |
@@ -388,6 +409,10 @@ public class EntityViewController extends BaseController { | @@ -388,6 +409,10 @@ public class EntityViewController extends BaseController { | ||
388 | logEntityAction(entityViewId, savedEntityView, | 409 | logEntityAction(entityViewId, savedEntityView, |
389 | savedEntityView.getCustomerId(), | 410 | savedEntityView.getCustomerId(), |
390 | ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName()); | 411 | ActionType.ASSIGNED_TO_CUSTOMER, null, strEntityViewId, strCustomerId, customer.getName()); |
412 | + | ||
413 | + sendEntityAssignToCustomerNotificationMsg(savedEntityView.getTenantId(), savedEntityView.getId(), | ||
414 | + customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER); | ||
415 | + | ||
391 | return savedEntityView; | 416 | return savedEntityView; |
392 | } catch (Exception e) { | 417 | } catch (Exception e) { |
393 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, | 418 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, |
@@ -414,6 +439,9 @@ public class EntityViewController extends BaseController { | @@ -414,6 +439,9 @@ public class EntityViewController extends BaseController { | ||
414 | entityView.getCustomerId(), | 439 | entityView.getCustomerId(), |
415 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName()); | 440 | ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEntityViewId, customer.getId().toString(), customer.getName()); |
416 | 441 | ||
442 | + sendEntityAssignToCustomerNotificationMsg(savedEntityView.getTenantId(), savedEntityView.getId(), | ||
443 | + customer.getId(), EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER); | ||
444 | + | ||
417 | return savedEntityView; | 445 | return savedEntityView; |
418 | } catch (Exception e) { | 446 | } catch (Exception e) { |
419 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, | 447 | logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, |
@@ -585,4 +613,107 @@ public class EntityViewController extends BaseController { | @@ -585,4 +613,107 @@ public class EntityViewController extends BaseController { | ||
585 | throw handleException(e); | 613 | throw handleException(e); |
586 | } | 614 | } |
587 | } | 615 | } |
616 | + | ||
617 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
618 | + @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.POST) | ||
619 | + @ResponseBody | ||
620 | + public EntityView assignEntityViewToEdge(@PathVariable(EDGE_ID) String strEdgeId, | ||
621 | + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { | ||
622 | + checkParameter(EDGE_ID, strEdgeId); | ||
623 | + checkParameter(ENTITY_VIEW_ID, strEntityViewId); | ||
624 | + try { | ||
625 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
626 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
627 | + | ||
628 | + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); | ||
629 | + checkEntityViewId(entityViewId, Operation.ASSIGN_TO_EDGE); | ||
630 | + | ||
631 | + EntityView savedEntityView = checkNotNull(entityViewService.assignEntityViewToEdge(getTenantId(), entityViewId, edgeId)); | ||
632 | + logEntityAction(entityViewId, savedEntityView, | ||
633 | + savedEntityView.getCustomerId(), | ||
634 | + ActionType.ASSIGNED_TO_EDGE, null, strEntityViewId, strEdgeId, edge.getName()); | ||
635 | + | ||
636 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedEntityView.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); | ||
637 | + | ||
638 | + return savedEntityView; | ||
639 | + } catch (Exception e) { | ||
640 | + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, | ||
641 | + null, | ||
642 | + ActionType.ASSIGNED_TO_EDGE, e, strEntityViewId, strEdgeId); | ||
643 | + throw handleException(e); | ||
644 | + } | ||
645 | + } | ||
646 | + | ||
647 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
648 | + @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.DELETE) | ||
649 | + @ResponseBody | ||
650 | + public EntityView unassignEntityViewFromEdge(@PathVariable(EDGE_ID) String strEdgeId, | ||
651 | + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { | ||
652 | + checkParameter(EDGE_ID, strEdgeId); | ||
653 | + checkParameter(ENTITY_VIEW_ID, strEntityViewId); | ||
654 | + try { | ||
655 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
656 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
657 | + | ||
658 | + EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); | ||
659 | + EntityView entityView = checkEntityViewId(entityViewId, Operation.UNASSIGN_FROM_EDGE); | ||
660 | + | ||
661 | + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId, edgeId)); | ||
662 | + logEntityAction(entityViewId, entityView, | ||
663 | + entityView.getCustomerId(), | ||
664 | + ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, strEdgeId, edge.getName()); | ||
665 | + | ||
666 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedEntityView.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE); | ||
667 | + | ||
668 | + return savedEntityView; | ||
669 | + } catch (Exception e) { | ||
670 | + logEntityAction(emptyId(EntityType.ENTITY_VIEW), null, | ||
671 | + null, | ||
672 | + ActionType.UNASSIGNED_FROM_EDGE, e, strEntityViewId, strEdgeId); | ||
673 | + throw handleException(e); | ||
674 | + } | ||
675 | + } | ||
676 | + | ||
677 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | ||
678 | + @RequestMapping(value = "/edge/{edgeId}/entityViews", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
679 | + @ResponseBody | ||
680 | + public PageData<EntityView> getEdgeEntityViews( | ||
681 | + @PathVariable(EDGE_ID) String strEdgeId, | ||
682 | + @RequestParam int pageSize, | ||
683 | + @RequestParam int page, | ||
684 | + @RequestParam(required = false) String type, | ||
685 | + @RequestParam(required = false) String textSearch, | ||
686 | + @RequestParam(required = false) String sortProperty, | ||
687 | + @RequestParam(required = false) String sortOrder, | ||
688 | + @RequestParam(required = false) Long startTime, | ||
689 | + @RequestParam(required = false) Long endTime) throws ThingsboardException { | ||
690 | + checkParameter(EDGE_ID, strEdgeId); | ||
691 | + try { | ||
692 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
693 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
694 | + checkEdgeId(edgeId, Operation.READ); | ||
695 | + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); | ||
696 | + PageData<EntityView> nonFilteredResult; | ||
697 | + if (type != null && type.trim().length() > 0) { | ||
698 | + nonFilteredResult = entityViewService.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink); | ||
699 | + } else { | ||
700 | + nonFilteredResult = entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); | ||
701 | + } | ||
702 | + List<EntityView> filteredEntityViews = nonFilteredResult.getData().stream().filter(entityView -> { | ||
703 | + try { | ||
704 | + accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, Operation.READ, entityView.getId(), entityView); | ||
705 | + return true; | ||
706 | + } catch (ThingsboardException e) { | ||
707 | + return false; | ||
708 | + } | ||
709 | + }).collect(Collectors.toList()); | ||
710 | + PageData<EntityView> filteredResult = new PageData<>(filteredEntityViews, | ||
711 | + nonFilteredResult.getTotalPages(), | ||
712 | + nonFilteredResult.getTotalElements(), | ||
713 | + nonFilteredResult.hasNext()); | ||
714 | + return checkNotNull(filteredResult); | ||
715 | + } catch (Exception e) { | ||
716 | + throw handleException(e); | ||
717 | + } | ||
718 | + } | ||
588 | } | 719 | } |
@@ -42,7 +42,10 @@ import org.thingsboard.server.common.data.DataConstants; | @@ -42,7 +42,10 @@ import org.thingsboard.server.common.data.DataConstants; | ||
42 | import org.thingsboard.server.common.data.EntityType; | 42 | import org.thingsboard.server.common.data.EntityType; |
43 | import org.thingsboard.server.common.data.Event; | 43 | import org.thingsboard.server.common.data.Event; |
44 | import org.thingsboard.server.common.data.audit.ActionType; | 44 | import org.thingsboard.server.common.data.audit.ActionType; |
45 | +import org.thingsboard.server.common.data.edge.Edge; | ||
46 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
45 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 47 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
48 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
46 | import org.thingsboard.server.common.data.id.RuleChainId; | 49 | import org.thingsboard.server.common.data.id.RuleChainId; |
47 | import org.thingsboard.server.common.data.id.RuleNodeId; | 50 | import org.thingsboard.server.common.data.id.RuleNodeId; |
48 | import org.thingsboard.server.common.data.id.TenantId; | 51 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -54,6 +57,7 @@ import org.thingsboard.server.common.data.rule.RuleChain; | @@ -54,6 +57,7 @@ import org.thingsboard.server.common.data.rule.RuleChain; | ||
54 | import org.thingsboard.server.common.data.rule.RuleChainData; | 57 | import org.thingsboard.server.common.data.rule.RuleChainData; |
55 | import org.thingsboard.server.common.data.rule.RuleChainImportResult; | 58 | import org.thingsboard.server.common.data.rule.RuleChainImportResult; |
56 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; | 59 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
60 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
57 | import org.thingsboard.server.common.data.rule.RuleNode; | 61 | import org.thingsboard.server.common.data.rule.RuleNode; |
58 | import org.thingsboard.server.common.msg.TbMsg; | 62 | import org.thingsboard.server.common.msg.TbMsg; |
59 | import org.thingsboard.server.common.msg.TbMsgDataType; | 63 | import org.thingsboard.server.common.msg.TbMsgDataType; |
@@ -138,13 +142,21 @@ public class RuleChainController extends BaseController { | @@ -138,13 +142,21 @@ public class RuleChainController extends BaseController { | ||
138 | 142 | ||
139 | RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); | 143 | RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); |
140 | 144 | ||
141 | - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(), | ||
142 | - created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | 145 | + if (RuleChainType.CORE.equals(savedRuleChain.getType())) { |
146 | + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(), | ||
147 | + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | ||
148 | + } | ||
143 | 149 | ||
144 | logEntityAction(savedRuleChain.getId(), savedRuleChain, | 150 | logEntityAction(savedRuleChain.getId(), savedRuleChain, |
145 | null, | 151 | null, |
146 | created ? ActionType.ADDED : ActionType.UPDATED, null); | 152 | created ? ActionType.ADDED : ActionType.UPDATED, null); |
147 | 153 | ||
154 | + if (RuleChainType.EDGE.equals(savedRuleChain.getType())) { | ||
155 | + if (!created) { | ||
156 | + sendEntityNotificationMsg(savedRuleChain.getTenantId(), savedRuleChain.getId(), EdgeEventActionType.UPDATED); | ||
157 | + } | ||
158 | + } | ||
159 | + | ||
148 | return savedRuleChain; | 160 | return savedRuleChain; |
149 | } catch (Exception e) { | 161 | } catch (Exception e) { |
150 | 162 | ||
@@ -234,12 +246,19 @@ public class RuleChainController extends BaseController { | @@ -234,12 +246,19 @@ public class RuleChainController extends BaseController { | ||
234 | RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE); | 246 | RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE); |
235 | RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData)); | 247 | RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData)); |
236 | 248 | ||
237 | - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); | 249 | + if (RuleChainType.CORE.equals(ruleChain.getType())) { |
250 | + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); | ||
251 | + } | ||
238 | 252 | ||
239 | logEntityAction(ruleChain.getId(), ruleChain, | 253 | logEntityAction(ruleChain.getId(), ruleChain, |
240 | null, | 254 | null, |
241 | ActionType.UPDATED, null, ruleChainMetaData); | 255 | ActionType.UPDATED, null, ruleChainMetaData); |
242 | 256 | ||
257 | + if (RuleChainType.EDGE.equals(ruleChain.getType())) { | ||
258 | + sendEntityNotificationMsg(ruleChain.getTenantId(), | ||
259 | + ruleChain.getId(), EdgeEventActionType.UPDATED); | ||
260 | + } | ||
261 | + | ||
243 | return savedRuleChainMetaData; | 262 | return savedRuleChainMetaData; |
244 | } catch (Exception e) { | 263 | } catch (Exception e) { |
245 | 264 | ||
@@ -256,13 +275,18 @@ public class RuleChainController extends BaseController { | @@ -256,13 +275,18 @@ public class RuleChainController extends BaseController { | ||
256 | public PageData<RuleChain> getRuleChains( | 275 | public PageData<RuleChain> getRuleChains( |
257 | @RequestParam int pageSize, | 276 | @RequestParam int pageSize, |
258 | @RequestParam int page, | 277 | @RequestParam int page, |
278 | + @RequestParam(value = "type", required = false) String typeStr, | ||
259 | @RequestParam(required = false) String textSearch, | 279 | @RequestParam(required = false) String textSearch, |
260 | @RequestParam(required = false) String sortProperty, | 280 | @RequestParam(required = false) String sortProperty, |
261 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { | 281 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { |
262 | try { | 282 | try { |
263 | TenantId tenantId = getCurrentUser().getTenantId(); | 283 | TenantId tenantId = getCurrentUser().getTenantId(); |
264 | PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | 284 | PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); |
265 | - return checkNotNull(ruleChainService.findTenantRuleChains(tenantId, pageLink)); | 285 | + RuleChainType type = RuleChainType.CORE; |
286 | + if (typeStr != null && typeStr.trim().length() > 0) { | ||
287 | + type = RuleChainType.valueOf(typeStr); | ||
288 | + } | ||
289 | + return checkNotNull(ruleChainService.findTenantRuleChainsByType(tenantId, type, pageLink)); | ||
266 | } catch (Exception e) { | 290 | } catch (Exception e) { |
267 | throw handleException(e); | 291 | throw handleException(e); |
268 | } | 292 | } |
@@ -281,19 +305,30 @@ public class RuleChainController extends BaseController { | @@ -281,19 +305,30 @@ public class RuleChainController extends BaseController { | ||
281 | 305 | ||
282 | Set<RuleChainId> referencingRuleChainIds = referencingRuleNodes.stream().map(RuleNode::getRuleChainId).collect(Collectors.toSet()); | 306 | Set<RuleChainId> referencingRuleChainIds = referencingRuleNodes.stream().map(RuleNode::getRuleChainId).collect(Collectors.toSet()); |
283 | 307 | ||
308 | + List<EdgeId> relatedEdgeIds = null; | ||
309 | + if (RuleChainType.EDGE.equals(ruleChain.getType())) { | ||
310 | + relatedEdgeIds = findRelatedEdgeIds(getTenantId(), ruleChainId); | ||
311 | + } | ||
312 | + | ||
284 | ruleChainService.deleteRuleChainById(getTenantId(), ruleChainId); | 313 | ruleChainService.deleteRuleChainById(getTenantId(), ruleChainId); |
285 | 314 | ||
286 | referencingRuleChainIds.remove(ruleChain.getId()); | 315 | referencingRuleChainIds.remove(ruleChain.getId()); |
287 | 316 | ||
288 | - referencingRuleChainIds.forEach(referencingRuleChainId -> | ||
289 | - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), referencingRuleChainId, ComponentLifecycleEvent.UPDATED)); | 317 | + if (RuleChainType.CORE.equals(ruleChain.getType())) { |
318 | + referencingRuleChainIds.forEach(referencingRuleChainId -> | ||
319 | + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), referencingRuleChainId, ComponentLifecycleEvent.UPDATED)); | ||
290 | 320 | ||
291 | - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED); | 321 | + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED); |
322 | + } | ||
292 | 323 | ||
293 | logEntityAction(ruleChainId, ruleChain, | 324 | logEntityAction(ruleChainId, ruleChain, |
294 | null, | 325 | null, |
295 | ActionType.DELETED, null, strRuleChainId); | 326 | ActionType.DELETED, null, strRuleChainId); |
296 | 327 | ||
328 | + if (RuleChainType.EDGE.equals(ruleChain.getType())) { | ||
329 | + sendDeleteNotificationMsg(ruleChain.getTenantId(), ruleChain.getId(), relatedEdgeIds); | ||
330 | + } | ||
331 | + | ||
297 | } catch (Exception e) { | 332 | } catch (Exception e) { |
298 | logEntityAction(emptyId(EntityType.RULE_CHAIN), | 333 | logEntityAction(emptyId(EntityType.RULE_CHAIN), |
299 | null, | 334 | null, |
@@ -411,7 +446,7 @@ public class RuleChainController extends BaseController { | @@ -411,7 +446,7 @@ public class RuleChainController extends BaseController { | ||
411 | public void importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { | 446 | public void importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { |
412 | try { | 447 | try { |
413 | TenantId tenantId = getCurrentUser().getTenantId(); | 448 | TenantId tenantId = getCurrentUser().getTenantId(); |
414 | - List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite); | 449 | + List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite); |
415 | if (!CollectionUtils.isEmpty(importResults)) { | 450 | if (!CollectionUtils.isEmpty(importResults)) { |
416 | for (RuleChainImportResult importResult : importResults) { | 451 | for (RuleChainImportResult importResult : importResults) { |
417 | tbClusterService.onEntityStateChange(importResult.getTenantId(), importResult.getRuleChainId(), importResult.getLifecycleEvent()); | 452 | tbClusterService.onEntityStateChange(importResult.getTenantId(), importResult.getRuleChainId(), importResult.getLifecycleEvent()); |
@@ -452,5 +487,160 @@ public class RuleChainController extends BaseController { | @@ -452,5 +487,160 @@ public class RuleChainController extends BaseController { | ||
452 | return msgData; | 487 | return msgData; |
453 | } | 488 | } |
454 | 489 | ||
490 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
491 | + @RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.POST) | ||
492 | + @ResponseBody | ||
493 | + public RuleChain assignRuleChainToEdge(@PathVariable("edgeId") String strEdgeId, | ||
494 | + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { | ||
495 | + checkParameter("edgeId", strEdgeId); | ||
496 | + checkParameter(RULE_CHAIN_ID, strRuleChainId); | ||
497 | + try { | ||
498 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
499 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
500 | + | ||
501 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | ||
502 | + checkRuleChain(ruleChainId, Operation.ASSIGN_TO_EDGE); | ||
503 | + | ||
504 | + RuleChain savedRuleChain = checkNotNull(ruleChainService.assignRuleChainToEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId)); | ||
505 | + | ||
506 | + logEntityAction(ruleChainId, savedRuleChain, | ||
507 | + null, | ||
508 | + ActionType.ASSIGNED_TO_EDGE, null, strRuleChainId, strEdgeId, edge.getName()); | ||
509 | + | ||
510 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedRuleChain.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE); | ||
511 | + | ||
512 | + return savedRuleChain; | ||
513 | + } catch (Exception e) { | ||
514 | + | ||
515 | + logEntityAction(emptyId(EntityType.RULE_CHAIN), null, | ||
516 | + null, | ||
517 | + ActionType.ASSIGNED_TO_EDGE, e, strRuleChainId, strEdgeId); | ||
518 | + | ||
519 | + throw handleException(e); | ||
520 | + } | ||
521 | + } | ||
522 | + | ||
523 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
524 | + @RequestMapping(value = "/edge/{edgeId}/ruleChain/{ruleChainId}", method = RequestMethod.DELETE) | ||
525 | + @ResponseBody | ||
526 | + public RuleChain unassignRuleChainFromEdge(@PathVariable("edgeId") String strEdgeId, | ||
527 | + @PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { | ||
528 | + checkParameter("edgeId", strEdgeId); | ||
529 | + checkParameter(RULE_CHAIN_ID, strRuleChainId); | ||
530 | + try { | ||
531 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
532 | + Edge edge = checkEdgeId(edgeId, Operation.READ); | ||
533 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | ||
534 | + RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.UNASSIGN_FROM_EDGE); | ||
535 | + | ||
536 | + RuleChain savedRuleChain = checkNotNull(ruleChainService.unassignRuleChainFromEdge(getCurrentUser().getTenantId(), ruleChainId, edgeId, false)); | ||
537 | + | ||
538 | + logEntityAction(ruleChainId, ruleChain, | ||
539 | + null, | ||
540 | + ActionType.UNASSIGNED_FROM_EDGE, null, strRuleChainId, strEdgeId, edge.getName()); | ||
541 | + | ||
542 | + sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedRuleChain.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE); | ||
543 | + | ||
544 | + return savedRuleChain; | ||
545 | + } catch (Exception e) { | ||
546 | + | ||
547 | + logEntityAction(emptyId(EntityType.RULE_CHAIN), null, | ||
548 | + null, | ||
549 | + ActionType.UNASSIGNED_FROM_EDGE, e, strRuleChainId, strEdgeId); | ||
550 | + | ||
551 | + throw handleException(e); | ||
552 | + } | ||
553 | + } | ||
554 | + | ||
555 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
556 | + @RequestMapping(value = "/edge/{edgeId}/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) | ||
557 | + @ResponseBody | ||
558 | + public PageData<RuleChain> getEdgeRuleChains( | ||
559 | + @PathVariable("edgeId") String strEdgeId, | ||
560 | + @RequestParam int pageSize, | ||
561 | + @RequestParam int page, | ||
562 | + @RequestParam(required = false) String textSearch, | ||
563 | + @RequestParam(required = false) String sortProperty, | ||
564 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
565 | + checkParameter("edgeId", strEdgeId); | ||
566 | + try { | ||
567 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
568 | + EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); | ||
569 | + checkEdgeId(edgeId, Operation.READ); | ||
570 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
571 | + return checkNotNull(ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink)); | ||
572 | + } catch (Exception e) { | ||
573 | + throw handleException(e); | ||
574 | + } | ||
575 | + } | ||
576 | + | ||
577 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
578 | + @RequestMapping(value = "/ruleChain/{ruleChainId}/edgeTemplateRoot", method = RequestMethod.POST) | ||
579 | + @ResponseBody | ||
580 | + public RuleChain setEdgeTemplateRootRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { | ||
581 | + checkParameter(RULE_CHAIN_ID, strRuleChainId); | ||
582 | + try { | ||
583 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | ||
584 | + RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE); | ||
585 | + ruleChainService.setEdgeTemplateRootRuleChain(getTenantId(), ruleChainId); | ||
586 | + return ruleChain; | ||
587 | + } catch (Exception e) { | ||
588 | + logEntityAction(emptyId(EntityType.RULE_CHAIN), | ||
589 | + null, | ||
590 | + null, | ||
591 | + ActionType.UPDATED, e, strRuleChainId); | ||
592 | + throw handleException(e); | ||
593 | + } | ||
594 | + } | ||
595 | + | ||
596 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
597 | + @RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.POST) | ||
598 | + @ResponseBody | ||
599 | + public RuleChain setAutoAssignToEdgeRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { | ||
600 | + checkParameter(RULE_CHAIN_ID, strRuleChainId); | ||
601 | + try { | ||
602 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | ||
603 | + RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE); | ||
604 | + ruleChainService.setAutoAssignToEdgeRuleChain(getTenantId(), ruleChainId); | ||
605 | + return ruleChain; | ||
606 | + } catch (Exception e) { | ||
607 | + logEntityAction(emptyId(EntityType.RULE_CHAIN), | ||
608 | + null, | ||
609 | + null, | ||
610 | + ActionType.UPDATED, e, strRuleChainId); | ||
611 | + throw handleException(e); | ||
612 | + } | ||
613 | + } | ||
614 | + | ||
615 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
616 | + @RequestMapping(value = "/ruleChain/{ruleChainId}/autoAssignToEdge", method = RequestMethod.DELETE) | ||
617 | + @ResponseBody | ||
618 | + public RuleChain unsetAutoAssignToEdgeRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { | ||
619 | + checkParameter(RULE_CHAIN_ID, strRuleChainId); | ||
620 | + try { | ||
621 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | ||
622 | + RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE); | ||
623 | + ruleChainService.unsetAutoAssignToEdgeRuleChain(getTenantId(), ruleChainId); | ||
624 | + return ruleChain; | ||
625 | + } catch (Exception e) { | ||
626 | + logEntityAction(emptyId(EntityType.RULE_CHAIN), | ||
627 | + null, | ||
628 | + null, | ||
629 | + ActionType.UPDATED, e, strRuleChainId); | ||
630 | + throw handleException(e); | ||
631 | + } | ||
632 | + } | ||
633 | + | ||
634 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
635 | + @RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET) | ||
636 | + @ResponseBody | ||
637 | + public List<RuleChain> getAutoAssignToEdgeRuleChains() throws ThingsboardException { | ||
638 | + try { | ||
639 | + TenantId tenantId = getCurrentUser().getTenantId(); | ||
640 | + return checkNotNull(ruleChainService.findAutoAssignToEdgeRuleChainsByTenantId(tenantId)).get(); | ||
641 | + } catch (Exception e) { | ||
642 | + throw handleException(e); | ||
643 | + } | ||
644 | + } | ||
455 | 645 | ||
456 | } | 646 | } |
@@ -95,6 +95,9 @@ public class TenantController extends BaseController { | @@ -95,6 +95,9 @@ public class TenantController extends BaseController { | ||
95 | tenant = checkNotNull(tenantService.saveTenant(tenant)); | 95 | tenant = checkNotNull(tenantService.saveTenant(tenant)); |
96 | if (newTenant) { | 96 | if (newTenant) { |
97 | installScripts.createDefaultRuleChains(tenant.getId()); | 97 | installScripts.createDefaultRuleChains(tenant.getId()); |
98 | + if (edgesEnabled) { | ||
99 | + installScripts.createDefaultEdgeRuleChains(tenant.getId()); | ||
100 | + } | ||
98 | } | 101 | } |
99 | tenantProfileCache.evict(tenant.getId()); | 102 | tenantProfileCache.evict(tenant.getId()); |
100 | tbClusterService.onTenantChange(tenant, null); | 103 | tbClusterService.onTenantChange(tenant, null); |
@@ -36,9 +36,11 @@ import org.thingsboard.rule.engine.api.MailService; | @@ -36,9 +36,11 @@ import org.thingsboard.rule.engine.api.MailService; | ||
36 | import org.thingsboard.server.common.data.EntityType; | 36 | import org.thingsboard.server.common.data.EntityType; |
37 | import org.thingsboard.server.common.data.User; | 37 | import org.thingsboard.server.common.data.User; |
38 | import org.thingsboard.server.common.data.audit.ActionType; | 38 | import org.thingsboard.server.common.data.audit.ActionType; |
39 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
39 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 40 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
40 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 41 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
41 | import org.thingsboard.server.common.data.id.CustomerId; | 42 | import org.thingsboard.server.common.data.id.CustomerId; |
43 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
42 | import org.thingsboard.server.common.data.id.TenantId; | 44 | import org.thingsboard.server.common.data.id.TenantId; |
43 | import org.thingsboard.server.common.data.id.UserId; | 45 | import org.thingsboard.server.common.data.id.UserId; |
44 | import org.thingsboard.server.common.data.page.PageData; | 46 | import org.thingsboard.server.common.data.page.PageData; |
@@ -57,6 +59,7 @@ import org.thingsboard.server.service.security.permission.Resource; | @@ -57,6 +59,7 @@ import org.thingsboard.server.service.security.permission.Resource; | ||
57 | import org.thingsboard.server.service.security.system.SystemSecurityService; | 59 | import org.thingsboard.server.service.security.system.SystemSecurityService; |
58 | 60 | ||
59 | import javax.servlet.http.HttpServletRequest; | 61 | import javax.servlet.http.HttpServletRequest; |
62 | +import java.util.List; | ||
60 | 63 | ||
61 | @RequiredArgsConstructor | 64 | @RequiredArgsConstructor |
62 | @RestController | 65 | @RestController |
@@ -178,6 +181,9 @@ public class UserController extends BaseController { | @@ -178,6 +181,9 @@ public class UserController extends BaseController { | ||
178 | savedUser.getCustomerId(), | 181 | savedUser.getCustomerId(), |
179 | user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); | 182 | user.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
180 | 183 | ||
184 | + sendEntityNotificationMsg(getTenantId(), savedUser.getId(), | ||
185 | + user.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); | ||
186 | + | ||
181 | return savedUser; | 187 | return savedUser; |
182 | } catch (Exception e) { | 188 | } catch (Exception e) { |
183 | 189 | ||
@@ -247,12 +253,17 @@ public class UserController extends BaseController { | @@ -247,12 +253,17 @@ public class UserController extends BaseController { | ||
247 | try { | 253 | try { |
248 | UserId userId = new UserId(toUUID(strUserId)); | 254 | UserId userId = new UserId(toUUID(strUserId)); |
249 | User user = checkUserId(userId, Operation.DELETE); | 255 | User user = checkUserId(userId, Operation.DELETE); |
256 | + | ||
257 | + List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(getTenantId(), userId); | ||
258 | + | ||
250 | userService.deleteUser(getCurrentUser().getTenantId(), userId); | 259 | userService.deleteUser(getCurrentUser().getTenantId(), userId); |
251 | 260 | ||
252 | logEntityAction(userId, user, | 261 | logEntityAction(userId, user, |
253 | user.getCustomerId(), | 262 | user.getCustomerId(), |
254 | ActionType.DELETED, null, strUserId); | 263 | ActionType.DELETED, null, strUserId); |
255 | 264 | ||
265 | + sendDeleteNotificationMsg(getTenantId(), userId, relatedEdgeIds); | ||
266 | + | ||
256 | } catch (Exception e) { | 267 | } catch (Exception e) { |
257 | logEntityAction(emptyId(EntityType.USER), | 268 | logEntityAction(emptyId(EntityType.USER), |
258 | null, | 269 | null, |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
18 | import org.springframework.http.HttpStatus; | 19 | import org.springframework.http.HttpStatus; |
19 | import org.springframework.security.access.prepost.PreAuthorize; | 20 | import org.springframework.security.access.prepost.PreAuthorize; |
20 | import org.springframework.web.bind.annotation.PathVariable; | 21 | import org.springframework.web.bind.annotation.PathVariable; |
@@ -25,6 +26,8 @@ import org.springframework.web.bind.annotation.RequestParam; | @@ -25,6 +26,8 @@ import org.springframework.web.bind.annotation.RequestParam; | ||
25 | import org.springframework.web.bind.annotation.ResponseBody; | 26 | import org.springframework.web.bind.annotation.ResponseBody; |
26 | import org.springframework.web.bind.annotation.ResponseStatus; | 27 | import org.springframework.web.bind.annotation.ResponseStatus; |
27 | import org.springframework.web.bind.annotation.RestController; | 28 | import org.springframework.web.bind.annotation.RestController; |
29 | +import org.thingsboard.server.common.data.EntityType; | ||
30 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
28 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 31 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
29 | import org.thingsboard.server.common.data.id.TenantId; | 32 | import org.thingsboard.server.common.data.id.TenantId; |
30 | import org.thingsboard.server.common.data.id.WidgetTypeId; | 33 | import org.thingsboard.server.common.data.id.WidgetTypeId; |
@@ -39,6 +42,7 @@ import org.thingsboard.server.service.security.permission.Resource; | @@ -39,6 +42,7 @@ import org.thingsboard.server.service.security.permission.Resource; | ||
39 | 42 | ||
40 | import java.util.List; | 43 | import java.util.List; |
41 | 44 | ||
45 | +@Slf4j | ||
42 | @RestController | 46 | @RestController |
43 | @TbCoreComponent | 47 | @TbCoreComponent |
44 | @RequestMapping("/api") | 48 | @RequestMapping("/api") |
@@ -69,8 +73,12 @@ public class WidgetTypeController extends BaseController { | @@ -69,8 +73,12 @@ public class WidgetTypeController extends BaseController { | ||
69 | } | 73 | } |
70 | 74 | ||
71 | checkEntity(widgetTypeDetails.getId(), widgetTypeDetails, Resource.WIDGET_TYPE); | 75 | checkEntity(widgetTypeDetails.getId(), widgetTypeDetails, Resource.WIDGET_TYPE); |
76 | + WidgetTypeDetails savedWidgetTypeDetails = widgetTypeService.saveWidgetType(widgetTypeDetails); | ||
72 | 77 | ||
73 | - return checkNotNull(widgetTypeService.saveWidgetType(widgetTypeDetails)); | 78 | + sendEntityNotificationMsg(getTenantId(), savedWidgetTypeDetails.getId(), |
79 | + widgetTypeDetails.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); | ||
80 | + | ||
81 | + return checkNotNull(savedWidgetTypeDetails); | ||
74 | } catch (Exception e) { | 82 | } catch (Exception e) { |
75 | throw handleException(e); | 83 | throw handleException(e); |
76 | } | 84 | } |
@@ -85,6 +93,9 @@ public class WidgetTypeController extends BaseController { | @@ -85,6 +93,9 @@ public class WidgetTypeController extends BaseController { | ||
85 | WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); | 93 | WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId)); |
86 | checkWidgetTypeId(widgetTypeId, Operation.DELETE); | 94 | checkWidgetTypeId(widgetTypeId, Operation.DELETE); |
87 | widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId); | 95 | widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId); |
96 | + | ||
97 | + sendEntityNotificationMsg(getTenantId(), widgetTypeId, EdgeEventActionType.DELETED); | ||
98 | + | ||
88 | } catch (Exception e) { | 99 | } catch (Exception e) { |
89 | throw handleException(e); | 100 | throw handleException(e); |
90 | } | 101 | } |
@@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestParam; | @@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestParam; | ||
25 | import org.springframework.web.bind.annotation.ResponseBody; | 25 | import org.springframework.web.bind.annotation.ResponseBody; |
26 | import org.springframework.web.bind.annotation.ResponseStatus; | 26 | import org.springframework.web.bind.annotation.ResponseStatus; |
27 | import org.springframework.web.bind.annotation.RestController; | 27 | import org.springframework.web.bind.annotation.RestController; |
28 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
28 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 29 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
29 | import org.thingsboard.server.common.data.id.TenantId; | 30 | import org.thingsboard.server.common.data.id.TenantId; |
30 | import org.thingsboard.server.common.data.id.WidgetsBundleId; | 31 | import org.thingsboard.server.common.data.id.WidgetsBundleId; |
@@ -68,7 +69,12 @@ public class WidgetsBundleController extends BaseController { | @@ -68,7 +69,12 @@ public class WidgetsBundleController extends BaseController { | ||
68 | } | 69 | } |
69 | 70 | ||
70 | checkEntity(widgetsBundle.getId(), widgetsBundle, Resource.WIDGETS_BUNDLE); | 71 | checkEntity(widgetsBundle.getId(), widgetsBundle, Resource.WIDGETS_BUNDLE); |
71 | - return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); | 72 | + WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); |
73 | + | ||
74 | + sendEntityNotificationMsg(getTenantId(), savedWidgetsBundle.getId(), | ||
75 | + widgetsBundle.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED); | ||
76 | + | ||
77 | + return checkNotNull(savedWidgetsBundle); | ||
72 | } catch (Exception e) { | 78 | } catch (Exception e) { |
73 | throw handleException(e); | 79 | throw handleException(e); |
74 | } | 80 | } |
@@ -83,6 +89,9 @@ public class WidgetsBundleController extends BaseController { | @@ -83,6 +89,9 @@ public class WidgetsBundleController extends BaseController { | ||
83 | WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); | 89 | WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); |
84 | checkWidgetsBundleId(widgetsBundleId, Operation.DELETE); | 90 | checkWidgetsBundleId(widgetsBundleId, Operation.DELETE); |
85 | widgetsBundleService.deleteWidgetsBundle(getTenantId(), widgetsBundleId); | 91 | widgetsBundleService.deleteWidgetsBundle(getTenantId(), widgetsBundleId); |
92 | + | ||
93 | + sendEntityNotificationMsg(getTenantId(), widgetsBundleId, EdgeEventActionType.DELETED); | ||
94 | + | ||
86 | } catch (Exception e) { | 95 | } catch (Exception e) { |
87 | throw handleException(e); | 96 | throw handleException(e); |
88 | } | 97 | } |
@@ -27,6 +27,7 @@ import org.springframework.security.authentication.LockedException; | @@ -27,6 +27,7 @@ import org.springframework.security.authentication.LockedException; | ||
27 | import org.springframework.security.core.AuthenticationException; | 27 | import org.springframework.security.core.AuthenticationException; |
28 | import org.springframework.security.web.access.AccessDeniedHandler; | 28 | import org.springframework.security.web.access.AccessDeniedHandler; |
29 | import org.springframework.stereotype.Component; | 29 | import org.springframework.stereotype.Component; |
30 | +import org.springframework.web.client.HttpClientErrorException; | ||
30 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | 31 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
31 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 32 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
32 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; | 33 | import org.thingsboard.server.common.msg.tools.TbRateLimitsException; |
@@ -66,7 +67,12 @@ public class ThingsboardErrorResponseHandler implements AccessDeniedHandler { | @@ -66,7 +67,12 @@ public class ThingsboardErrorResponseHandler implements AccessDeniedHandler { | ||
66 | response.setContentType(MediaType.APPLICATION_JSON_VALUE); | 67 | response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
67 | 68 | ||
68 | if (exception instanceof ThingsboardException) { | 69 | if (exception instanceof ThingsboardException) { |
69 | - handleThingsboardException((ThingsboardException) exception, response); | 70 | + ThingsboardException thingsboardException = (ThingsboardException) exception; |
71 | + if (thingsboardException.getErrorCode() == ThingsboardErrorCode.SUBSCRIPTION_VIOLATION) { | ||
72 | + handleSubscriptionException((ThingsboardException) exception, response); | ||
73 | + } else { | ||
74 | + handleThingsboardException((ThingsboardException) exception, response); | ||
75 | + } | ||
70 | } else if (exception instanceof TbRateLimitsException) { | 76 | } else if (exception instanceof TbRateLimitsException) { |
71 | handleRateLimitException(response, (TbRateLimitsException) exception); | 77 | handleRateLimitException(response, (TbRateLimitsException) exception); |
72 | } else if (exception instanceof AccessDeniedException) { | 78 | } else if (exception instanceof AccessDeniedException) { |
@@ -126,6 +132,11 @@ public class ThingsboardErrorResponseHandler implements AccessDeniedHandler { | @@ -126,6 +132,11 @@ public class ThingsboardErrorResponseHandler implements AccessDeniedHandler { | ||
126 | ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS)); | 132 | ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS)); |
127 | } | 133 | } |
128 | 134 | ||
135 | + private void handleSubscriptionException(ThingsboardException subscriptionException, HttpServletResponse response) throws IOException { | ||
136 | + response.setStatus(HttpStatus.FORBIDDEN.value()); | ||
137 | + mapper.writeValue(response.getWriter(), | ||
138 | + (new ObjectMapper()).readValue(((HttpClientErrorException) subscriptionException.getCause()).getResponseBodyAsByteArray(), Object.class)); | ||
139 | + } | ||
129 | 140 | ||
130 | private void handleAccessDeniedException(HttpServletResponse response) throws IOException { | 141 | private void handleAccessDeniedException(HttpServletResponse response) throws IOException { |
131 | response.setStatus(HttpStatus.FORBIDDEN.value()); | 142 | response.setStatus(HttpStatus.FORBIDDEN.value()); |
@@ -193,7 +193,9 @@ public class ThingsboardInstallService { | @@ -193,7 +193,9 @@ public class ThingsboardInstallService { | ||
193 | databaseEntitiesUpgradeService.upgradeDatabase("3.2.1"); | 193 | databaseEntitiesUpgradeService.upgradeDatabase("3.2.1"); |
194 | case "3.2.2": | 194 | case "3.2.2": |
195 | log.info("Upgrading ThingsBoard from version 3.2.2 to 3.3.0 ..."); | 195 | log.info("Upgrading ThingsBoard from version 3.2.2 to 3.3.0 ..."); |
196 | - databaseEntitiesUpgradeService.upgradeDatabase("3.2.2"); | 196 | + databaseEntitiesUpgradeService.upgradeDatabase("3.2.2"); |
197 | + | ||
198 | + dataUpdateService.updateData("3.2.2"); | ||
197 | 199 | ||
198 | log.info("Updating system data..."); | 200 | log.info("Updating system data..."); |
199 | systemDataLoaderService.updateSystemWidgets(); | 201 | systemDataLoaderService.updateSystemWidgets(); |
@@ -34,13 +34,13 @@ import org.thingsboard.rule.engine.api.TbRelationTypes; | @@ -34,13 +34,13 @@ import org.thingsboard.rule.engine.api.TbRelationTypes; | ||
34 | import org.thingsboard.server.common.data.id.TenantId; | 34 | import org.thingsboard.server.common.data.id.TenantId; |
35 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | 35 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
36 | import org.thingsboard.server.common.data.plugin.ComponentType; | 36 | import org.thingsboard.server.common.data.plugin.ComponentType; |
37 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
37 | import org.thingsboard.server.dao.component.ComponentDescriptorService; | 38 | import org.thingsboard.server.dao.component.ComponentDescriptorService; |
38 | 39 | ||
39 | import javax.annotation.PostConstruct; | 40 | import javax.annotation.PostConstruct; |
40 | import java.lang.annotation.Annotation; | 41 | import java.lang.annotation.Annotation; |
41 | import java.util.ArrayList; | 42 | import java.util.ArrayList; |
42 | import java.util.Arrays; | 43 | import java.util.Arrays; |
43 | -import java.util.Collection; | ||
44 | import java.util.Collections; | 44 | import java.util.Collections; |
45 | import java.util.HashMap; | 45 | import java.util.HashMap; |
46 | import java.util.HashSet; | 46 | import java.util.HashSet; |
@@ -65,7 +65,9 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | @@ -65,7 +65,9 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | ||
65 | 65 | ||
66 | private Map<String, ComponentDescriptor> components = new HashMap<>(); | 66 | private Map<String, ComponentDescriptor> components = new HashMap<>(); |
67 | 67 | ||
68 | - private Map<ComponentType, List<ComponentDescriptor>> componentsMap = new HashMap<>(); | 68 | + private Map<ComponentType, List<ComponentDescriptor>> coreComponentsMap = new HashMap<>(); |
69 | + | ||
70 | + private Map<ComponentType, List<ComponentDescriptor>> edgeComponentsMap = new HashMap<>(); | ||
69 | 71 | ||
70 | private ObjectMapper mapper = new ObjectMapper(); | 72 | private ObjectMapper mapper = new ObjectMapper(); |
71 | 73 | ||
@@ -93,7 +95,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | @@ -93,7 +95,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | ||
93 | ComponentType type = ruleNodeAnnotation.type(); | 95 | ComponentType type = ruleNodeAnnotation.type(); |
94 | ComponentDescriptor component = scanAndPersistComponent(def, type); | 96 | ComponentDescriptor component = scanAndPersistComponent(def, type); |
95 | components.put(component.getClazz(), component); | 97 | components.put(component.getClazz(), component); |
96 | - componentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component); | 98 | + putComponentIntoMaps(type, ruleNodeAnnotation, component); |
97 | break; | 99 | break; |
98 | } catch (Exception e) { | 100 | } catch (Exception e) { |
99 | log.trace("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); | 101 | log.trace("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); |
@@ -113,22 +115,35 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | @@ -113,22 +115,35 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | ||
113 | } | 115 | } |
114 | } | 116 | } |
115 | 117 | ||
116 | - private void registerComponents(ComponentType type, Class<? extends Annotation> annotation) { | ||
117 | - List<ComponentDescriptor> components = persist(getBeanDefinitions(annotation), type); | ||
118 | - componentsMap.put(type, components); | ||
119 | - registerComponents(components); | ||
120 | - } | ||
121 | - | ||
122 | - private void registerComponents(Collection<ComponentDescriptor> comps) { | ||
123 | - comps.forEach(c -> components.put(c.getClazz(), c)); | 118 | + private void putComponentIntoMaps(ComponentType type, RuleNode ruleNodeAnnotation, ComponentDescriptor component) { |
119 | + boolean ruleChainTypesMethodAvailable; | ||
120 | + try { | ||
121 | + ruleNodeAnnotation.getClass().getMethod("ruleChainTypes"); | ||
122 | + ruleChainTypesMethodAvailable = true; | ||
123 | + } catch (NoSuchMethodException exception) { | ||
124 | + log.warn("[{}] does not have ruleChainTypes. Probably extension class compiled before 3.3 release. " + | ||
125 | + "Please update your extensions and compile using latest 3.3 release dependency", ruleNodeAnnotation.name()); | ||
126 | + ruleChainTypesMethodAvailable = false; | ||
127 | + } | ||
128 | + if (ruleChainTypesMethodAvailable) { | ||
129 | + if (ruleChainTypeContainsArray(RuleChainType.CORE, ruleNodeAnnotation.ruleChainTypes())) { | ||
130 | + coreComponentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component); | ||
131 | + } | ||
132 | + if (ruleChainTypeContainsArray(RuleChainType.EDGE, ruleNodeAnnotation.ruleChainTypes())) { | ||
133 | + edgeComponentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component); | ||
134 | + } | ||
135 | + } else { | ||
136 | + coreComponentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component); | ||
137 | + } | ||
124 | } | 138 | } |
125 | 139 | ||
126 | - private List<ComponentDescriptor> persist(Set<BeanDefinition> filterDefs, ComponentType type) { | ||
127 | - List<ComponentDescriptor> result = new ArrayList<>(); | ||
128 | - for (BeanDefinition def : filterDefs) { | ||
129 | - result.add(scanAndPersistComponent(def, type)); | 140 | + private boolean ruleChainTypeContainsArray(RuleChainType ruleChainType, RuleChainType[] array) { |
141 | + for (RuleChainType tmp : array) { | ||
142 | + if (ruleChainType.equals(tmp)) { | ||
143 | + return true; | ||
144 | + } | ||
130 | } | 145 | } |
131 | - return result; | 146 | + return false; |
132 | } | 147 | } |
133 | 148 | ||
134 | private ComponentDescriptor scanAndPersistComponent(BeanDefinition def, ComponentType type) { | 149 | private ComponentDescriptor scanAndPersistComponent(BeanDefinition def, ComponentType type) { |
@@ -222,25 +237,47 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | @@ -222,25 +237,47 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe | ||
222 | } | 237 | } |
223 | 238 | ||
224 | @Override | 239 | @Override |
225 | - public List<ComponentDescriptor> getComponents(ComponentType type) { | ||
226 | - if (componentsMap.containsKey(type)) { | ||
227 | - return Collections.unmodifiableList(componentsMap.get(type)); | 240 | + public List<ComponentDescriptor> getComponents(ComponentType type, RuleChainType ruleChainType) { |
241 | + if (RuleChainType.CORE.equals(ruleChainType)) { | ||
242 | + if (coreComponentsMap.containsKey(type)) { | ||
243 | + return Collections.unmodifiableList(coreComponentsMap.get(type)); | ||
244 | + } else { | ||
245 | + return Collections.emptyList(); | ||
246 | + } | ||
247 | + } else if (RuleChainType.EDGE.equals(ruleChainType)) { | ||
248 | + if (edgeComponentsMap.containsKey(type)) { | ||
249 | + return Collections.unmodifiableList(edgeComponentsMap.get(type)); | ||
250 | + } else { | ||
251 | + return Collections.emptyList(); | ||
252 | + } | ||
228 | } else { | 253 | } else { |
229 | - return Collections.emptyList(); | 254 | + log.error("Unsupported rule chain type {}", ruleChainType); |
255 | + throw new RuntimeException("Unsupported rule chain type " + ruleChainType); | ||
230 | } | 256 | } |
231 | } | 257 | } |
232 | 258 | ||
233 | @Override | 259 | @Override |
234 | - public List<ComponentDescriptor> getComponents(Set<ComponentType> types) { | ||
235 | - List<ComponentDescriptor> result = new ArrayList<>(); | ||
236 | - types.stream().filter(type -> componentsMap.containsKey(type)).forEach(type -> { | ||
237 | - result.addAll(componentsMap.get(type)); | ||
238 | - }); | ||
239 | - return Collections.unmodifiableList(result); | 260 | + public List<ComponentDescriptor> getComponents(Set<ComponentType> types, RuleChainType ruleChainType) { |
261 | + if (RuleChainType.CORE.equals(ruleChainType)) { | ||
262 | + return getComponents(types, coreComponentsMap); | ||
263 | + } else if (RuleChainType.EDGE.equals(ruleChainType)) { | ||
264 | + return getComponents(types, edgeComponentsMap); | ||
265 | + } else { | ||
266 | + log.error("Unsupported rule chain type {}", ruleChainType); | ||
267 | + throw new RuntimeException("Unsupported rule chain type " + ruleChainType); | ||
268 | + } | ||
240 | } | 269 | } |
241 | 270 | ||
242 | @Override | 271 | @Override |
243 | public Optional<ComponentDescriptor> getComponent(String clazz) { | 272 | public Optional<ComponentDescriptor> getComponent(String clazz) { |
244 | return Optional.ofNullable(components.get(clazz)); | 273 | return Optional.ofNullable(components.get(clazz)); |
245 | } | 274 | } |
275 | + | ||
276 | + private List<ComponentDescriptor> getComponents(Set<ComponentType> types, Map<ComponentType, List<ComponentDescriptor>> componentsMap) { | ||
277 | + List<ComponentDescriptor> result = new ArrayList<>(); | ||
278 | + types.stream().filter(componentsMap::containsKey).forEach(type -> { | ||
279 | + result.addAll(componentsMap.get(type)); | ||
280 | + }); | ||
281 | + return Collections.unmodifiableList(result); | ||
282 | + } | ||
246 | } | 283 | } |
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.component; | @@ -17,6 +17,7 @@ package org.thingsboard.server.service.component; | ||
17 | 17 | ||
18 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | 18 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
19 | import org.thingsboard.server.common.data.plugin.ComponentType; | 19 | import org.thingsboard.server.common.data.plugin.ComponentType; |
20 | +import org.thingsboard.server.common.data.rule.RuleChainType; | ||
20 | 21 | ||
21 | import java.util.List; | 22 | import java.util.List; |
22 | import java.util.Optional; | 23 | import java.util.Optional; |
@@ -29,10 +30,9 @@ public interface ComponentDiscoveryService { | @@ -29,10 +30,9 @@ public interface ComponentDiscoveryService { | ||
29 | 30 | ||
30 | void discoverComponents(); | 31 | void discoverComponents(); |
31 | 32 | ||
32 | - List<ComponentDescriptor> getComponents(ComponentType type); | 33 | + List<ComponentDescriptor> getComponents(ComponentType type, RuleChainType ruleChainType); |
33 | 34 | ||
34 | - List<ComponentDescriptor> getComponents(Set<ComponentType> types); | 35 | + List<ComponentDescriptor> getComponents(Set<ComponentType> types, RuleChainType ruleChainType); |
35 | 36 | ||
36 | Optional<ComponentDescriptor> getComponent(String clazz); | 37 | Optional<ComponentDescriptor> getComponent(String clazz); |
37 | - | ||
38 | } | 38 | } |
application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.service.edge; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
19 | +import com.fasterxml.jackson.databind.JsonNode; | ||
20 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
21 | +import com.google.common.util.concurrent.FutureCallback; | ||
22 | +import com.google.common.util.concurrent.Futures; | ||
23 | +import com.google.common.util.concurrent.ListenableFuture; | ||
24 | +import lombok.extern.slf4j.Slf4j; | ||
25 | +import org.checkerframework.checker.nullness.qual.Nullable; | ||
26 | +import org.springframework.beans.factory.annotation.Autowired; | ||
27 | +import org.springframework.stereotype.Service; | ||
28 | +import org.thingsboard.server.common.data.EdgeUtils; | ||
29 | +import org.thingsboard.server.common.data.EntityType; | ||
30 | +import org.thingsboard.server.common.data.User; | ||
31 | +import org.thingsboard.server.common.data.alarm.Alarm; | ||
32 | +import org.thingsboard.server.common.data.edge.Edge; | ||
33 | +import org.thingsboard.server.common.data.edge.EdgeEvent; | ||
34 | +import org.thingsboard.server.common.data.edge.EdgeEventActionType; | ||
35 | +import org.thingsboard.server.common.data.edge.EdgeEventType; | ||
36 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
37 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
38 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
39 | +import org.thingsboard.server.common.data.id.EntityId; | ||
40 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | ||
41 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
42 | +import org.thingsboard.server.common.data.id.TenantId; | ||
43 | +import org.thingsboard.server.common.data.page.PageData; | ||
44 | +import org.thingsboard.server.common.data.page.PageLink; | ||
45 | +import org.thingsboard.server.common.data.page.TimePageLink; | ||
46 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
47 | +import org.thingsboard.server.common.data.rule.RuleChain; | ||
48 | +import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; | ||
49 | +import org.thingsboard.server.common.msg.queue.TbCallback; | ||
50 | +import org.thingsboard.server.dao.alarm.AlarmService; | ||
51 | +import org.thingsboard.server.dao.edge.EdgeEventService; | ||
52 | +import org.thingsboard.server.dao.edge.EdgeService; | ||
53 | +import org.thingsboard.server.dao.rule.RuleChainService; | ||
54 | +import org.thingsboard.server.dao.user.UserService; | ||
55 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
56 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
57 | +import org.thingsboard.server.service.executors.DbCallbackExecutorService; | ||
58 | +import org.thingsboard.server.service.queue.TbClusterService; | ||
59 | + | ||
60 | +import javax.annotation.PostConstruct; | ||
61 | +import javax.annotation.PreDestroy; | ||
62 | +import java.io.IOException; | ||
63 | +import java.util.ArrayList; | ||
64 | +import java.util.HashSet; | ||
65 | +import java.util.List; | ||
66 | +import java.util.Set; | ||
67 | +import java.util.UUID; | ||
68 | +import java.util.concurrent.ExecutorService; | ||
69 | +import java.util.concurrent.Executors; | ||
70 | + | ||
71 | +@Service | ||
72 | +@TbCoreComponent | ||
73 | +@Slf4j | ||
74 | +public class DefaultEdgeNotificationService implements EdgeNotificationService { | ||
75 | + | ||
76 | + private static final ObjectMapper mapper = new ObjectMapper(); | ||
77 | + | ||
78 | + private static final int DEFAULT_LIMIT = 100; | ||
79 | + | ||
80 | + @Autowired | ||
81 | + private EdgeService edgeService; | ||
82 | + | ||
83 | + @Autowired | ||
84 | + private AlarmService alarmService; | ||
85 | + | ||
86 | + @Autowired | ||
87 | + private UserService userService; | ||
88 | + | ||
89 | + @Autowired | ||
90 | + private RuleChainService ruleChainService; | ||
91 | + | ||
92 | + @Autowired | ||
93 | + private EdgeEventService edgeEventService; | ||
94 | + | ||
95 | + @Autowired | ||
96 | + private TbClusterService clusterService; | ||
97 | + | ||
98 | + @Autowired | ||
99 | + private DbCallbackExecutorService dbCallbackExecutorService; | ||
100 | + | ||
101 | + private ExecutorService tsCallBackExecutor; | ||
102 | + | ||
103 | + @PostConstruct | ||
104 | + public void initExecutor() { | ||
105 | + tsCallBackExecutor = Executors.newSingleThreadExecutor(); | ||
106 | + } | ||
107 | + | ||
108 | + @PreDestroy | ||
109 | + public void shutdownExecutor() { | ||
110 | + if (tsCallBackExecutor != null) { | ||
111 | + tsCallBackExecutor.shutdownNow(); | ||
112 | + } | ||
113 | + } | ||
114 | + | ||
115 | + @Override | ||
116 | + public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException { | ||
117 | + edge.setRootRuleChainId(ruleChainId); | ||
118 | + Edge savedEdge = edgeService.saveEdge(edge); | ||
119 | + saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, EdgeEventActionType.UPDATED, ruleChainId, null); | ||
120 | + return savedEdge; | ||
121 | + } | ||
122 | + | ||
123 | + private void saveEdgeEvent(TenantId tenantId, | ||
124 | + EdgeId edgeId, | ||
125 | + EdgeEventType type, | ||
126 | + EdgeEventActionType action, | ||
127 | + EntityId entityId, | ||
128 | + JsonNode body) { | ||
129 | + log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]", | ||
130 | + tenantId, edgeId, type, action, entityId, body); | ||
131 | + | ||
132 | + EdgeEvent edgeEvent = new EdgeEvent(); | ||
133 | + edgeEvent.setEdgeId(edgeId); | ||
134 | + edgeEvent.setTenantId(tenantId); | ||
135 | + edgeEvent.setType(type); | ||
136 | + edgeEvent.setAction(action); | ||
137 | + if (entityId != null) { | ||
138 | + edgeEvent.setEntityId(entityId.getId()); | ||
139 | + } | ||
140 | + edgeEvent.setBody(body); | ||
141 | + ListenableFuture<EdgeEvent> future = edgeEventService.saveAsync(edgeEvent); | ||
142 | + Futures.addCallback(future, new FutureCallback<EdgeEvent>() { | ||
143 | + @Override | ||
144 | + public void onSuccess(@Nullable EdgeEvent result) { | ||
145 | + clusterService.onEdgeEventUpdate(tenantId, edgeId); | ||
146 | + } | ||
147 | + | ||
148 | + @Override | ||
149 | + public void onFailure(Throwable t) { | ||
150 | + log.warn("[{}] Can't save edge event [{}] for edge [{}]", tenantId.getId(), edgeEvent, edgeId.getId(), t); | ||
151 | + } | ||
152 | + }, dbCallbackExecutorService); | ||
153 | + | ||
154 | + } | ||
155 | + | ||
156 | + @Override | ||
157 | + public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { | ||
158 | + try { | ||
159 | + TenantId tenantId = new TenantId(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); | ||
160 | + EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); | ||
161 | + switch (type) { | ||
162 | + case EDGE: | ||
163 | + processEdge(tenantId, edgeNotificationMsg); | ||
164 | + break; | ||
165 | + case USER: | ||
166 | + case ASSET: | ||
167 | + case DEVICE: | ||
168 | + case DEVICE_PROFILE: | ||
169 | + case ENTITY_VIEW: | ||
170 | + case DASHBOARD: | ||
171 | + case RULE_CHAIN: | ||
172 | + processEntity(tenantId, edgeNotificationMsg); | ||
173 | + break; | ||
174 | + case CUSTOMER: | ||
175 | + processCustomer(tenantId, edgeNotificationMsg); | ||
176 | + break; | ||
177 | + case WIDGETS_BUNDLE: | ||
178 | + case WIDGET_TYPE: | ||
179 | + processWidgetBundleOrWidgetType(tenantId, edgeNotificationMsg); | ||
180 | + break; | ||
181 | + case ALARM: | ||
182 | + processAlarm(tenantId, edgeNotificationMsg); | ||
183 | + break; | ||
184 | + case RELATION: | ||
185 | + processRelation(tenantId, edgeNotificationMsg); | ||
186 | + break; | ||
187 | + default: | ||
188 | + log.debug("Edge event type [{}] is not designed to be pushed to edge", type); | ||
189 | + } | ||
190 | + } catch (Exception e) { | ||
191 | + callback.onFailure(e); | ||
192 | + log.error("Can't push to edge updates, edgeNotificationMsg [{}]", edgeNotificationMsg, e); | ||
193 | + } finally { | ||
194 | + callback.onSuccess(); | ||
195 | + } | ||
196 | + } | ||
197 | + | ||
198 | + private void processEdge(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { | ||
199 | + try { | ||
200 | + EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); | ||
201 | + EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); | ||
202 | + ListenableFuture<Edge> edgeFuture; | ||
203 | + switch (actionType) { | ||
204 | + case ASSIGNED_TO_CUSTOMER: | ||
205 | + CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class); | ||
206 | + edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId); | ||
207 | + Futures.addCallback(edgeFuture, new FutureCallback<Edge>() { | ||
208 | + @Override | ||
209 | + public void onSuccess(@Nullable Edge edge) { | ||
210 | + if (edge != null && !customerId.isNullUid()) { | ||
211 | + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null); | ||
212 | + PageLink pageLink = new PageLink(DEFAULT_LIMIT); | ||
213 | + PageData<User> pageData; | ||
214 | + do { | ||
215 | + pageData = userService.findCustomerUsers(tenantId, customerId, pageLink); | ||
216 | + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { | ||
217 | + log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size()); | ||
218 | + for (User user : pageData.getData()) { | ||
219 | + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null); | ||
220 | + } | ||
221 | + if (pageData.hasNext()) { | ||
222 | + pageLink = pageLink.nextPageLink(); | ||
223 | + } | ||
224 | + } | ||
225 | + } while (pageData != null && pageData.hasNext()); | ||
226 | + } | ||
227 | + } | ||
228 | + | ||
229 | + @Override | ||
230 | + public void onFailure(Throwable t) { | ||
231 | + log.error("Can't find edge by id [{}]", edgeNotificationMsg, t); | ||
232 | + } | ||
233 | + }, dbCallbackExecutorService); | ||
234 | + break; | ||
235 | + case UNASSIGNED_FROM_CUSTOMER: | ||
236 | + CustomerId customerIdToDelete = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class); | ||
237 | + edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId); | ||
238 | + Futures.addCallback(edgeFuture, new FutureCallback<Edge>() { | ||
239 | + @Override | ||
240 | + public void onSuccess(@Nullable Edge edge) { | ||
241 | + if (edge != null && !customerIdToDelete.isNullUid()) { | ||
242 | + saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.DELETED, customerIdToDelete, null); | ||
243 | + } | ||
244 | + } | ||
245 | + | ||
246 | + @Override | ||
247 | + public void onFailure(Throwable t) { | ||
248 | + log.error("Can't find edge by id [{}]", edgeNotificationMsg, t); | ||
249 | + } | ||
250 | + }, dbCallbackExecutorService); | ||
251 | + break; | ||
252 | + } | ||
253 | + } catch (Exception e) { | ||
254 | + log.error("Exception during processing edge event", e); | ||
255 | + } | ||
256 | + } | ||
257 | + | ||
258 | + private void processWidgetBundleOrWidgetType(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { | ||
259 | + EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); | ||
260 | + EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); | ||
261 | + EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); | ||
262 | + switch (actionType) { | ||
263 | + case ADDED: | ||
264 | + case UPDATED: | ||
265 | + case DELETED: | ||
266 | + processActionForAllEdges(tenantId, type, actionType, entityId); | ||
267 | + break; | ||
268 | + } | ||
269 | + } | ||
270 | + | ||
271 | + private void processCustomer(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { | ||
272 | + EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); | ||
273 | + EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); | ||
274 | + UUID uuid = new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()); | ||
275 | + CustomerId customerId = new CustomerId(EntityIdFactory.getByEdgeEventTypeAndUuid(type, uuid).getId()); | ||
276 | + switch (actionType) { | ||
277 | + case UPDATED: | ||
278 | + PageLink pageLink = new PageLink(DEFAULT_LIMIT); | ||
279 | + PageData<Edge> pageData; | ||
280 | + do { | ||
281 | + pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); | ||
282 | + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { | ||
283 | + for (Edge edge : pageData.getData()) { | ||
284 | + saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null); | ||
285 | + } | ||
286 | + if (pageData.hasNext()) { | ||
287 | + pageLink = pageLink.nextPageLink(); | ||
288 | + } | ||
289 | + } | ||
290 | + } while (pageData != null && pageData.hasNext()); | ||
291 | + break; | ||
292 | + case DELETED: | ||
293 | + EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); | ||
294 | + saveEdgeEvent(tenantId, edgeId, type, actionType, customerId, null); | ||
295 | + break; | ||
296 | + } | ||
297 | + } | ||
298 | + | ||
299 | + private void processEntity(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { | ||
300 | + EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); | ||
301 | + EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); | ||
302 | + EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, | ||
303 | + new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); | ||
304 | + EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); | ||
305 | + ListenableFuture<List<EdgeId>> edgeIdsFuture; | ||
306 | + switch (actionType) { | ||
307 | + case ADDED: // used only for USER entity | ||
308 | + case UPDATED: | ||
309 | + case CREDENTIALS_UPDATED: | ||
310 | + edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId); | ||
311 | + Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() { | ||
312 | + @Override | ||
313 | + public void onSuccess(@Nullable List<EdgeId> edgeIds) { | ||
314 | + if (edgeIds != null && !edgeIds.isEmpty()) { | ||
315 | + for (EdgeId edgeId : edgeIds) { | ||
316 | + saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); | ||
317 | + } | ||
318 | + } | ||
319 | + } | ||
320 | + @Override | ||
321 | + public void onFailure(Throwable throwable) { | ||
322 | + log.error("Failed to find related edge ids [{}]", edgeNotificationMsg, throwable); | ||
323 | + } | ||
324 | + }, dbCallbackExecutorService); | ||
325 | + break; | ||
326 | + case ASSIGNED_TO_CUSTOMER: | ||
327 | + case UNASSIGNED_FROM_CUSTOMER: | ||
328 | + edgeIdsFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId); | ||
329 | + Futures.addCallback(edgeIdsFuture, new FutureCallback<List<EdgeId>>() { | ||
330 | + @Override | ||
331 | + public void onSuccess(@Nullable List<EdgeId> edgeIds) { | ||
332 | + if (edgeIds != null && !edgeIds.isEmpty()) { | ||
333 | + for (EdgeId edgeId : edgeIds) { | ||
334 | + try { | ||
335 | + CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class); | ||
336 | + ListenableFuture<Edge> future = edgeService.findEdgeByIdAsync(tenantId, edgeId); | ||
337 | + Futures.addCallback(future, new FutureCallback<Edge>() { | ||
338 | + @Override | ||
339 | + public void onSuccess(@Nullable Edge edge) { | ||
340 | + if (edge != null && edge.getCustomerId() != null && | ||
341 | + !edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(customerId)) { | ||
342 | + saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); | ||
343 | + } | ||
344 | + } | ||
345 | + @Override | ||
346 | + public void onFailure(Throwable throwable) { | ||
347 | + log.error("Failed to find edge by id [{}]", edgeNotificationMsg, throwable); | ||
348 | + } | ||
349 | + }, dbCallbackExecutorService); | ||
350 | + } catch (Exception e) { | ||
351 | + log.error("Can't parse customer id from entity body [{}]", edgeNotificationMsg, e); | ||
352 | + } | ||
353 | + } | ||
354 | + } | ||
355 | + } | ||
356 | + | ||
357 | + @Override | ||
358 | + public void onFailure(Throwable throwable) { | ||
359 | + log.error("Failed to find related edge ids [{}]", edgeNotificationMsg, throwable); | ||
360 | + } | ||
361 | + }, dbCallbackExecutorService); | ||
362 | + break; | ||
363 | + case DELETED: | ||
364 | + saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); | ||
365 | + break; | ||
366 | + case ASSIGNED_TO_EDGE: | ||
367 | + case UNASSIGNED_FROM_EDGE: | ||
368 | + saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); | ||
369 | + if (type.equals(EdgeEventType.RULE_CHAIN)) { | ||
370 | + updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId); | ||
371 | + } | ||
372 | + break; | ||
373 | + } | ||
374 | + } | ||
375 | + | ||
376 | + private void updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) { | ||
377 | + PageLink pageLink = new PageLink(DEFAULT_LIMIT); | ||
378 | + PageData<RuleChain> pageData; | ||
379 | + do { | ||
380 | + pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); | ||
381 | + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { | ||
382 | + for (RuleChain ruleChain : pageData.getData()) { | ||
383 | + if (!ruleChain.getId().equals(processingRuleChainId)) { | ||
384 | + List<RuleChainConnectionInfo> connectionInfos = | ||
385 | + ruleChainService.loadRuleChainMetaData(ruleChain.getTenantId(), ruleChain.getId()).getRuleChainConnections(); | ||
386 | + if (connectionInfos != null && !connectionInfos.isEmpty()) { | ||
387 | + for (RuleChainConnectionInfo connectionInfo : connectionInfos) { | ||
388 | + if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) { | ||
389 | + saveEdgeEvent(tenantId, | ||
390 | + edgeId, | ||
391 | + EdgeEventType.RULE_CHAIN_METADATA, | ||
392 | + EdgeEventActionType.UPDATED, | ||
393 | + ruleChain.getId(), | ||
394 | + null); | ||
395 | + } | ||
396 | + } | ||
397 | + } | ||
398 | + } | ||
399 | + } | ||
400 | + if (pageData.hasNext()) { | ||
401 | + pageLink = pageLink.nextPageLink(); | ||
402 | + } | ||
403 | + } | ||
404 | + } while (pageData != null && pageData.hasNext()); | ||
405 | + } | ||
406 | + | ||
407 | + private void processAlarm(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { | ||
408 | + AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); | ||
409 | + ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId); | ||
410 | + Futures.addCallback(alarmFuture, new FutureCallback<Alarm>() { | ||
411 | + @Override | ||
412 | + public void onSuccess(@Nullable Alarm alarm) { | ||
413 | + if (alarm != null) { | ||
414 | + EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType()); | ||
415 | + if (type != null) { | ||
416 | + ListenableFuture<List<EdgeId>> relatedEdgeIdsByEntityIdFuture = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator()); | ||
417 | + Futures.addCallback(relatedEdgeIdsByEntityIdFuture, new FutureCallback<List<EdgeId>>() { | ||
418 | + @Override | ||
419 | + public void onSuccess(@Nullable List<EdgeId> relatedEdgeIdsByEntityId) { | ||
420 | + if (relatedEdgeIdsByEntityId != null) { | ||
421 | + for (EdgeId edgeId : relatedEdgeIdsByEntityId) { | ||
422 | + saveEdgeEvent(tenantId, | ||
423 | + edgeId, | ||
424 | + EdgeEventType.ALARM, | ||
425 | + EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()), | ||
426 | + alarmId, | ||
427 | + null); | ||
428 | + } | ||
429 | + } | ||
430 | + } | ||
431 | + | ||
432 | + @Override | ||
433 | + public void onFailure(Throwable t) { | ||
434 | + log.warn("[{}] can't find related edge ids by entity id [{}]", tenantId.getId(), alarm.getOriginator(), t); | ||
435 | + } | ||
436 | + }, dbCallbackExecutorService); | ||
437 | + } | ||
438 | + } | ||
439 | + } | ||
440 | + | ||
441 | + @Override | ||
442 | + public void onFailure(Throwable t) { | ||
443 | + log.warn("[{}] can't find alarm by id [{}]", tenantId.getId(), alarmId.getId(), t); | ||
444 | + } | ||
445 | + }, dbCallbackExecutorService); | ||
446 | + } | ||
447 | + | ||
448 | + private void processRelation(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException { | ||
449 | + EntityRelation relation = mapper.readValue(edgeNotificationMsg.getBody(), EntityRelation.class); | ||
450 | + if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && | ||
451 | + !relation.getTo().getEntityType().equals(EntityType.EDGE)) { | ||
452 | + List<ListenableFuture<List<EdgeId>>> futures = new ArrayList<>(); | ||
453 | + futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getTo())); | ||
454 | + futures.add(edgeService.findRelatedEdgeIdsByEntityId(tenantId, relation.getFrom())); | ||
455 | + ListenableFuture<List<List<EdgeId>>> combinedFuture = Futures.allAsList(futures); | ||
456 | + Futures.addCallback(combinedFuture, new FutureCallback<List<List<EdgeId>>>() { | ||
457 | + @Override | ||
458 | + public void onSuccess(@Nullable List<List<EdgeId>> listOfListsEdgeIds) { | ||
459 | + Set<EdgeId> uniqueEdgeIds = new HashSet<>(); | ||
460 | + if (listOfListsEdgeIds != null && !listOfListsEdgeIds.isEmpty()) { | ||
461 | + for (List<EdgeId> listOfListsEdgeId : listOfListsEdgeIds) { | ||
462 | + if (listOfListsEdgeId != null) { | ||
463 | + uniqueEdgeIds.addAll(listOfListsEdgeId); | ||
464 | + } | ||
465 | + } | ||
466 | + } | ||
467 | + if (!uniqueEdgeIds.isEmpty()) { | ||
468 | + for (EdgeId edgeId : uniqueEdgeIds) { | ||
469 | + saveEdgeEvent(tenantId, | ||
470 | + edgeId, | ||
471 | + EdgeEventType.RELATION, | ||
472 | + EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()), | ||
473 | + null, | ||
474 | + mapper.valueToTree(relation)); | ||
475 | + } | ||
476 | + } | ||
477 | + } | ||
478 | + | ||
479 | + @Override | ||
480 | + public void onFailure(Throwable t) { | ||
481 | + log.warn("[{}] can't find related edge ids by relation to id [{}] and relation from id [{}]" , | ||
482 | + tenantId.getId(), relation.getTo().getId(), relation.getFrom().getId(), t); | ||
483 | + } | ||
484 | + }, dbCallbackExecutorService); | ||
485 | + } | ||
486 | + } | ||
487 | + | ||
488 | + private void processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) { | ||
489 | + PageLink pageLink = new PageLink(DEFAULT_LIMIT); | ||
490 | + PageData<Edge> pageData; | ||
491 | + do { | ||
492 | + pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); | ||
493 | + if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { | ||
494 | + for (Edge edge : pageData.getData()) { | ||
495 | + saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null); | ||
496 | + } | ||
497 | + if (pageData.hasNext()) { | ||
498 | + pageLink = pageLink.nextPageLink(); | ||
499 | + } | ||
500 | + } | ||
501 | + } while (pageData != null && pageData.hasNext()); | ||
502 | + } | ||
503 | +} | ||
504 | + | ||
505 | + |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.service.edge; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import lombok.Getter; | ||
20 | +import org.springframework.beans.factory.annotation.Autowired; | ||
21 | +import org.springframework.context.annotation.Lazy; | ||
22 | +import org.springframework.stereotype.Component; | ||
23 | +import org.thingsboard.server.actors.service.ActorService; | ||
24 | +import org.thingsboard.server.dao.alarm.AlarmService; | ||
25 | +import org.thingsboard.server.dao.asset.AssetService; | ||
26 | +import org.thingsboard.server.dao.attributes.AttributesService; | ||
27 | +import org.thingsboard.server.dao.customer.CustomerService; | ||
28 | +import org.thingsboard.server.dao.dashboard.DashboardService; | ||
29 | +import org.thingsboard.server.dao.device.DeviceCredentialsService; | ||
30 | +import org.thingsboard.server.dao.device.DeviceProfileService; | ||
31 | +import org.thingsboard.server.dao.device.DeviceService; | ||
32 | +import org.thingsboard.server.dao.edge.EdgeEventService; | ||
33 | +import org.thingsboard.server.dao.edge.EdgeService; | ||
34 | +import org.thingsboard.server.dao.entityview.EntityViewService; | ||
35 | +import org.thingsboard.server.dao.relation.RelationService; | ||
36 | +import org.thingsboard.server.dao.rule.RuleChainService; | ||
37 | +import org.thingsboard.server.dao.user.UserService; | ||
38 | +import org.thingsboard.server.dao.widget.WidgetTypeService; | ||
39 | +import org.thingsboard.server.dao.widget.WidgetsBundleService; | ||
40 | +import org.thingsboard.server.queue.discovery.PartitionService; | ||
41 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
42 | +import org.thingsboard.server.service.edge.rpc.EdgeEventStorageSettings; | ||
43 | +import org.thingsboard.server.service.edge.rpc.constructor.AdminSettingsMsgConstructor; | ||
44 | +import org.thingsboard.server.service.edge.rpc.constructor.AlarmMsgConstructor; | ||
45 | +import org.thingsboard.server.service.edge.rpc.constructor.AssetMsgConstructor; | ||
46 | +import org.thingsboard.server.service.edge.rpc.constructor.CustomerMsgConstructor; | ||
47 | +import org.thingsboard.server.service.edge.rpc.constructor.DashboardMsgConstructor; | ||
48 | +import org.thingsboard.server.service.edge.rpc.constructor.DeviceMsgConstructor; | ||
49 | +import org.thingsboard.server.service.edge.rpc.constructor.DeviceProfileMsgConstructor; | ||
50 | +import org.thingsboard.server.service.edge.rpc.constructor.EntityDataMsgConstructor; | ||
51 | +import org.thingsboard.server.service.edge.rpc.constructor.EntityViewMsgConstructor; | ||
52 | +import org.thingsboard.server.service.edge.rpc.constructor.RelationMsgConstructor; | ||
53 | +import org.thingsboard.server.service.edge.rpc.constructor.RuleChainMsgConstructor; | ||
54 | +import org.thingsboard.server.service.edge.rpc.constructor.UserMsgConstructor; | ||
55 | +import org.thingsboard.server.service.edge.rpc.constructor.WidgetTypeMsgConstructor; | ||
56 | +import org.thingsboard.server.service.edge.rpc.constructor.WidgetsBundleMsgConstructor; | ||
57 | +import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService; | ||
58 | +import org.thingsboard.server.service.edge.rpc.processor.AlarmProcessor; | ||
59 | +import org.thingsboard.server.service.edge.rpc.processor.DeviceProcessor; | ||
60 | +import org.thingsboard.server.service.edge.rpc.processor.RelationProcessor; | ||
61 | +import org.thingsboard.server.service.edge.rpc.processor.TelemetryProcessor; | ||
62 | +import org.thingsboard.server.service.executors.DbCallbackExecutorService; | ||
63 | +import org.thingsboard.server.service.queue.TbClusterService; | ||
64 | +import org.thingsboard.server.service.state.DeviceStateService; | ||
65 | + | ||
66 | +@Component | ||
67 | +@TbCoreComponent | ||
68 | +@Data | ||
69 | +public class EdgeContextComponent { | ||
70 | + | ||
71 | + @Lazy | ||
72 | + @Autowired | ||
73 | + private EdgeService edgeService; | ||
74 | + | ||
75 | + @Autowired | ||
76 | + private PartitionService partitionService; | ||
77 | + | ||
78 | + @Lazy | ||
79 | + @Autowired | ||
80 | + private EdgeEventService edgeEventService; | ||
81 | + | ||
82 | + @Lazy | ||
83 | + @Autowired | ||
84 | + private AssetService assetService; | ||
85 | + | ||
86 | + @Lazy | ||
87 | + @Autowired | ||
88 | + private DeviceService deviceService; | ||
89 | + | ||
90 | + @Lazy | ||
91 | + @Autowired | ||
92 | + private DeviceProfileService deviceProfileService; | ||
93 | + | ||
94 | + @Lazy | ||
95 | + @Autowired | ||
96 | + private DeviceCredentialsService deviceCredentialsService; | ||
97 | + | ||
98 | + @Lazy | ||
99 | + @Autowired | ||
100 | + private EntityViewService entityViewService; | ||
101 | + | ||
102 | + @Lazy | ||
103 | + @Autowired | ||
104 | + private AttributesService attributesService; | ||
105 | + | ||
106 | + @Lazy | ||
107 | + @Autowired | ||
108 | + private CustomerService customerService; | ||
109 | + | ||
110 | + @Lazy | ||
111 | + @Autowired | ||
112 | + private RelationService relationService; | ||
113 | + | ||
114 | + @Lazy | ||
115 | + @Autowired | ||
116 | + private AlarmService alarmService; | ||
117 | + | ||
118 | + @Lazy | ||
119 | + @Autowired | ||
120 | + private DashboardService dashboardService; | ||
121 | + | ||
122 | + @Lazy | ||
123 | + @Autowired | ||
124 | + private RuleChainService ruleChainService; | ||
125 | + | ||
126 | + @Lazy | ||
127 | + @Autowired | ||
128 | + private UserService userService; | ||
129 | + | ||
130 | + @Lazy | ||
131 | + @Autowired | ||
132 | + private ActorService actorService; | ||
133 | + | ||
134 | + @Lazy | ||
135 | + @Autowired | ||
136 | + private WidgetsBundleService widgetsBundleService; | ||
137 | + | ||
138 | + @Lazy | ||
139 | + @Autowired | ||
140 | + private WidgetTypeService widgetTypeService; | ||
141 | + | ||
142 | + @Lazy | ||
143 | + @Autowired | ||
144 | + private DeviceStateService deviceStateService; | ||
145 | + | ||
146 | + @Lazy | ||
147 | + @Autowired | ||
148 | + private TbClusterService tbClusterService; | ||
149 | + | ||
150 | + @Lazy | ||
151 | + @Autowired | ||
152 | + private SyncEdgeService syncEdgeService; | ||
153 | + | ||
154 | + @Lazy | ||
155 | + @Autowired | ||
156 | + private RuleChainMsgConstructor ruleChainMsgConstructor; | ||
157 | + | ||
158 | + @Lazy | ||
159 | + @Autowired | ||
160 | + private AlarmMsgConstructor alarmMsgConstructor; | ||
161 | + | ||
162 | + @Lazy | ||
163 | + @Autowired | ||
164 | + private DeviceMsgConstructor deviceMsgConstructor; | ||
165 | + | ||
166 | + @Lazy | ||
167 | + @Autowired | ||
168 | + private DeviceProfileMsgConstructor deviceProfileMsgConstructor; | ||
169 | + | ||
170 | + @Lazy | ||
171 | + @Autowired | ||
172 | + private AssetMsgConstructor assetMsgConstructor; | ||
173 | + | ||
174 | + @Lazy | ||
175 | + @Autowired | ||
176 | + private EntityViewMsgConstructor entityViewMsgConstructor; | ||
177 | + | ||
178 | + @Lazy | ||
179 | + @Autowired | ||
180 | + private DashboardMsgConstructor dashboardMsgConstructor; | ||
181 | + | ||
182 | + @Lazy | ||
183 | + @Autowired | ||
184 | + private CustomerMsgConstructor customerMsgConstructor; | ||
185 | + | ||
186 | + @Lazy | ||
187 | + @Autowired | ||
188 | + private UserMsgConstructor userMsgConstructor; | ||
189 | + | ||
190 | + @Lazy | ||
191 | + @Autowired | ||
192 | + private RelationMsgConstructor relationMsgConstructor; | ||
193 | + | ||
194 | + @Lazy | ||
195 | + @Autowired | ||
196 | + private WidgetsBundleMsgConstructor widgetsBundleMsgConstructor; | ||
197 | + | ||
198 | + @Lazy | ||
199 | + @Autowired | ||
200 | + private WidgetTypeMsgConstructor widgetTypeMsgConstructor; | ||
201 | + | ||
202 | + @Lazy | ||
203 | + @Autowired | ||
204 | + private AdminSettingsMsgConstructor adminSettingsMsgConstructor; | ||
205 | + | ||
206 | + @Lazy | ||
207 | + @Autowired | ||
208 | + private EntityDataMsgConstructor entityDataMsgConstructor; | ||
209 | + | ||
210 | + @Lazy | ||
211 | + @Autowired | ||
212 | + private AlarmProcessor alarmProcessor; | ||
213 | + | ||
214 | + @Lazy | ||
215 | + @Autowired | ||
216 | + private DeviceProcessor deviceProcessor; | ||
217 | + | ||
218 | + @Lazy | ||
219 | + @Autowired | ||
220 | + private RelationProcessor relationProcessor; | ||
221 | + | ||
222 | + @Lazy | ||
223 | + @Autowired | ||
224 | + private TelemetryProcessor telemetryProcessor; | ||
225 | + | ||
226 | + @Lazy | ||
227 | + @Autowired | ||
228 | + private EdgeEventStorageSettings edgeEventStorageSettings; | ||
229 | + | ||
230 | + @Autowired | ||
231 | + @Getter | ||
232 | + private DbCallbackExecutorService dbCallbackExecutor; | ||
233 | +} |
application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.service.edge; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.edge.Edge; | ||
19 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
20 | +import org.thingsboard.server.common.data.id.TenantId; | ||
21 | +import org.thingsboard.server.common.msg.queue.TbCallback; | ||
22 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
23 | + | ||
24 | +import java.io.IOException; | ||
25 | + | ||
26 | +public interface EdgeNotificationService { | ||
27 | + | ||
28 | + Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException; | ||
29 | + | ||
30 | + void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback); | ||
31 | +} |
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeEventStorageSettings.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.service.edge.rpc; | ||
17 | + | ||
18 | + | ||
19 | +import lombok.Data; | ||
20 | +import org.springframework.beans.factory.annotation.Value; | ||
21 | +import org.springframework.stereotype.Component; | ||
22 | + | ||
23 | +@Component | ||
24 | +@Data | ||
25 | +public class EdgeEventStorageSettings { | ||
26 | + @Value("${edges.storage.max_read_records_count}") | ||
27 | + private int maxReadRecordsCount; | ||
28 | + @Value("${edges.storage.no_read_records_sleep}") | ||
29 | + private long noRecordsSleepInterval; | ||
30 | + @Value("${edges.storage.sleep_between_batches}") | ||
31 | + private long sleepIntervalBetweenBatches; | ||
32 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 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.service.edge.rpc; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
19 | +import com.google.common.io.Resources; | ||
20 | +import com.google.common.util.concurrent.FutureCallback; | ||
21 | +import io.grpc.Server; | ||
22 | +import io.grpc.netty.NettyServerBuilder; | ||
23 | +import io.grpc.stub.StreamObserver; | ||
24 | +import lombok.extern.slf4j.Slf4j; | ||
25 | +import org.springframework.beans.factory.annotation.Autowired; | ||
26 | +import org.springframework.beans.factory.annotation.Value; | ||
27 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
28 | +import org.springframework.stereotype.Service; | ||
29 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | ||
30 | +import org.thingsboard.server.common.data.DataConstants; | ||
31 | +import org.thingsboard.server.common.data.Tenant; | ||
32 | +import org.thingsboard.server.common.data.edge.Edge; | ||
33 | +import org.thingsboard.server.common.data.id.EdgeId; | ||
34 | +import org.thingsboard.server.common.data.id.TenantId; | ||
35 | +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; | ||
36 | +import org.thingsboard.server.common.data.kv.BooleanDataEntry; | ||
37 | +import org.thingsboard.server.common.data.kv.LongDataEntry; | ||
38 | +import org.thingsboard.server.gen.edge.EdgeRpcServiceGrpc; | ||
39 | +import org.thingsboard.server.gen.edge.RequestMsg; | ||
40 | +import org.thingsboard.server.gen.edge.ResponseMsg; | ||
41 | +import org.thingsboard.server.queue.util.TbCoreComponent; | ||
42 | +import org.thingsboard.server.service.edge.EdgeContextComponent; | ||
43 | +import org.thingsboard.server.service.state.DefaultDeviceStateService; | ||
44 | +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | ||
45 | + | ||
46 | +import javax.annotation.Nullable; | ||
47 | +import javax.annotation.PostConstruct; | ||
48 | +import javax.annotation.PreDestroy; | ||
49 | +import java.io.File; | ||
50 | +import java.io.IOException; | ||
51 | +import java.util.Collections; | ||
52 | +import java.util.Map; | ||
53 | +import java.util.UUID; | ||
54 | +import java.util.concurrent.ConcurrentHashMap; | ||
55 | +import java.util.concurrent.ConcurrentMap; | ||
56 | +import java.util.concurrent.Executors; | ||
57 | +import java.util.concurrent.ScheduledExecutorService; | ||
58 | +import java.util.concurrent.ScheduledFuture; | ||
59 | +import java.util.concurrent.TimeUnit; | ||
60 | + | ||
61 | +@Service | ||
62 | +@Slf4j | ||
63 | +@ConditionalOnProperty(prefix = "edges", value = "enabled", havingValue = "true") | ||
64 | +@TbCoreComponent | ||
65 | +public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase implements EdgeRpcService { | ||
66 | + | ||
67 | + private final ConcurrentMap<EdgeId, EdgeGrpcSession> sessions = new ConcurrentHashMap<>(); | ||
68 | + private final ConcurrentMap<EdgeId, Boolean> sessionNewEvents = new ConcurrentHashMap<>(); | ||
69 | + private final ConcurrentMap<EdgeId, ScheduledFuture<?>> sessionEdgeEventChecks = new ConcurrentHashMap<>(); | ||
70 | + private static final ObjectMapper mapper = new ObjectMapper(); | ||
71 | + | ||
72 | + @Value("${edges.rpc.port}") | ||
73 | + private int rpcPort; | ||
74 | + @Value("${edges.rpc.ssl.enabled}") | ||
75 | + private boolean sslEnabled; | ||
76 | + @Value("${edges.rpc.ssl.cert}") | ||
77 | + private String certFileResource; | ||
78 | + @Value("${edges.rpc.ssl.private_key}") | ||
79 | + private String privateKeyResource; | ||
80 | + @Value("${edges.state.persistToTelemetry:false}") | ||
81 | + private boolean persistToTelemetry; | ||
82 | + @Value("${edges.rpc.client_max_keep_alive_time_sec}") | ||
83 | + private int clientMaxKeepAliveTimeSec; | ||
84 | + | ||
85 | + @Value("${edges.scheduler_pool_size}") | ||
86 | + private int schedulerPoolSize; | ||
87 | + | ||
88 | + @Autowired | ||
89 | + private EdgeContextComponent ctx; | ||
90 | + | ||
91 | + @Autowired | ||
92 | + private TelemetrySubscriptionService tsSubService; | ||
93 | + | ||
94 | + private Server server; | ||
95 | + | ||
96 | + private ScheduledExecutorService scheduler; | ||
97 | + | ||
98 | + @PostConstruct | ||
99 | + public void init() { | ||
100 | + log.info("Initializing Edge RPC service!"); | ||
101 | + NettyServerBuilder builder = NettyServerBuilder.forPort(rpcPort) | ||
102 | + .permitKeepAliveTime(clientMaxKeepAliveTimeSec, TimeUnit.SECONDS) | ||
103 | + .addService(this); | ||
104 | + if (sslEnabled) { | ||
105 | + try { | ||
106 | + File certFile = new File(Resources.getResource(certFileResource).toURI()); | ||
107 | + File privateKeyFile = new File(Resources.getResource(privateKeyResource).toURI()); | ||
108 | + builder.useTransportSecurity(certFile, privateKeyFile); | ||
109 | + } catch (Exception e) { | ||
110 | + log.error("Unable to set up SSL context. Reason: " + e.getMessage(), e); | ||
111 | + throw new RuntimeException("Unable to set up SSL context!", e); | ||
112 | + } | ||
113 | + } | ||
114 | + server = builder.build(); | ||
115 | + log.info("Going to start Edge RPC server using port: {}", rpcPort); | ||
116 | + try { | ||
117 | + server.start(); | ||
118 | + } catch (IOException e) { | ||
119 | + log.error("Failed to start Edge RPC server!", e); | ||
120 | + throw new RuntimeException("Failed to start Edge RPC server!"); | ||
121 | + } | ||
122 | + this.scheduler = Executors.newScheduledThreadPool(schedulerPoolSize, ThingsBoardThreadFactory.forName("edge-scheduler")); | ||
123 | + log.info("Edge RPC service initialized!"); | ||
124 | + } | ||
125 | + | ||
126 | + @PreDestroy | ||
127 | + public void destroy() { | ||
128 | + if (server != null) { | ||
129 | + server.shutdownNow(); | ||
130 | + } | ||
131 | + for (Map.Entry<EdgeId, ScheduledFuture<?>> entry : sessionEdgeEventChecks.entrySet()) { | ||
132 | + EdgeId edgeId = entry.getKey(); | ||
133 | + ScheduledFuture<?> sessionEdgeEventCheck = entry.getValue(); | ||
134 | + if (sessionEdgeEventCheck != null && !sessionEdgeEventCheck.isCancelled() && !sessionEdgeEventCheck.isDone()) { | ||
135 | + sessionEdgeEventCheck.cancel(true); | ||
136 | + sessionEdgeEventChecks.remove(edgeId); | ||
137 | + } | ||
138 | + } | ||
139 | + if (scheduler != null) { | ||
140 | + scheduler.shutdownNow(); | ||
141 | + } | ||
142 | + } | ||
143 | + | ||
144 | + @Override | ||
145 | + public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) { | ||
146 | + return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper).getInputStream(); | ||
147 | + } | ||
148 | + | ||
149 | + @Override | ||
150 | + public void updateEdge(Edge edge) { | ||
151 | + EdgeGrpcSession session = sessions.get(edge.getId()); | ||
152 | + if (session != null && session.isConnected()) { | ||
153 | + log.debug("[{}] Updating configuration for edge [{}] [{}]", edge.getTenantId(), edge.getName(), edge.getId()); | ||
154 | + session.onConfigurationUpdate(edge); | ||
155 | + } else { | ||
156 | + log.debug("[{}] Session doesn't exist for edge [{}] [{}]", edge.getTenantId(), edge.getName(), edge.getId()); | ||
157 | + } | ||
158 | + } | ||
159 | + | ||
160 | + @Override | ||
161 | + public void deleteEdge(EdgeId edgeId) { | ||
162 | + EdgeGrpcSession session = sessions.get(edgeId); | ||
163 | + if (session != null && session.isConnected()) { | ||
164 | + log.info("Closing and removing session for edge [{}]", edgeId); | ||
165 | + session.close(); | ||
166 | + sessions.remove(edgeId); | ||
167 | + sessionNewEvents.remove(edgeId); | ||
168 | + cancelScheduleEdgeEventsCheck(edgeId); | ||
169 | + } | ||
170 | + } | ||
171 | + | ||
172 | + @Override | ||
173 | + public void onEdgeEvent(EdgeId edgeId) { | ||
174 | + log.trace("[{}] onEdgeEvent", edgeId.getId()); | ||
175 | + if (!sessionNewEvents.get(edgeId)) { | ||
176 | + log.trace("[{}] set session new events flag to true", edgeId.getId()); | ||
177 | + sessionNewEvents.put(edgeId, true); | ||
178 | + } | ||
179 | + } | ||
180 | + | ||
181 | + private void onEdgeConnect(EdgeId edgeId, EdgeGrpcSession edgeGrpcSession) { | ||
182 | + log.info("[{}] edge [{}] connected successfully.", edgeGrpcSession.getSessionId(), edgeId); | ||
183 | + sessions.put(edgeId, edgeGrpcSession); | ||
184 | + sessionNewEvents.put(edgeId, false); | ||
185 | + save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, true); | ||
186 | + save(edgeId, DefaultDeviceStateService.LAST_CONNECT_TIME, System.currentTimeMillis()); | ||
187 | + cancelScheduleEdgeEventsCheck(edgeId); | ||
188 | + scheduleEdgeEventsCheck(edgeGrpcSession); | ||
189 | + } | ||
190 | + | ||
191 | + public EdgeGrpcSession getEdgeGrpcSessionById(TenantId tenantId, EdgeId edgeId) { | ||
192 | + EdgeGrpcSession session = sessions.get(edgeId); | ||
193 | + if (session != null && session.isConnected()) { | ||
194 | + return session; | ||
195 | + } else { | ||
196 | + log.error("[{}] Edge is not connected [{}]", tenantId, edgeId); | ||
197 | + throw new RuntimeException("Edge is not connected"); | ||
198 | + } | ||
199 | + } | ||
200 | + | ||
201 | + private void scheduleEdgeEventsCheck(EdgeGrpcSession session) { | ||
202 | + EdgeId edgeId = session.getEdge().getId(); | ||
203 | + UUID tenantId = session.getEdge().getTenantId().getId(); | ||
204 | + if (sessions.containsKey(edgeId)) { | ||
205 | + ScheduledFuture<?> schedule = scheduler.schedule(() -> { | ||
206 | + try { | ||
207 | + if (sessionNewEvents.get(edgeId)) { | ||
208 | + log.trace("[{}] Set session new events flag to false", edgeId.getId()); | ||
209 | + sessionNewEvents.put(edgeId, false); | ||
210 | + session.processEdgeEvents(); | ||
211 | + } | ||
212 | + } catch (Exception e) { | ||
213 | + log.warn("[{}] Failed to process edge events for edge [{}]!", tenantId, session.getEdge().getId().getId(), e); | ||
214 | + } | ||
215 | + scheduleEdgeEventsCheck(session); | ||
216 | + }, ctx.getEdgeEventStorageSettings().getNoRecordsSleepInterval(), TimeUnit.MILLISECONDS); | ||
217 | + sessionEdgeEventChecks.put(edgeId, schedule); | ||
218 | + log.trace("[{}] Check edge event scheduled for edge [{}]", tenantId, edgeId.getId()); | ||
219 | + } else { | ||
220 | + log.debug("[{}] Session was removed and edge event check schedule must not be started [{}]", | ||
221 | + tenantId, edgeId.getId()); | ||
222 | + } | ||
223 | + } | ||
224 | + | ||
225 | + private void cancelScheduleEdgeEventsCheck(EdgeId edgeId) { | ||
226 | + log.trace("[{}] cancelling edge event check for edge", edgeId); | ||
227 | + if (sessionEdgeEventChecks.containsKey(edgeId)) { | ||
228 | + ScheduledFuture<?> sessionEdgeEventCheck = sessionEdgeEventChecks.get(edgeId); | ||
229 | + if (sessionEdgeEventCheck != null && !sessionEdgeEventCheck.isCancelled() && !sessionEdgeEventCheck.isDone()) { | ||
230 | + sessionEdgeEventCheck.cancel(true); | ||
231 | + sessionEdgeEventChecks.remove(edgeId); | ||
232 | + } | ||
233 | + } | ||
234 | + } | ||
235 | + | ||
236 | + private void onEdgeDisconnect(EdgeId edgeId) { | ||
237 | + log.info("[{}] edge disconnected!", edgeId); | ||
238 | + sessions.remove(edgeId); | ||
239 | + sessionNewEvents.remove(edgeId); | ||
240 | + save(edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); | ||
241 | + save(edgeId, DefaultDeviceStateService.LAST_DISCONNECT_TIME, System.currentTimeMillis()); | ||
242 | + cancelScheduleEdgeEventsCheck(edgeId); | ||
243 | + } | ||
244 | + | ||
245 | + private void save(EdgeId edgeId, String key, long value) { | ||
246 | + log.debug("[{}] Updating long edge telemetry [{}] [{}]", edgeId, key, value); | ||
247 | + if (persistToTelemetry) { | ||
248 | + tsSubService.saveAndNotify( | ||
249 | + TenantId.SYS_TENANT_ID, edgeId, | ||
250 | + Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new LongDataEntry(key, value))), | ||
251 | + new AttributeSaveCallback(edgeId, key, value)); | ||
252 | + } else { | ||
253 | + tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value)); | ||
254 | + } | ||
255 | + } | ||
256 | + | ||
257 | + private void save(EdgeId edgeId, String key, boolean value) { | ||
258 | + log.debug("[{}] Updating boolean edge telemetry [{}] [{}]", edgeId, key, value); | ||
259 | + if (persistToTelemetry) { | ||
260 | + tsSubService.saveAndNotify( | ||
261 | + TenantId.SYS_TENANT_ID, edgeId, | ||
262 | + Collections.singletonList(new BasicTsKvEntry(System.currentTimeMillis(), new BooleanDataEntry(key, value))), | ||
263 | + new AttributeSaveCallback(edgeId, key, value)); | ||
264 | + } else { | ||
265 | + tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, edgeId, DataConstants.SERVER_SCOPE, key, value, new AttributeSaveCallback(edgeId, key, value)); | ||
266 | + } | ||
267 | + } | ||
268 | + | ||
269 | + private static class AttributeSaveCallback implements FutureCallback<Void> { | ||
270 | + private final EdgeId edgeId; | ||
271 | + private final String key; | ||
272 | + private final Object value; | ||
273 | + | ||
274 | + AttributeSaveCallback(EdgeId edgeId, String key, Object value) { | ||
275 | + this.edgeId = edgeId; | ||
276 | + this.key = key; | ||
277 | + this.value = value; | ||
278 | + } | ||
279 | + | ||
280 | + @Override | ||
281 | + public void onSuccess(@Nullable Void result) { | ||
282 | + log.trace("[{}] Successfully updated attribute [{}] with value [{}]", edgeId, key, value); | ||
283 | + } | ||
284 | + | ||
285 | + @Override | ||
286 | + public void onFailure(Throwable t) { | ||
287 | + log.warn("[{}] Failed to update attribute [{}] with value [{}]", edgeId, key, value, t); | ||
288 | + } | ||
289 | + } | ||
290 | +} |