Commit de3dd0f7d3f1fd859aa73ba946f147f3c6198576
Committed by
GitHub
Merge pull request #725 from thingsboard/feature/rpc-refactoring
Server Side RPC, Telemetry, Default Rule Chain(s), Fixed Integration Tests
Showing
83 changed files
with
1396 additions
and
1718 deletions
Too many changes to show.
To preserve performance only 83 of 176 files are displayed.
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 | # limitations under the License. |
15 | 15 | # |
16 | 16 | |
17 | -export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@" | |
17 | +export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@ -Dinstall.data_dir=@pkg.installFolder@" | |
18 | 18 | export LOG_FILENAME=${pkg.name}.out |
19 | 19 | export LOADER_PATH=${pkg.installFolder}/conf,${pkg.installFolder}/extensions |
20 | 20 | export SQL_DATA_FOLDER=${pkg.installFolder}/data/sql | ... | ... |
application/src/main/data/json/demo/plugins/demo_device_messaging_rpc_plugin.json
deleted
100644 → 0
1 | -{ | |
2 | - "apiToken": "messaging", | |
3 | - "name": "Demo Device Messaging RPC Plugin", | |
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.messaging.DeviceMessagingPlugin", | |
5 | - "publicAccess": false, | |
6 | - "state": "ACTIVE", | |
7 | - "configuration": { | |
8 | - "maxDeviceCountPerCustomer": 1024, | |
9 | - "defaultTimeout": 20000, | |
10 | - "maxTimeout": 60000 | |
11 | - }, | |
12 | - "additionalInfo": null | |
13 | -} | |
\ No newline at end of file |
application/src/main/data/json/demo/plugins/demo_email_plugin.json
deleted
100644 → 0
1 | -{ | |
2 | - "apiToken": "mail", | |
3 | - "name": "Demo Email Plugin", | |
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.mail.MailPlugin", | |
5 | - "publicAccess": true, | |
6 | - "state": "ACTIVE", | |
7 | - "configuration": { | |
8 | - "host": "smtp.sendgrid.net", | |
9 | - "port": 2525, | |
10 | - "username": "apikey", | |
11 | - "password": "your_api_key", | |
12 | - "otherProperties": [ | |
13 | - { | |
14 | - "key": "mail.smtp.auth", | |
15 | - "value": "true" | |
16 | - }, | |
17 | - { | |
18 | - "key": "mail.smtp.timeout", | |
19 | - "value": "10000" | |
20 | - }, | |
21 | - { | |
22 | - "key": "mail.smtp.starttls.enable", | |
23 | - "value": "true" | |
24 | - } | |
25 | - ] | |
26 | - }, | |
27 | - "additionalInfo": null | |
28 | -} | |
\ No newline at end of file |
application/src/main/data/json/demo/plugins/demo_time_rpc_plugin.json
deleted
100644 → 0
1 | -{ | |
2 | - "apiToken": "time", | |
3 | - "name": "Demo Time RPC Plugin", | |
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.time.TimePlugin", | |
5 | - "publicAccess": false, | |
6 | - "state": "ACTIVE", | |
7 | - "configuration": { | |
8 | - "timeFormat": "yyyy MM dd HH:mm:ss.SSS" | |
9 | - }, | |
10 | - "additionalInfo": null | |
11 | -} | |
\ No newline at end of file |
application/src/main/data/json/demo/rules/demo_alarm_rule.json
deleted
100644 → 0
1 | -{ | |
2 | - "name": "Demo Alarm Rule", | |
3 | - "state": "ACTIVE", | |
4 | - "weight": 0, | |
5 | - "pluginToken": "mail", | |
6 | - "filters": [ | |
7 | - { | |
8 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter", | |
9 | - "name": "MsgTypeFilter", | |
10 | - "configuration": { | |
11 | - "messageTypes": [ | |
12 | - "POST_TELEMETRY", | |
13 | - "POST_ATTRIBUTES", | |
14 | - "GET_ATTRIBUTES" | |
15 | - ] | |
16 | - } | |
17 | - }, | |
18 | - { | |
19 | - "clazz": "org.thingsboard.server.extensions.core.filter.DeviceTelemetryFilter", | |
20 | - "name": "Temperature filter", | |
21 | - "configuration": { | |
22 | - "filter": "typeof temperature !== 'undefined' && temperature >= 100" | |
23 | - } | |
24 | - } | |
25 | - ], | |
26 | - "processor": { | |
27 | - "clazz": "org.thingsboard.server.extensions.core.processor.AlarmDeduplicationProcessor", | |
28 | - "name": "AlarmDeduplicationProcessor", | |
29 | - "configuration": { | |
30 | - "alarmIdTemplate": "[$date.get('yyyy-MM-dd HH:mm')] Device $cs.get('serialNumber')($cs.get('model')) temperature is high!", | |
31 | - "alarmBodyTemplate": "[$date.get('yyyy-MM-dd HH:mm:ss')] Device $cs.get('serialNumber')($cs.get('model')) temperature is $temp.valueAsString!" | |
32 | - } | |
33 | - }, | |
34 | - "action": { | |
35 | - "clazz": "org.thingsboard.server.extensions.core.action.mail.SendMailAction", | |
36 | - "name": "Send Mail Action", | |
37 | - "configuration": { | |
38 | - "sendFlag": "isNewAlarm", | |
39 | - "fromTemplate": "thingsboard@gmail.com", | |
40 | - "toTemplate": "thingsboard@gmail.com", | |
41 | - "subjectTemplate": "$alarmId", | |
42 | - "bodyTemplate": "$alarmBody" | |
43 | - } | |
44 | - }, | |
45 | - "additionalInfo": null | |
46 | -} | |
\ No newline at end of file |
application/src/main/data/json/demo/rules/demo_gettime_rpc_rule.json
deleted
100644 → 0
1 | -{ | |
2 | - "name": "Demo getTime RPC Rule", | |
3 | - "state": "ACTIVE", | |
4 | - "weight": 0, | |
5 | - "pluginToken": "time", | |
6 | - "filters": [ | |
7 | - { | |
8 | - "configuration": { | |
9 | - "messageTypes": [ | |
10 | - "RPC_REQUEST" | |
11 | - ] | |
12 | - }, | |
13 | - "name": "RPC Request Filter", | |
14 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter" | |
15 | - }, | |
16 | - { | |
17 | - "configuration": { | |
18 | - "methodNames": [ | |
19 | - { | |
20 | - "name": "getTime" | |
21 | - } | |
22 | - ] | |
23 | - }, | |
24 | - "name": "getTime method filter", | |
25 | - "clazz": "org.thingsboard.server.extensions.core.filter.MethodNameFilter" | |
26 | - } | |
27 | - ], | |
28 | - "processor": null, | |
29 | - "action": { | |
30 | - "configuration": {}, | |
31 | - "clazz": "org.thingsboard.server.extensions.core.action.rpc.RpcPluginAction", | |
32 | - "name": "getTimeAction" | |
33 | - }, | |
34 | - "additionalInfo": null | |
35 | -} | |
\ No newline at end of file |
application/src/main/data/json/demo/rules/demo_messaging_rpc_rule.json
deleted
100644 → 0
1 | -{ | |
2 | - "name": "Demo Messaging RPC Rule", | |
3 | - "state": "ACTIVE", | |
4 | - "weight": 0, | |
5 | - "pluginToken": "messaging", | |
6 | - "filters": [ | |
7 | - { | |
8 | - "configuration": { | |
9 | - "messageTypes": [ | |
10 | - "RPC_REQUEST" | |
11 | - ] | |
12 | - }, | |
13 | - "name": "RPC Request Filter", | |
14 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter" | |
15 | - }, | |
16 | - { | |
17 | - "configuration": { | |
18 | - "methodNames": [ | |
19 | - { | |
20 | - "name": "getDevices" | |
21 | - }, | |
22 | - { | |
23 | - "name": "sendMsg" | |
24 | - } | |
25 | - ] | |
26 | - }, | |
27 | - "name": "Messaging methods filter", | |
28 | - "clazz": "org.thingsboard.server.extensions.core.filter.MethodNameFilter" | |
29 | - } | |
30 | - ], | |
31 | - "processor": null, | |
32 | - "action": { | |
33 | - "configuration": {}, | |
34 | - "clazz": "org.thingsboard.server.extensions.core.action.rpc.RpcPluginAction", | |
35 | - "name": "Messaging RPC Action" | |
36 | - }, | |
37 | - "additionalInfo": null | |
38 | -} | |
\ No newline at end of file |
application/src/main/data/json/system/plugins/system_rpc_plugin.json
deleted
100644 → 0
1 | -{ | |
2 | - "apiToken": "rpc", | |
3 | - "name": "System RPC Plugin", | |
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.rpc.RpcPlugin", | |
5 | - "publicAccess": true, | |
6 | - "state": "ACTIVE", | |
7 | - "configuration": { | |
8 | - "defaultTimeout": 20000 | |
9 | - }, | |
10 | - "additionalInfo": null | |
11 | -} | |
\ No newline at end of file |
application/src/main/data/json/system/plugins/system_telemetry_plugin.json
deleted
100644 → 0
1 | -{ | |
2 | - "apiToken": "telemetry", | |
3 | - "name": "System Telemetry Plugin", | |
4 | - "clazz": "org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin", | |
5 | - "publicAccess": true, | |
6 | - "state": "ACTIVE", | |
7 | - "configuration": {}, | |
8 | - "additionalInfo": null | |
9 | -} | |
\ No newline at end of file |
application/src/main/data/json/system/rules/system_telemetry_rule.json
deleted
100644 → 0
1 | -{ | |
2 | - "name": "System Telemetry Rule", | |
3 | - "state": "ACTIVE", | |
4 | - "weight": 0, | |
5 | - "pluginToken": "telemetry", | |
6 | - "filters": [ | |
7 | - { | |
8 | - "clazz": "org.thingsboard.server.extensions.core.filter.MsgTypeFilter", | |
9 | - "name": "TelemetryFilter", | |
10 | - "configuration": { | |
11 | - "messageTypes": [ | |
12 | - "POST_TELEMETRY", | |
13 | - "POST_ATTRIBUTES", | |
14 | - "GET_ATTRIBUTES" | |
15 | - ] | |
16 | - } | |
17 | - } | |
18 | - ], | |
19 | - "processor": null, | |
20 | - "action": { | |
21 | - "clazz": "org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction", | |
22 | - "name": "TelemetryMsgConverterAction", | |
23 | - "configuration": { | |
24 | - "timeUnit": "DAYS", | |
25 | - "ttlValue": 365 | |
26 | - } | |
27 | - }, | |
28 | - "additionalInfo": null | |
29 | -} | |
\ No newline at end of file |
1 | +{ | |
2 | + "ruleChain": { | |
3 | + "additionalInfo": null, | |
4 | + "name": "Root Rule Chain", | |
5 | + "firstRuleNodeId": null, | |
6 | + "root": true, | |
7 | + "debugMode": false, | |
8 | + "configuration": null | |
9 | + }, | |
10 | + "metadata": { | |
11 | + "firstNodeIndex": 2, | |
12 | + "nodes": [ | |
13 | + { | |
14 | + "additionalInfo": { | |
15 | + "layoutX": 639, | |
16 | + "layoutY": 113 | |
17 | + }, | |
18 | + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode", | |
19 | + "name": "PostAttributes", | |
20 | + "debugMode": true, | |
21 | + "configuration": { | |
22 | + "messageTypes": [ | |
23 | + "POST_ATTRIBUTES_REQUEST" | |
24 | + ] | |
25 | + } | |
26 | + }, | |
27 | + { | |
28 | + "additionalInfo": { | |
29 | + "layoutX": 638, | |
30 | + "layoutY": 206 | |
31 | + }, | |
32 | + "type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode", | |
33 | + "name": "PostTelemetry", | |
34 | + "debugMode": true, | |
35 | + "configuration": { | |
36 | + "messageTypes": [ | |
37 | + "POST_TELEMETRY_REQUEST" | |
38 | + ] | |
39 | + } | |
40 | + }, | |
41 | + { | |
42 | + "additionalInfo": { | |
43 | + "layoutX": 297, | |
44 | + "layoutY": 148 | |
45 | + }, | |
46 | + "type": "org.thingsboard.rule.engine.action.TbLogNode", | |
47 | + "name": "Log", | |
48 | + "debugMode": false, | |
49 | + "configuration": { | |
50 | + "jsScript": "return 'incoming message = ' + msg;" | |
51 | + } | |
52 | + }, | |
53 | + { | |
54 | + "additionalInfo": { | |
55 | + "layoutX": 905, | |
56 | + "layoutY": 203 | |
57 | + }, | |
58 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode", | |
59 | + "name": "SaveTS", | |
60 | + "debugMode": true, | |
61 | + "configuration": { | |
62 | + "defaultTTL": 0 | |
63 | + } | |
64 | + }, | |
65 | + { | |
66 | + "additionalInfo": { | |
67 | + "layoutX": 904, | |
68 | + "layoutY": 110 | |
69 | + }, | |
70 | + "type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode", | |
71 | + "name": "save client attributes", | |
72 | + "debugMode": true, | |
73 | + "configuration": { | |
74 | + "scope": "CLIENT_SCOPE" | |
75 | + } | |
76 | + } | |
77 | + ], | |
78 | + "connections": [ | |
79 | + { | |
80 | + "fromIndex": 0, | |
81 | + "toIndex": 4, | |
82 | + "type": "True" | |
83 | + }, | |
84 | + { | |
85 | + "fromIndex": 1, | |
86 | + "toIndex": 3, | |
87 | + "type": "True" | |
88 | + }, | |
89 | + { | |
90 | + "fromIndex": 2, | |
91 | + "toIndex": 0, | |
92 | + "type": "Success" | |
93 | + }, | |
94 | + { | |
95 | + "fromIndex": 2, | |
96 | + "toIndex": 1, | |
97 | + "type": "Success" | |
98 | + } | |
99 | + ], | |
100 | + "ruleChainConnections": null | |
101 | + } | |
102 | +} | ... | ... |
... | ... | @@ -61,6 +61,7 @@ import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
61 | 61 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
62 | 62 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
63 | 63 | import org.thingsboard.server.service.mail.MailExecutorService; |
64 | +import org.thingsboard.server.service.rpc.DeviceRpcService; | |
64 | 65 | import org.thingsboard.server.service.script.JsExecutorService; |
65 | 66 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
66 | 67 | |
... | ... | @@ -163,6 +164,10 @@ public class ActorSystemContext { |
163 | 164 | |
164 | 165 | @Autowired |
165 | 166 | @Getter |
167 | + private DeviceRpcService deviceRpcService; | |
168 | + | |
169 | + @Autowired | |
170 | + @Getter | |
166 | 171 | @Setter |
167 | 172 | private PluginWebSocketMsgEndpoint wsMsgEndpoint; |
168 | 173 | |
... | ... | @@ -186,17 +191,13 @@ public class ActorSystemContext { |
186 | 191 | @Getter |
187 | 192 | private long syncSessionTimeout; |
188 | 193 | |
189 | - @Value("${actors.plugin.termination.delay}") | |
190 | - @Getter | |
191 | - private long pluginActorTerminationDelay; | |
192 | - | |
193 | - @Value("${actors.plugin.processing.timeout}") | |
194 | + @Value("${actors.queue.enabled}") | |
194 | 195 | @Getter |
195 | - private long pluginProcessingTimeout; | |
196 | + private boolean queuePersistenceEnabled; | |
196 | 197 | |
197 | - @Value("${actors.plugin.error_persist_frequency}") | |
198 | + @Value("${actors.queue.timeout}") | |
198 | 199 | @Getter |
199 | - private long pluginErrorPersistFrequency; | |
200 | + private long queuePersistenceTimeout; | |
200 | 201 | |
201 | 202 | @Value("${actors.rule.chain.error_persist_frequency}") |
202 | 203 | @Getter |
... | ... | @@ -206,14 +207,6 @@ public class ActorSystemContext { |
206 | 207 | @Getter |
207 | 208 | private long ruleNodeErrorPersistFrequency; |
208 | 209 | |
209 | - @Value("${actors.rule.termination.delay}") | |
210 | - @Getter | |
211 | - private long ruleActorTerminationDelay; | |
212 | - | |
213 | - @Value("${actors.rule.error_persist_frequency}") | |
214 | - @Getter | |
215 | - private long ruleErrorPersistFrequency; | |
216 | - | |
217 | 210 | @Value("${actors.statistics.enabled}") |
218 | 211 | @Getter |
219 | 212 | private boolean statisticsEnabled; | ... | ... |
... | ... | @@ -29,13 +29,12 @@ import org.thingsboard.server.actors.shared.plugin.SystemPluginManager; |
29 | 29 | import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager; |
30 | 30 | import org.thingsboard.server.actors.tenant.TenantActor; |
31 | 31 | import org.thingsboard.server.common.data.Tenant; |
32 | -import org.thingsboard.server.common.data.id.PluginId; | |
33 | -import org.thingsboard.server.common.data.id.RuleChainId; | |
34 | 32 | import org.thingsboard.server.common.data.id.TenantId; |
35 | 33 | import org.thingsboard.server.common.data.page.PageDataIterable; |
36 | 34 | import org.thingsboard.server.common.msg.TbActorMsg; |
37 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
38 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
35 | +import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; | |
36 | +import org.thingsboard.server.common.msg.aware.TenantAwareMsg; | |
37 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
39 | 38 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
40 | 39 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
41 | 40 | import org.thingsboard.server.dao.model.ModelConstants; |
... | ... | @@ -90,12 +89,22 @@ public class AppActor extends RuleChainManagerActor { |
90 | 89 | @Override |
91 | 90 | protected boolean process(TbActorMsg msg) { |
92 | 91 | switch (msg.getMsgType()) { |
92 | + case CLUSTER_EVENT_MSG: | |
93 | + broadcast(msg); | |
94 | + break; | |
93 | 95 | case COMPONENT_LIFE_CYCLE_MSG: |
94 | 96 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
95 | 97 | break; |
96 | 98 | case SERVICE_TO_RULE_ENGINE_MSG: |
97 | 99 | onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); |
98 | 100 | break; |
101 | + case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | |
102 | + case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | |
103 | + case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | |
104 | + case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | |
105 | + case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | |
106 | + onToDeviceActorMsg((TenantAwareMsg) msg); | |
107 | + break; | |
99 | 108 | default: |
100 | 109 | return false; |
101 | 110 | } |
... | ... | @@ -110,48 +119,12 @@ public class AppActor extends RuleChainManagerActor { |
110 | 119 | } |
111 | 120 | } |
112 | 121 | |
113 | - | |
114 | -// @Override | |
115 | -// public void onReceive(Object msg) throws Exception { | |
116 | -// logger.debug("Received message: {}", msg); | |
117 | -// if (msg instanceof ToDeviceActorMsg) { | |
118 | -// processDeviceMsg((ToDeviceActorMsg) msg); | |
119 | -// } else if (msg instanceof ToPluginActorMsg) { | |
120 | -// onToPluginMsg((ToPluginActorMsg) msg); | |
121 | -// } else if (msg instanceof ToDeviceActorNotificationMsg) { | |
122 | -// onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg); | |
123 | -// } else if (msg instanceof Terminated) { | |
124 | -// processTermination((Terminated) msg); | |
125 | -// } else if (msg instanceof ClusterEventMsg) { | |
126 | -// broadcast(msg); | |
127 | -// } else if (msg instanceof ComponentLifecycleMsg) { | |
128 | -// onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
129 | -// } else if (msg instanceof PluginTerminationMsg) { | |
130 | -// onPluginTerminated((PluginTerminationMsg) msg); | |
131 | -// } else { | |
132 | -// logger.warning("Unknown message: {}!", msg); | |
133 | -// } | |
134 | -// } | |
135 | - | |
136 | - private void onPluginTerminated(PluginTerminationMsg msg) { | |
137 | - pluginManager.remove(msg.getId()); | |
138 | - } | |
139 | - | |
140 | - private void broadcast(Object msg) { | |
141 | - pluginManager.broadcast(msg); | |
122 | + @Override | |
123 | + protected void broadcast(Object msg) { | |
124 | + super.broadcast(msg); | |
142 | 125 | tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
143 | 126 | } |
144 | 127 | |
145 | - private void onToPluginMsg(ToPluginActorMsg msg) { | |
146 | - ActorRef target; | |
147 | - if (SYSTEM_TENANT.equals(msg.getPluginTenantId())) { | |
148 | - target = pluginManager.getOrCreateActor(this.context(), msg.getPluginId()); | |
149 | - } else { | |
150 | - target = getOrCreateTenantActor(msg.getPluginTenantId()); | |
151 | - } | |
152 | - target.tell(msg, ActorRef.noSender()); | |
153 | - } | |
154 | - | |
155 | 128 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
156 | 129 | ActorRef target; |
157 | 130 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
... | ... | @@ -166,17 +139,17 @@ public class AppActor extends RuleChainManagerActor { |
166 | 139 | } |
167 | 140 | } |
168 | 141 | |
169 | - private void onToDeviceActorMsg(ToDeviceActorNotificationMsg msg) { | |
142 | + private void onToDeviceActorMsg(TenantAwareMsg msg) { | |
170 | 143 | getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); |
171 | 144 | } |
172 | 145 | |
173 | - private void processDeviceMsg(ToDeviceActorMsg toDeviceActorMsg) { | |
174 | - TenantId tenantId = toDeviceActorMsg.getTenantId(); | |
146 | + private void processDeviceMsg(DeviceToDeviceActorMsg deviceToDeviceActorMsg) { | |
147 | + TenantId tenantId = deviceToDeviceActorMsg.getTenantId(); | |
175 | 148 | ActorRef tenantActor = getOrCreateTenantActor(tenantId); |
176 | - if (toDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { | |
177 | -// tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | |
149 | + if (deviceToDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { | |
150 | +// tenantActor.tell(new RuleChainDeviceMsg(deviceToDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | |
178 | 151 | } else { |
179 | - tenantActor.tell(toDeviceActorMsg, context().self()); | |
152 | + tenantActor.tell(deviceToDeviceActorMsg, context().self()); | |
180 | 153 | } |
181 | 154 | } |
182 | 155 | ... | ... |
... | ... | @@ -24,59 +24,59 @@ import org.thingsboard.server.common.data.id.DeviceId; |
24 | 24 | import org.thingsboard.server.common.data.id.TenantId; |
25 | 25 | import org.thingsboard.server.common.msg.TbActorMsg; |
26 | 26 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
27 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
27 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
28 | +import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | |
29 | +import org.thingsboard.server.common.msg.timeout.DeviceActorRpcTimeoutMsg; | |
28 | 30 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
29 | -import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg; | |
30 | 31 | import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; |
31 | -import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; | |
32 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | |
33 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | |
32 | +import org.thingsboard.server.common.msg.timeout.TimeoutMsg; | |
33 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; | |
34 | 34 | |
35 | 35 | public class DeviceActor extends ContextAwareActor { |
36 | 36 | |
37 | 37 | private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); |
38 | 38 | |
39 | - private final TenantId tenantId; | |
40 | - private final DeviceId deviceId; | |
41 | 39 | private final DeviceActorMessageProcessor processor; |
42 | 40 | |
43 | 41 | private DeviceActor(ActorSystemContext systemContext, TenantId tenantId, DeviceId deviceId) { |
44 | 42 | super(systemContext); |
45 | - this.tenantId = tenantId; | |
46 | - this.deviceId = deviceId; | |
47 | - this.processor = new DeviceActorMessageProcessor(systemContext, logger, deviceId); | |
43 | + this.processor = new DeviceActorMessageProcessor(systemContext, logger, tenantId, deviceId); | |
48 | 44 | } |
49 | 45 | |
50 | 46 | @Override |
51 | 47 | protected boolean process(TbActorMsg msg) { |
52 | - return false; | |
53 | - } | |
54 | - | |
55 | - @Override | |
56 | - public void onReceive(Object msg) throws Exception { | |
57 | -// if (msg instanceof RuleChainDeviceMsg) { | |
58 | -// processor.process(context(), (RuleChainDeviceMsg) msg); | |
59 | -// } else if (msg instanceof RulesProcessedMsg) { | |
60 | -// processor.onRulesProcessedMsg(context(), (RulesProcessedMsg) msg); | |
61 | - if (msg instanceof ToDeviceActorMsg) { | |
62 | - processor.process(context(), (ToDeviceActorMsg) msg); | |
63 | - } else if (msg instanceof ToDeviceActorNotificationMsg) { | |
64 | - if (msg instanceof DeviceAttributesEventNotificationMsg) { | |
48 | + switch (msg.getMsgType()) { | |
49 | + case CLUSTER_EVENT_MSG: | |
50 | + processor.processClusterEventMsg((ClusterEventMsg) msg); | |
51 | + break; | |
52 | + case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | |
53 | + processor.process(context(), (DeviceToDeviceActorMsg) msg); | |
54 | + break; | |
55 | + case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | |
65 | 56 | processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); |
66 | - } else if (msg instanceof ToDeviceRpcRequestPluginMsg) { | |
67 | - processor.processRpcRequest(context(), (ToDeviceRpcRequestPluginMsg) msg); | |
68 | - } else if (msg instanceof DeviceCredentialsUpdateNotificationMsg){ | |
57 | + break; | |
58 | + case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | |
69 | 59 | processor.processCredentialsUpdate(); |
70 | - } else if (msg instanceof DeviceNameOrTypeUpdateMsg){ | |
60 | + break; | |
61 | + case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | |
71 | 62 | processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg); |
72 | - } | |
73 | - } else if (msg instanceof TimeoutMsg) { | |
74 | - processor.processTimeout(context(), (TimeoutMsg) msg); | |
75 | - } else if (msg instanceof ClusterEventMsg) { | |
76 | - processor.processClusterEventMsg((ClusterEventMsg) msg); | |
77 | - } else { | |
78 | - logger.debug("[{}][{}] Unknown msg type.", tenantId, deviceId, msg.getClass().getName()); | |
63 | + break; | |
64 | + case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | |
65 | + processor.processRpcRequest(context(), (ToDeviceRpcRequestMsg) msg); | |
66 | + break; | |
67 | + case DEVICE_ACTOR_RPC_TIMEOUT_MSG: | |
68 | + processor.processRpcTimeout(context(), (DeviceActorRpcTimeoutMsg) msg); | |
69 | + break; | |
70 | + case DEVICE_ACTOR_QUEUE_TIMEOUT_MSG: | |
71 | + processor.processQueueTimeout(context(), (DeviceActorQueueTimeoutMsg) msg); | |
72 | + break; | |
73 | + case RULE_ENGINE_QUEUE_PUT_ACK_MSG: | |
74 | + processor.processQueueAck(context(), (RuleEngineQueuePutAckMsg) msg); | |
75 | + break; | |
76 | + default: | |
77 | + return false; | |
79 | 78 | } |
79 | + return true; | |
80 | 80 | } |
81 | 81 | |
82 | 82 | public static class ActorCreator extends ContextBasedCreator<DeviceActor> { | ... | ... |
... | ... | @@ -18,29 +18,75 @@ package org.thingsboard.server.actors.device; |
18 | 18 | import akka.actor.ActorContext; |
19 | 19 | import akka.actor.ActorRef; |
20 | 20 | import akka.event.LoggingAdapter; |
21 | +import com.datastax.driver.core.utils.UUIDs; | |
22 | +import com.google.common.util.concurrent.FutureCallback; | |
23 | +import com.google.common.util.concurrent.Futures; | |
24 | +import com.google.common.util.concurrent.ListenableFuture; | |
25 | +import com.google.gson.Gson; | |
26 | +import com.google.gson.JsonArray; | |
27 | +import com.google.gson.JsonObject; | |
21 | 28 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | 29 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
23 | 30 | import org.thingsboard.server.common.data.DataConstants; |
24 | 31 | import org.thingsboard.server.common.data.Device; |
25 | 32 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | 33 | import org.thingsboard.server.common.data.id.SessionId; |
34 | +import org.thingsboard.server.common.data.id.TenantId; | |
27 | 35 | import org.thingsboard.server.common.data.kv.AttributeKey; |
28 | 36 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
37 | +import org.thingsboard.server.common.data.kv.KvEntry; | |
38 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | |
39 | +import org.thingsboard.server.common.msg.TbMsg; | |
40 | +import org.thingsboard.server.common.msg.TbMsgDataType; | |
41 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | |
29 | 42 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
30 | 43 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
31 | -import org.thingsboard.server.common.msg.core.*; | |
32 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
44 | +import org.thingsboard.server.common.msg.core.AttributesUpdateNotification; | |
45 | +import org.thingsboard.server.common.msg.core.AttributesUpdateRequest; | |
46 | +import org.thingsboard.server.common.msg.core.BasicCommandAckResponse; | |
47 | +import org.thingsboard.server.common.msg.core.BasicGetAttributesResponse; | |
48 | +import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; | |
49 | +import org.thingsboard.server.common.msg.core.BasicToDeviceSessionActorMsg; | |
50 | +import org.thingsboard.server.common.msg.core.GetAttributesRequest; | |
51 | +import org.thingsboard.server.common.msg.core.RuleEngineError; | |
52 | +import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg; | |
53 | +import org.thingsboard.server.common.msg.core.SessionCloseMsg; | |
54 | +import org.thingsboard.server.common.msg.core.SessionCloseNotification; | |
55 | +import org.thingsboard.server.common.msg.core.SessionOpenMsg; | |
56 | +import org.thingsboard.server.common.msg.core.StatusCodeResponse; | |
57 | +import org.thingsboard.server.common.msg.core.TelemetryUploadRequest; | |
58 | +import org.thingsboard.server.common.msg.core.ToDeviceRpcRequestMsg; | |
59 | +import org.thingsboard.server.common.msg.core.ToDeviceRpcResponseMsg; | |
60 | +import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; | |
61 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
33 | 62 | import org.thingsboard.server.common.msg.kv.BasicAttributeKVMsg; |
63 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
34 | 64 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
35 | -import org.thingsboard.server.common.msg.session.MsgType; | |
65 | +import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; | |
66 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
67 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
36 | 68 | import org.thingsboard.server.common.msg.session.SessionType; |
37 | 69 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
38 | -import org.thingsboard.server.extensions.api.device.DeviceAttributes; | |
70 | +import org.thingsboard.server.common.msg.timeout.DeviceActorQueueTimeoutMsg; | |
71 | +import org.thingsboard.server.common.msg.timeout.DeviceActorRpcTimeoutMsg; | |
39 | 72 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
40 | 73 | import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; |
41 | -import org.thingsboard.server.extensions.api.plugins.msg.*; | |
42 | - | |
43 | -import java.util.*; | |
74 | +import org.thingsboard.server.extensions.api.plugins.PluginCallback; | |
75 | +import org.thingsboard.server.extensions.api.plugins.PluginContext; | |
76 | +import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; | |
77 | +import org.thingsboard.server.extensions.api.plugins.msg.RpcError; | |
78 | + | |
79 | +import javax.annotation.Nullable; | |
80 | +import java.util.ArrayList; | |
81 | +import java.util.Arrays; | |
82 | +import java.util.Collections; | |
83 | +import java.util.HashMap; | |
84 | +import java.util.HashSet; | |
85 | +import java.util.List; | |
86 | +import java.util.Map; | |
87 | +import java.util.Optional; | |
88 | +import java.util.Set; | |
89 | +import java.util.UUID; | |
44 | 90 | import java.util.concurrent.ExecutionException; |
45 | 91 | import java.util.concurrent.TimeoutException; |
46 | 92 | import java.util.function.Consumer; |
... | ... | @@ -52,46 +98,43 @@ import java.util.stream.Collectors; |
52 | 98 | */ |
53 | 99 | public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
54 | 100 | |
101 | + private final TenantId tenantId; | |
55 | 102 | private final DeviceId deviceId; |
56 | 103 | private final Map<SessionId, SessionInfo> sessions; |
57 | 104 | private final Map<SessionId, SessionInfo> attributeSubscriptions; |
58 | 105 | private final Map<SessionId, SessionInfo> rpcSubscriptions; |
59 | - | |
60 | 106 | private final Map<Integer, ToDeviceRpcRequestMetadata> rpcPendingMap; |
107 | + private final Map<UUID, PendingSessionMsgData> pendingMsgs; | |
108 | + | |
109 | + private final Gson gson = new Gson(); | |
61 | 110 | |
62 | 111 | private int rpcSeq = 0; |
63 | 112 | private String deviceName; |
64 | 113 | private String deviceType; |
65 | - private DeviceAttributes deviceAttributes; | |
114 | + private TbMsgMetaData defaultMetaData; | |
66 | 115 | |
67 | - public DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, DeviceId deviceId) { | |
116 | + public DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, DeviceId deviceId) { | |
68 | 117 | super(systemContext, logger); |
118 | + this.tenantId = tenantId; | |
69 | 119 | this.deviceId = deviceId; |
70 | 120 | this.sessions = new HashMap<>(); |
71 | 121 | this.attributeSubscriptions = new HashMap<>(); |
72 | 122 | this.rpcSubscriptions = new HashMap<>(); |
73 | 123 | this.rpcPendingMap = new HashMap<>(); |
124 | + this.pendingMsgs = new HashMap<>(); | |
74 | 125 | initAttributes(); |
75 | 126 | } |
76 | 127 | |
77 | 128 | private void initAttributes() { |
78 | - //TODO: add invalidation of deviceType cache. | |
79 | 129 | Device device = systemContext.getDeviceService().findDeviceById(deviceId); |
80 | 130 | this.deviceName = device.getName(); |
81 | 131 | this.deviceType = device.getType(); |
82 | - this.deviceAttributes = new DeviceAttributes(fetchAttributes(DataConstants.CLIENT_SCOPE), | |
83 | - fetchAttributes(DataConstants.SERVER_SCOPE), fetchAttributes(DataConstants.SHARED_SCOPE)); | |
84 | - } | |
85 | - | |
86 | - private void refreshAttributes(DeviceAttributesEventNotificationMsg msg) { | |
87 | - if (msg.isDeleted()) { | |
88 | - msg.getDeletedKeys().forEach(key -> deviceAttributes.remove(key)); | |
89 | - } else { | |
90 | - deviceAttributes.update(msg.getScope(), msg.getValues()); | |
91 | - } | |
132 | + this.defaultMetaData = new TbMsgMetaData(); | |
133 | + this.defaultMetaData.putValue("deviceName", deviceName); | |
134 | + this.defaultMetaData.putValue("deviceType", deviceType); | |
92 | 135 | } |
93 | 136 | |
94 | - void processRpcRequest(ActorContext context, ToDeviceRpcRequestPluginMsg msg) { | |
137 | + void processRpcRequest(ActorContext context, org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg msg) { | |
95 | 138 | ToDeviceRpcRequest request = msg.getMsg(); |
96 | 139 | ToDeviceRpcRequestBody body = request.getBody(); |
97 | 140 | ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( |
... | ... | @@ -118,9 +161,8 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
118 | 161 | syncSessionSet.forEach(rpcSubscriptions::remove); |
119 | 162 | |
120 | 163 | if (request.isOneway() && sent) { |
121 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(msg, (String) null); | |
122 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | |
123 | 164 | logger.debug("[{}] Rpc command response sent [{}]!", deviceId, request.getId()); |
165 | + systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(msg.getMsg().getId(), null, null)); | |
124 | 166 | } else { |
125 | 167 | registerPendingRpcRequest(context, msg, sent, rpcRequest, timeout); |
126 | 168 | } |
... | ... | @@ -132,18 +174,36 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
132 | 174 | |
133 | 175 | } |
134 | 176 | |
135 | - private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestPluginMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { | |
177 | + private void registerPendingRpcRequest(ActorContext context, org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { | |
136 | 178 | rpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); |
137 | - TimeoutIntMsg timeoutMsg = new TimeoutIntMsg(rpcRequest.getRequestId(), timeout); | |
179 | + DeviceActorRpcTimeoutMsg timeoutMsg = new DeviceActorRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); | |
138 | 180 | scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout()); |
139 | 181 | } |
140 | 182 | |
141 | - public void processTimeout(ActorContext context, TimeoutMsg msg) { | |
183 | + void processRpcTimeout(ActorContext context, DeviceActorRpcTimeoutMsg msg) { | |
142 | 184 | ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(msg.getId()); |
143 | 185 | if (requestMd != null) { |
144 | 186 | logger.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); |
145 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(requestMd.getMsg(), requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION); | |
146 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | |
187 | + systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), | |
188 | + null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); | |
189 | + } | |
190 | + } | |
191 | + | |
192 | + void processQueueTimeout(ActorContext context, DeviceActorQueueTimeoutMsg msg) { | |
193 | + PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | |
194 | + if (data != null) { | |
195 | + logger.debug("[{}] Queue put [{}] timeout detected!", deviceId, msg.getId()); | |
196 | + ToDeviceMsg toDeviceMsg = new RuleEngineErrorMsg(data.getSessionMsgType(), RuleEngineError.QUEUE_PUT_TIMEOUT); | |
197 | + sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | |
198 | + } | |
199 | + } | |
200 | + | |
201 | + void processQueueAck(ActorContext context, RuleEngineQueuePutAckMsg msg) { | |
202 | + PendingSessionMsgData data = pendingMsgs.remove(msg.getId()); | |
203 | + if (data != null) { | |
204 | + logger.debug("[{}] Queue put [{}] ack detected!", deviceId, msg.getId()); | |
205 | + ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onSuccess(data.getSessionMsgType(), data.getRequestId()); | |
206 | + sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, data.getSessionId()), data.getServerAddress()); | |
147 | 207 | } |
148 | 208 | } |
149 | 209 | |
... | ... | @@ -173,8 +233,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
173 | 233 | ToDeviceRpcRequestBody body = request.getBody(); |
174 | 234 | if (request.isOneway()) { |
175 | 235 | sentOneWayIds.add(entry.getKey()); |
176 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(entry.getValue().getMsg(), (String) null); | |
177 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | |
236 | + systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(request.getId(), null, null)); | |
178 | 237 | } |
179 | 238 | ToDeviceRpcRequestMsg rpcRequest = new ToDeviceRpcRequestMsg( |
180 | 239 | entry.getKey(), |
... | ... | @@ -186,14 +245,120 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
186 | 245 | }; |
187 | 246 | } |
188 | 247 | |
189 | - void process(ActorContext context, ToDeviceActorMsg msg) { | |
248 | + void process(ActorContext context, DeviceToDeviceActorMsg msg) { | |
190 | 249 | processSubscriptionCommands(context, msg); |
191 | 250 | processRpcResponses(context, msg); |
192 | 251 | processSessionStateMsgs(msg); |
252 | + | |
253 | + SessionMsgType sessionMsgType = msg.getPayload().getMsgType(); | |
254 | + if (sessionMsgType.requiresRulesProcessing()) { | |
255 | + switch (sessionMsgType) { | |
256 | + case GET_ATTRIBUTES_REQUEST: | |
257 | + handleGetAttributesRequest(msg); | |
258 | + break; | |
259 | + case POST_ATTRIBUTES_REQUEST: | |
260 | + handlePostAttributesRequest(context, msg); | |
261 | + break; | |
262 | + case POST_TELEMETRY_REQUEST: | |
263 | + handlePostTelemetryRequest(context, msg); | |
264 | + break; | |
265 | + case TO_SERVER_RPC_REQUEST: | |
266 | + break; | |
267 | + //TODO: push to queue and start processing! | |
268 | + } | |
269 | + } | |
270 | + } | |
271 | + | |
272 | + private void handleGetAttributesRequest(DeviceToDeviceActorMsg src) { | |
273 | + GetAttributesRequest request = (GetAttributesRequest) src.getPayload(); | |
274 | + ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, request.getClientAttributeNames()); | |
275 | + ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, request.getClientAttributeNames()); | |
276 | + | |
277 | + Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback<List<List<AttributeKvEntry>>>() { | |
278 | + @Override | |
279 | + public void onSuccess(@Nullable List<List<AttributeKvEntry>> result) { | |
280 | + BasicGetAttributesResponse response = BasicGetAttributesResponse.onSuccess(request.getMsgType(), | |
281 | + request.getRequestId(), BasicAttributeKVMsg.from(result.get(0), result.get(1))); | |
282 | + sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(response, src.getSessionId()), src.getServerAddress()); | |
283 | + } | |
284 | + | |
285 | + @Override | |
286 | + public void onFailure(Throwable t) { | |
287 | + if (t instanceof Exception) { | |
288 | + ToDeviceMsg toDeviceMsg = BasicStatusCodeResponse.onError(SessionMsgType.GET_ATTRIBUTES_REQUEST, request.getRequestId(), (Exception) t); | |
289 | + sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(toDeviceMsg, src.getSessionId()), src.getServerAddress()); | |
290 | + } else { | |
291 | + logger.error("[{}] Failed to process attributes request", deviceId, t); | |
292 | + } | |
293 | + } | |
294 | + }); | |
295 | + } | |
296 | + | |
297 | + private ListenableFuture<List<AttributeKvEntry>> getAttributeKvEntries(DeviceId deviceId, String scope, Optional<Set<String>> names) { | |
298 | + if (names.isPresent()) { | |
299 | + if (!names.get().isEmpty()) { | |
300 | + return systemContext.getAttributesService().find(deviceId, scope, names.get()); | |
301 | + } else { | |
302 | + return systemContext.getAttributesService().findAll(deviceId, scope); | |
303 | + } | |
304 | + } else { | |
305 | + return Futures.immediateFuture(Collections.emptyList()); | |
306 | + } | |
307 | + } | |
308 | + | |
309 | + private void handlePostAttributesRequest(ActorContext context, DeviceToDeviceActorMsg src) { | |
310 | + AttributesUpdateRequest request = (AttributesUpdateRequest) src.getPayload(); | |
311 | + | |
312 | + JsonObject json = new JsonObject(); | |
313 | + for (AttributeKvEntry kv : request.getAttributes()) { | |
314 | + kv.getBooleanValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
315 | + kv.getLongValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
316 | + kv.getDoubleValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
317 | + kv.getStrValue().ifPresent(v -> json.addProperty(kv.getKey(), v)); | |
318 | + } | |
319 | + | |
320 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json)); | |
321 | + pushToRuleEngineWithTimeout(context, tbMsg, src, request); | |
322 | + } | |
323 | + | |
324 | + private void handlePostTelemetryRequest(ActorContext context, DeviceToDeviceActorMsg src) { | |
325 | + TelemetryUploadRequest request = (TelemetryUploadRequest) src.getPayload(); | |
326 | + | |
327 | + Map<Long, List<KvEntry>> tsData = request.getData(); | |
328 | + | |
329 | + JsonArray json = new JsonArray(); | |
330 | + for (Map.Entry<Long, List<KvEntry>> entry : tsData.entrySet()) { | |
331 | + JsonObject ts = new JsonObject(); | |
332 | + ts.addProperty("ts", entry.getKey()); | |
333 | + JsonObject values = new JsonObject(); | |
334 | + for (KvEntry kv : entry.getValue()) { | |
335 | + kv.getBooleanValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); | |
336 | + kv.getLongValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); | |
337 | + kv.getDoubleValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); | |
338 | + kv.getStrValue().ifPresent(v -> values.addProperty(kv.getKey(), v)); | |
339 | + } | |
340 | + ts.add("values", values); | |
341 | + json.add(ts); | |
342 | + } | |
343 | + | |
344 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, defaultMetaData, TbMsgDataType.JSON, gson.toJson(json)); | |
345 | + pushToRuleEngineWithTimeout(context, tbMsg, src, request); | |
346 | + } | |
347 | + | |
348 | + private void pushToRuleEngineWithTimeout(ActorContext context, TbMsg tbMsg, DeviceToDeviceActorMsg src, FromDeviceRequestMsg fromDeviceRequestMsg) { | |
349 | + SessionMsgType sessionMsgType = fromDeviceRequestMsg.getMsgType(); | |
350 | + int requestId = fromDeviceRequestMsg.getRequestId(); | |
351 | + if (systemContext.isQueuePersistenceEnabled()) { | |
352 | + pendingMsgs.put(tbMsg.getId(), new PendingSessionMsgData(src.getSessionId(), src.getServerAddress(), sessionMsgType, requestId)); | |
353 | + scheduleMsgWithDelay(context, new DeviceActorQueueTimeoutMsg(tbMsg.getId(), systemContext.getQueuePersistenceTimeout()), systemContext.getQueuePersistenceTimeout()); | |
354 | + } else { | |
355 | + ToDeviceSessionActorMsg response = new BasicToDeviceSessionActorMsg(BasicStatusCodeResponse.onSuccess(sessionMsgType, requestId), src.getSessionId()); | |
356 | + sendMsgToSessionActor(response, src.getServerAddress()); | |
357 | + } | |
358 | + context.parent().tell(new DeviceActorToRuleEngineMsg(context.self(), tbMsg), context.self()); | |
193 | 359 | } |
194 | 360 | |
195 | 361 | void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { |
196 | - refreshAttributes(msg); | |
197 | 362 | if (attributeSubscriptions.size() > 0) { |
198 | 363 | ToDeviceMsg notification = null; |
199 | 364 | if (msg.isDeleted()) { |
... | ... | @@ -223,50 +388,29 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
223 | 388 | } |
224 | 389 | } |
225 | 390 | |
226 | -// void process(ActorContext context, RuleChainDeviceMsg srcMsg) { | |
227 | -// ChainProcessingMetaData md = new ChainProcessingMetaData(srcMsg.getRuleChain(), | |
228 | -// srcMsg.getToDeviceActorMsg(), new DeviceMetaData(deviceId, deviceName, deviceType, deviceAttributes), context.self()); | |
229 | -// ChainProcessingContext ctx = new ChainProcessingContext(md); | |
230 | -// if (ctx.getChainLength() > 0) { | |
231 | -// RuleProcessingMsg msg = new RuleProcessingMsg(ctx); | |
232 | -// ActorRef ruleActorRef = ctx.getCurrentActor(); | |
233 | -// ruleActorRef.tell(msg, ActorRef.noSender()); | |
234 | -// } else { | |
235 | -// context.self().tell(new RulesProcessedMsg(ctx), context.self()); | |
236 | -// } | |
237 | -// } | |
238 | - | |
239 | - void processRpcResponses(ActorContext context, ToDeviceActorMsg msg) { | |
391 | + private void processRpcResponses(ActorContext context, DeviceToDeviceActorMsg msg) { | |
240 | 392 | SessionId sessionId = msg.getSessionId(); |
241 | 393 | FromDeviceMsg inMsg = msg.getPayload(); |
242 | - if (inMsg.getMsgType() == MsgType.TO_DEVICE_RPC_RESPONSE) { | |
394 | + if (inMsg.getMsgType() == SessionMsgType.TO_DEVICE_RPC_RESPONSE) { | |
243 | 395 | logger.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); |
244 | 396 | ToDeviceRpcResponseMsg responseMsg = (ToDeviceRpcResponseMsg) inMsg; |
245 | 397 | ToDeviceRpcRequestMetadata requestMd = rpcPendingMap.remove(responseMsg.getRequestId()); |
246 | 398 | boolean success = requestMd != null; |
247 | 399 | if (success) { |
248 | - ToPluginRpcResponseDeviceMsg responsePluginMsg = toPluginRpcResponseMsg(requestMd.getMsg(), responseMsg.getData()); | |
249 | - Optional<ServerAddress> pluginServerAddress = requestMd.getMsg().getServerAddress(); | |
250 | - if (pluginServerAddress.isPresent()) { | |
251 | - systemContext.getRpcService().tell(pluginServerAddress.get(), responsePluginMsg); | |
252 | - logger.debug("[{}] Rpc command response sent to remote plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId()); | |
253 | - } else { | |
254 | - context.parent().tell(responsePluginMsg, ActorRef.noSender()); | |
255 | - logger.debug("[{}] Rpc command response sent to local plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId()); | |
256 | - } | |
400 | + systemContext.getDeviceRpcService().process(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), responseMsg.getData(), null)); | |
257 | 401 | } else { |
258 | 402 | logger.debug("[{}] Rpc command response [{}] is stale!", deviceId, responseMsg.getRequestId()); |
259 | 403 | } |
260 | 404 | if (msg.getSessionType() == SessionType.SYNC) { |
261 | 405 | BasicCommandAckResponse response = success |
262 | - ? BasicCommandAckResponse.onSuccess(MsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId()) | |
263 | - : BasicCommandAckResponse.onError(MsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId(), new TimeoutException()); | |
406 | + ? BasicCommandAckResponse.onSuccess(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId()) | |
407 | + : BasicCommandAckResponse.onError(SessionMsgType.TO_DEVICE_RPC_REQUEST, responseMsg.getRequestId(), new TimeoutException()); | |
264 | 408 | sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(response, msg.getSessionId()), msg.getServerAddress()); |
265 | 409 | } |
266 | 410 | } |
267 | 411 | } |
268 | 412 | |
269 | - public void processClusterEventMsg(ClusterEventMsg msg) { | |
413 | + void processClusterEventMsg(ClusterEventMsg msg) { | |
270 | 414 | if (!msg.isAdded()) { |
271 | 415 | logger.debug("[{}] Clearing attributes/rpc subscription for server [{}]", deviceId, msg.getServerAddress()); |
272 | 416 | Predicate<Map.Entry<SessionId, SessionInfo>> filter = e -> e.getValue().getServer() |
... | ... | @@ -276,59 +420,27 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
276 | 420 | } |
277 | 421 | } |
278 | 422 | |
279 | - private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, String data) { | |
280 | - return toPluginRpcResponseMsg(requestMsg, data, null); | |
281 | - } | |
282 | - | |
283 | - private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, RpcError error) { | |
284 | - return toPluginRpcResponseMsg(requestMsg, null, error); | |
285 | - } | |
286 | - | |
287 | - private ToPluginRpcResponseDeviceMsg toPluginRpcResponseMsg(ToDeviceRpcRequestPluginMsg requestMsg, String data, RpcError error) { | |
288 | - return new ToPluginRpcResponseDeviceMsg( | |
289 | - requestMsg.getPluginId(), | |
290 | - requestMsg.getPluginTenantId(), | |
291 | - new FromDeviceRpcResponse(requestMsg.getMsg().getId(), | |
292 | - data, | |
293 | - error | |
294 | - ) | |
295 | - ); | |
296 | - } | |
297 | - | |
298 | -// void onRulesProcessedMsg(ActorContext context, RulesProcessedMsg msg) { | |
299 | -// ChainProcessingContext ctx = msg.getCtx(); | |
300 | -// ToDeviceActorMsg inMsg = ctx.getInMsg(); | |
301 | -// SessionId sid = inMsg.getSessionId(); | |
302 | -// ToDeviceSessionActorMsg response; | |
303 | -// if (ctx.getResponse() != null) { | |
304 | -// response = new BasicToDeviceSessionActorMsg(ctx.getResponse(), sid); | |
305 | -// } else { | |
306 | -// response = new BasicToDeviceSessionActorMsg(ctx.getError(), sid); | |
307 | -// } | |
308 | -// sendMsgToSessionActor(response, inMsg.getServerAddress()); | |
309 | -// } | |
310 | - | |
311 | - private void processSubscriptionCommands(ActorContext context, ToDeviceActorMsg msg) { | |
423 | + private void processSubscriptionCommands(ActorContext context, DeviceToDeviceActorMsg msg) { | |
312 | 424 | SessionId sessionId = msg.getSessionId(); |
313 | 425 | SessionType sessionType = msg.getSessionType(); |
314 | 426 | FromDeviceMsg inMsg = msg.getPayload(); |
315 | - if (inMsg.getMsgType() == MsgType.SUBSCRIBE_ATTRIBUTES_REQUEST) { | |
427 | + if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST) { | |
316 | 428 | logger.debug("[{}] Registering attributes subscription for session [{}]", deviceId, sessionId); |
317 | 429 | attributeSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); |
318 | - } else if (inMsg.getMsgType() == MsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST) { | |
430 | + } else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST) { | |
319 | 431 | logger.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId); |
320 | 432 | attributeSubscriptions.remove(sessionId); |
321 | - } else if (inMsg.getMsgType() == MsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST) { | |
433 | + } else if (inMsg.getMsgType() == SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST) { | |
322 | 434 | logger.debug("[{}] Registering rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); |
323 | 435 | rpcSubscriptions.put(sessionId, new SessionInfo(sessionType, msg.getServerAddress())); |
324 | 436 | sendPendingRequests(context, sessionId, sessionType, msg.getServerAddress()); |
325 | - } else if (inMsg.getMsgType() == MsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST) { | |
437 | + } else if (inMsg.getMsgType() == SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST) { | |
326 | 438 | logger.debug("[{}] Canceling rpc subscription for session [{}][{}]", deviceId, sessionId, sessionType); |
327 | 439 | rpcSubscriptions.remove(sessionId); |
328 | 440 | } |
329 | 441 | } |
330 | 442 | |
331 | - private void processSessionStateMsgs(ToDeviceActorMsg msg) { | |
443 | + private void processSessionStateMsgs(DeviceToDeviceActorMsg msg) { | |
332 | 444 | SessionId sessionId = msg.getSessionId(); |
333 | 445 | FromDeviceMsg inMsg = msg.getPayload(); |
334 | 446 | if (inMsg instanceof SessionOpenMsg) { |
... | ... | @@ -352,17 +464,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
352 | 464 | } |
353 | 465 | } |
354 | 466 | |
355 | - private List<AttributeKvEntry> fetchAttributes(String scope) { | |
356 | - try { | |
357 | - //TODO: replace this with async operation. Happens only during actor creation, but is still criticla for performance, | |
358 | - return systemContext.getAttributesService().findAll(this.deviceId, scope).get(); | |
359 | - } catch (InterruptedException | ExecutionException e) { | |
360 | - logger.warning("[{}] Failed to fetch attributes for scope: {}", deviceId, scope); | |
361 | - throw new RuntimeException(e); | |
362 | - } | |
363 | - } | |
364 | - | |
365 | - public void processCredentialsUpdate() { | |
467 | + void processCredentialsUpdate() { | |
366 | 468 | sessions.forEach((k, v) -> { |
367 | 469 | sendMsgToSessionActor(new BasicToDeviceSessionActorMsg(new SessionCloseNotification(), k), v.getServer()); |
368 | 470 | }); |
... | ... | @@ -370,8 +472,12 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
370 | 472 | rpcSubscriptions.clear(); |
371 | 473 | } |
372 | 474 | |
373 | - public void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { | |
475 | + void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) { | |
374 | 476 | this.deviceName = msg.getDeviceName(); |
375 | 477 | this.deviceType = msg.getDeviceType(); |
478 | + this.defaultMetaData = new TbMsgMetaData(); | |
479 | + this.defaultMetaData.putValue("deviceName", deviceName); | |
480 | + this.defaultMetaData.putValue("deviceType", deviceType); | |
376 | 481 | } |
482 | + | |
377 | 483 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorToRuleEngineMsg.java
renamed from
application/src/test/java/org/thingsboard/server/controller/sql/PluginControllerSqlTest.java
... | ... | @@ -13,14 +13,26 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.controller.sql; | |
16 | +package org.thingsboard.server.actors.device; | |
17 | 17 | |
18 | -import org.thingsboard.server.controller.BasePluginControllerTest; | |
19 | -import org.thingsboard.server.dao.service.DaoSqlTest; | |
18 | +import akka.actor.ActorRef; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.id.TenantId; | |
21 | +import org.thingsboard.server.common.msg.MsgType; | |
22 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
23 | +import org.thingsboard.server.common.msg.TbMsg; | |
20 | 24 | |
21 | 25 | /** |
22 | - * Created by Valerii Sosliuk on 6/28/2017. | |
26 | + * Created by ashvayka on 15.03.18. | |
23 | 27 | */ |
24 | -@DaoSqlTest | |
25 | -public class PluginControllerSqlTest extends BasePluginControllerTest { | |
28 | +@Data | |
29 | +public final class DeviceActorToRuleEngineMsg implements TbActorMsg { | |
30 | + | |
31 | + private final ActorRef callbackRef; | |
32 | + private final TbMsg tbMsg; | |
33 | + | |
34 | + @Override | |
35 | + public MsgType getMsgType() { | |
36 | + return MsgType.DEVICE_ACTOR_TO_RULE_ENGINE_MSG; | |
37 | + } | |
26 | 38 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/device/PendingSessionMsgData.java
renamed from
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/rpc/RpcPluginConfiguration.java
... | ... | @@ -13,14 +13,24 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.extensions.core.plugin.rpc; | |
16 | +package org.thingsboard.server.actors.device; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | +import org.thingsboard.server.common.data.id.SessionId; | |
20 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
21 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
22 | + | |
23 | +import java.util.Optional; | |
19 | 24 | |
20 | 25 | /** |
21 | - * @author Andrew Shvayka | |
26 | + * Created by ashvayka on 17.04.18. | |
22 | 27 | */ |
23 | 28 | @Data |
24 | -public class RpcPluginConfiguration { | |
25 | - private long defaultTimeout; | |
29 | +public final class PendingSessionMsgData { | |
30 | + | |
31 | + private final SessionId sessionId; | |
32 | + private final Optional<ServerAddress> serverAddress; | |
33 | + private final SessionMsgType sessionMsgType; | |
34 | + private final int requestId; | |
35 | + | |
26 | 36 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/device/RuleEngineQueuePutAckMsg.java
renamed from
application/src/test/java/org/thingsboard/server/controller/nosql/PluginControllerNoSqlTest.java
... | ... | @@ -13,14 +13,24 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.controller.nosql; | |
16 | +package org.thingsboard.server.actors.device; | |
17 | 17 | |
18 | -import org.thingsboard.server.controller.BasePluginControllerTest; | |
19 | -import org.thingsboard.server.dao.service.DaoNoSqlTest; | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.msg.MsgType; | |
20 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
21 | + | |
22 | +import java.util.UUID; | |
20 | 23 | |
21 | 24 | /** |
22 | - * Created by Valerii Sosliuk on 6/28/2017. | |
25 | + * Created by ashvayka on 15.03.18. | |
23 | 26 | */ |
24 | -@DaoNoSqlTest | |
25 | -public class PluginControllerNoSqlTest extends BasePluginControllerTest { | |
27 | +@Data | |
28 | +public final class RuleEngineQueuePutAckMsg implements TbActorMsg { | |
29 | + | |
30 | + private final UUID id; | |
31 | + | |
32 | + @Override | |
33 | + public MsgType getMsgType() { | |
34 | + return MsgType.RULE_ENGINE_QUEUE_PUT_ACK_MSG; | |
35 | + } | |
26 | 36 | } | ... | ... |
... | ... | @@ -16,13 +16,13 @@ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | |
19 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; | |
20 | 20 | |
21 | 21 | /** |
22 | 22 | * @author Andrew Shvayka |
23 | 23 | */ |
24 | 24 | @Data |
25 | 25 | public class ToDeviceRpcRequestMetadata { |
26 | - private final ToDeviceRpcRequestPluginMsg msg; | |
26 | + private final ToDeviceRpcRequestMsg msg; | |
27 | 27 | private final boolean sent; |
28 | 28 | } | ... | ... |
... | ... | @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
26 | 26 | import org.thingsboard.server.common.msg.TbActorMsg; |
27 | 27 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
28 | 28 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
29 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | |
29 | +import org.thingsboard.server.common.msg.timeout.TimeoutMsg; | |
30 | 30 | import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg; |
31 | 31 | import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg; |
32 | 32 | import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; |
... | ... | @@ -153,6 +153,7 @@ public class PluginActor extends ComponentActor<PluginId, PluginActorMessageProc |
153 | 153 | |
154 | 154 | @Override |
155 | 155 | protected long getErrorPersistFrequency() { |
156 | - return systemContext.getPluginErrorPersistFrequency(); | |
156 | + return 0; | |
157 | +// return systemContext.getPluginErrorPersistFrequency(); | |
157 | 158 | } |
158 | 159 | } | ... | ... |
... | ... | @@ -30,13 +30,14 @@ import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
30 | 30 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
31 | 31 | import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; |
32 | 32 | import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
33 | -import org.thingsboard.server.common.msg.session.MsgType; | |
33 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
34 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
34 | 35 | import org.thingsboard.server.extensions.api.plugins.Plugin; |
35 | 36 | import org.thingsboard.server.extensions.api.plugins.PluginInitializationException; |
36 | 37 | import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; |
37 | 38 | import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; |
38 | 39 | import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; |
39 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | |
40 | +import org.thingsboard.server.common.msg.timeout.TimeoutMsg; | |
40 | 41 | import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg; |
41 | 42 | import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; |
42 | 43 | import org.thingsboard.server.extensions.api.plugins.ws.msg.PluginWebsocketMsg; |
... | ... | @@ -108,7 +109,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
108 | 109 | } catch (Exception ex) { |
109 | 110 | logger.debug("[{}] Failed to process RuleToPlugin msg: [{}] [{}]", tenantId, msg.getMsg(), ex); |
110 | 111 | RuleToPluginMsg ruleMsg = msg.getMsg(); |
111 | - MsgType responceMsgType = MsgType.RULE_ENGINE_ERROR; | |
112 | + SessionMsgType responceMsgType = SessionMsgType.RULE_ENGINE_ERROR; | |
112 | 113 | Integer requestId = 0; |
113 | 114 | if (ruleMsg.getPayload() instanceof FromDeviceRequestMsg) { |
114 | 115 | requestId = ((FromDeviceRequestMsg) ruleMsg.getPayload()).getRequestId(); |
... | ... | @@ -216,7 +217,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
216 | 217 | @Override |
217 | 218 | public void onStop(ActorContext context) { |
218 | 219 | onStop(); |
219 | - scheduleMsgWithDelay(context, new PluginTerminationMsg(entityId), systemContext.getPluginActorTerminationDelay()); | |
220 | +// scheduleMsgWithDelay(context, new PluginTerminationMsg(entityId), systemContext.getPluginActorTerminationDelay()); | |
220 | 221 | } |
221 | 222 | |
222 | 223 | private void onStop() { | ... | ... |
... | ... | @@ -36,9 +36,12 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
36 | 36 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
37 | 37 | import org.thingsboard.server.common.data.relation.EntityRelation; |
38 | 38 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
39 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | |
39 | 40 | import org.thingsboard.server.common.data.rule.RuleChain; |
40 | 41 | import org.thingsboard.server.common.data.rule.RuleMetaData; |
41 | 42 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
43 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
44 | +import org.thingsboard.server.common.msg.timeout.TimeoutMsg; | |
42 | 45 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
43 | 46 | import org.thingsboard.server.extensions.api.plugins.PluginApiCallSecurityContext; |
44 | 47 | import org.thingsboard.server.extensions.api.plugins.PluginCallback; |
... | ... | @@ -348,7 +351,7 @@ public final class PluginProcessingContext implements PluginContext { |
348 | 351 | throw new IllegalStateException("Not Implemented!"); |
349 | 352 | } |
350 | 353 | } else { |
351 | - callback.onSuccess(this, ValidationResult.ok()); | |
354 | + callback.onSuccess(this, ValidationResult.ok(null)); | |
352 | 355 | } |
353 | 356 | } |
354 | 357 | |
... | ... | @@ -366,7 +369,7 @@ public final class PluginProcessingContext implements PluginContext { |
366 | 369 | } else if (ctx.isCustomerUser() && !device.getCustomerId().equals(ctx.getCustomerId())) { |
367 | 370 | return ValidationResult.accessDenied("Device doesn't belong to the current Customer!"); |
368 | 371 | } else { |
369 | - return ValidationResult.ok(); | |
372 | + return ValidationResult.ok(null); | |
370 | 373 | } |
371 | 374 | } |
372 | 375 | })); |
... | ... | @@ -387,7 +390,7 @@ public final class PluginProcessingContext implements PluginContext { |
387 | 390 | } else if (ctx.isCustomerUser() && !asset.getCustomerId().equals(ctx.getCustomerId())) { |
388 | 391 | return ValidationResult.accessDenied("Asset doesn't belong to the current Customer!"); |
389 | 392 | } else { |
390 | - return ValidationResult.ok(); | |
393 | + return ValidationResult.ok(null); | |
391 | 394 | } |
392 | 395 | } |
393 | 396 | })); |
... | ... | @@ -408,7 +411,7 @@ public final class PluginProcessingContext implements PluginContext { |
408 | 411 | } else if (ctx.isSystemAdmin() && !rule.getTenantId().isNullUid()) { |
409 | 412 | return ValidationResult.accessDenied("Rule is not in system scope!"); |
410 | 413 | } else { |
411 | - return ValidationResult.ok(); | |
414 | + return ValidationResult.ok(null); | |
412 | 415 | } |
413 | 416 | } |
414 | 417 | })); |
... | ... | @@ -429,7 +432,7 @@ public final class PluginProcessingContext implements PluginContext { |
429 | 432 | } else if (ctx.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) { |
430 | 433 | return ValidationResult.accessDenied("Rule chain is not in system scope!"); |
431 | 434 | } else { |
432 | - return ValidationResult.ok(); | |
435 | + return ValidationResult.ok(null); | |
433 | 436 | } |
434 | 437 | } |
435 | 438 | })); |
... | ... | @@ -451,7 +454,7 @@ public final class PluginProcessingContext implements PluginContext { |
451 | 454 | } else if (ctx.isSystemAdmin() && !plugin.getTenantId().isNullUid()) { |
452 | 455 | return ValidationResult.accessDenied("Plugin is not in system scope!"); |
453 | 456 | } else { |
454 | - return ValidationResult.ok(); | |
457 | + return ValidationResult.ok(null); | |
455 | 458 | } |
456 | 459 | } |
457 | 460 | })); |
... | ... | @@ -472,7 +475,7 @@ public final class PluginProcessingContext implements PluginContext { |
472 | 475 | } else if (ctx.isCustomerUser() && !customer.getId().equals(ctx.getCustomerId())) { |
473 | 476 | return ValidationResult.accessDenied("Customer doesn't relate to the currently authorized customer user!"); |
474 | 477 | } else { |
475 | - return ValidationResult.ok(); | |
478 | + return ValidationResult.ok(null); | |
476 | 479 | } |
477 | 480 | } |
478 | 481 | })); |
... | ... | @@ -483,7 +486,7 @@ public final class PluginProcessingContext implements PluginContext { |
483 | 486 | if (ctx.isCustomerUser()) { |
484 | 487 | callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); |
485 | 488 | } else if (ctx.isSystemAdmin()) { |
486 | - callback.onSuccess(this, ValidationResult.ok()); | |
489 | + callback.onSuccess(this, ValidationResult.ok(null)); | |
487 | 490 | } else { |
488 | 491 | ListenableFuture<Tenant> tenantFuture = pluginCtx.tenantService.findTenantByIdAsync(new TenantId(entityId.getId())); |
489 | 492 | Futures.addCallback(tenantFuture, getCallback(callback, tenant -> { |
... | ... | @@ -492,7 +495,7 @@ public final class PluginProcessingContext implements PluginContext { |
492 | 495 | } else if (!tenant.getId().equals(ctx.getTenantId())) { |
493 | 496 | return ValidationResult.accessDenied("Tenant doesn't relate to the currently authorized user!"); |
494 | 497 | } else { |
495 | - return ValidationResult.ok(); | |
498 | + return ValidationResult.ok(null); | |
496 | 499 | } |
497 | 500 | })); |
498 | 501 | } | ... | ... |
... | ... | @@ -18,13 +18,13 @@ package org.thingsboard.server.actors.plugin; |
18 | 18 | import akka.actor.ActorRef; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | -import org.thingsboard.server.common.data.Device; | |
22 | 21 | import org.thingsboard.server.common.data.id.DeviceId; |
23 | -import org.thingsboard.server.common.data.id.EntityId; | |
22 | +import org.thingsboard.server.common.data.id.PluginId; | |
24 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
25 | 24 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
25 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
26 | +import org.thingsboard.server.common.msg.timeout.TimeoutMsg; | |
26 | 27 | import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; |
27 | -import org.thingsboard.server.common.data.id.PluginId; | |
28 | 28 | import org.thingsboard.server.dao.asset.AssetService; |
29 | 29 | import org.thingsboard.server.dao.attributes.AttributesService; |
30 | 30 | import org.thingsboard.server.dao.audit.AuditLogService; |
... | ... | @@ -37,9 +37,6 @@ import org.thingsboard.server.dao.rule.RuleService; |
37 | 37 | import org.thingsboard.server.dao.tenant.TenantService; |
38 | 38 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
39 | 39 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
40 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | |
41 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest; | |
42 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | |
43 | 40 | import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; |
44 | 41 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
45 | 42 | import scala.concurrent.duration.Duration; |
... | ... | @@ -108,8 +105,8 @@ public final class SharedPluginProcessingContext { |
108 | 105 | |
109 | 106 | public void sendRpcRequest(ToDeviceRpcRequest msg) { |
110 | 107 | log.trace("[{}] Forwarding msg {} to device actor!", pluginId, msg); |
111 | - ToDeviceRpcRequestPluginMsg rpcMsg = new ToDeviceRpcRequestPluginMsg(pluginId, tenantId, msg); | |
112 | - forward(msg.getDeviceId(), rpcMsg, rpcService::tell); | |
108 | +// ToDeviceRpcRequestPluginMsg rpcMsg = new ToDeviceRpcRequestPluginMsg(pluginId, tenantId, msg); | |
109 | +// forward(msg.getDeviceId(), rpcMsg, rpcService::tell); | |
113 | 110 | } |
114 | 111 | |
115 | 112 | private <T> void forward(DeviceId deviceId, T msg, BiConsumer<ServerAddress, T> rpcFunction) { | ... | ... |
... | ... | @@ -20,29 +20,30 @@ import lombok.Data; |
20 | 20 | |
21 | 21 | @Data |
22 | 22 | @AllArgsConstructor |
23 | -public class ValidationResult { | |
23 | +public class ValidationResult<V> { | |
24 | 24 | |
25 | 25 | private final ValidationResultCode resultCode; |
26 | 26 | private final String message; |
27 | + private final V v; | |
27 | 28 | |
28 | - public static ValidationResult ok() { | |
29 | - return new ValidationResult(ValidationResultCode.OK, "Ok"); | |
29 | + public static <V> ValidationResult<V> ok(V v) { | |
30 | + return new ValidationResult<>(ValidationResultCode.OK, "Ok", v); | |
30 | 31 | } |
31 | 32 | |
32 | - public static ValidationResult accessDenied(String message) { | |
33 | - return new ValidationResult(ValidationResultCode.ACCESS_DENIED, message); | |
33 | + public static <V> ValidationResult<V> accessDenied(String message) { | |
34 | + return new ValidationResult<>(ValidationResultCode.ACCESS_DENIED, message, null); | |
34 | 35 | } |
35 | 36 | |
36 | - public static ValidationResult entityNotFound(String message) { | |
37 | - return new ValidationResult(ValidationResultCode.ENTITY_NOT_FOUND, message); | |
37 | + public static <V> ValidationResult<V> entityNotFound(String message) { | |
38 | + return new ValidationResult<>(ValidationResultCode.ENTITY_NOT_FOUND, message, null); | |
38 | 39 | } |
39 | 40 | |
40 | - public static ValidationResult unauthorized(String message) { | |
41 | - return new ValidationResult(ValidationResultCode.UNAUTHORIZED, message); | |
41 | + public static <V> ValidationResult<V> unauthorized(String message) { | |
42 | + return new ValidationResult<>(ValidationResultCode.UNAUTHORIZED, message, null); | |
42 | 43 | } |
43 | 44 | |
44 | - public static ValidationResult internalError(String message) { | |
45 | - return new ValidationResult(ValidationResultCode.INTERNAL_ERROR, message); | |
45 | + public static <V> ValidationResult<V> internalError(String message) { | |
46 | + return new ValidationResult<>(ValidationResultCode.INTERNAL_ERROR, message, null); | |
46 | 47 | } |
47 | 48 | |
48 | 49 | } | ... | ... |
... | ... | @@ -24,10 +24,12 @@ import org.thingsboard.server.actors.service.ActorService; |
24 | 24 | import org.thingsboard.server.common.data.id.DeviceId; |
25 | 25 | import org.thingsboard.server.common.data.id.PluginId; |
26 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | |
27 | 28 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
28 | 29 | import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
29 | 30 | import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; |
30 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
31 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
32 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
31 | 33 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
32 | 34 | import org.thingsboard.server.extensions.api.plugins.msg.*; |
33 | 35 | import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; |
... | ... | @@ -35,6 +37,7 @@ import org.thingsboard.server.extensions.api.plugins.rpc.RpcMsg; |
35 | 37 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
36 | 38 | import org.thingsboard.server.service.cluster.rpc.GrpcSession; |
37 | 39 | import org.thingsboard.server.service.cluster.rpc.GrpcSessionListener; |
40 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; | |
38 | 41 | |
39 | 42 | import java.io.Serializable; |
40 | 43 | import java.util.UUID; |
... | ... | @@ -83,7 +86,7 @@ public class BasicRpcSessionListener implements GrpcSessionListener { |
83 | 86 | @Override |
84 | 87 | public void onToDeviceActorRpcMsg(GrpcSession session, ClusterAPIProtos.ToDeviceActorRpcMessage msg) { |
85 | 88 | log.trace("{} session [{}] received device actor msg {}", getType(session), session.getRemoteServer(), msg); |
86 | - service.onMsg((ToDeviceActorMsg) deserialize(msg.getData().toByteArray())); | |
89 | + service.onMsg((DeviceToDeviceActorMsg) deserialize(msg.getData().toByteArray())); | |
87 | 90 | } |
88 | 91 | |
89 | 92 | @Override |
... | ... | @@ -139,28 +142,20 @@ public class BasicRpcSessionListener implements GrpcSessionListener { |
139 | 142 | return new UUID(uid.getPluginUuidMsb(), uid.getPluginUuidLsb()); |
140 | 143 | } |
141 | 144 | |
142 | - private static ToDeviceRpcRequestPluginMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) { | |
143 | - ClusterAPIProtos.PluginAddress address = msg.getAddress(); | |
144 | - TenantId pluginTenantId = new TenantId(toUUID(address.getTenantId())); | |
145 | - PluginId pluginId = new PluginId(toUUID(address.getPluginId())); | |
146 | - | |
145 | + private static ToDeviceRpcRequestMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToDeviceRpcRequestRpcMessage msg) { | |
147 | 146 | TenantId deviceTenantId = new TenantId(toUUID(msg.getDeviceTenantId())); |
148 | 147 | DeviceId deviceId = new DeviceId(toUUID(msg.getDeviceId())); |
149 | 148 | |
150 | 149 | ToDeviceRpcRequestBody requestBody = new ToDeviceRpcRequestBody(msg.getMethod(), msg.getParams()); |
151 | - ToDeviceRpcRequest request = new ToDeviceRpcRequest(toUUID(msg.getMsgId()), null, deviceTenantId, deviceId, msg.getOneway(), msg.getExpTime(), requestBody); | |
150 | + ToDeviceRpcRequest request = new ToDeviceRpcRequest(toUUID(msg.getMsgId()), deviceTenantId, deviceId, msg.getOneway(), msg.getExpTime(), requestBody); | |
152 | 151 | |
153 | - return new ToDeviceRpcRequestPluginMsg(serverAddress, pluginId, pluginTenantId, request); | |
152 | + return new ToDeviceRpcRequestMsg(serverAddress, request); | |
154 | 153 | } |
155 | 154 | |
156 | 155 | private static ToPluginRpcResponseDeviceMsg deserialize(ServerAddress serverAddress, ClusterAPIProtos.ToPluginRpcResponseRpcMessage msg) { |
157 | - ClusterAPIProtos.PluginAddress address = msg.getAddress(); | |
158 | - TenantId pluginTenantId = new TenantId(toUUID(address.getTenantId())); | |
159 | - PluginId pluginId = new PluginId(toUUID(address.getPluginId())); | |
160 | - | |
161 | 156 | RpcError error = !StringUtils.isEmpty(msg.getError()) ? RpcError.valueOf(msg.getError()) : null; |
162 | 157 | FromDeviceRpcResponse response = new FromDeviceRpcResponse(toUUID(msg.getMsgId()), msg.getResponse(), error); |
163 | - return new ToPluginRpcResponseDeviceMsg(pluginId, pluginTenantId, response); | |
158 | + return new ToPluginRpcResponseDeviceMsg(null, null, response); | |
164 | 159 | } |
165 | 160 | |
166 | 161 | @SuppressWarnings("unchecked") | ... | ... |
... | ... | @@ -18,6 +18,7 @@ package org.thingsboard.server.actors.ruleChain; |
18 | 18 | import akka.actor.OneForOneStrategy; |
19 | 19 | import akka.actor.SupervisorStrategy; |
20 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | +import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; | |
21 | 22 | import org.thingsboard.server.actors.service.ComponentActor; |
22 | 23 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
23 | 24 | import org.thingsboard.server.common.data.id.RuleChainId; |
... | ... | @@ -44,6 +45,9 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe |
44 | 45 | case SERVICE_TO_RULE_ENGINE_MSG: |
45 | 46 | processor.onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); |
46 | 47 | break; |
48 | + case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: | |
49 | + processor.onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); | |
50 | + break; | |
47 | 51 | case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG: |
48 | 52 | processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg); |
49 | 53 | break; | ... | ... |
... | ... | @@ -20,6 +20,8 @@ import akka.actor.ActorRef; |
20 | 20 | import akka.actor.Props; |
21 | 21 | import akka.event.LoggingAdapter; |
22 | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | +import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; | |
24 | +import org.thingsboard.server.actors.device.RuleEngineQueuePutAckMsg; | |
23 | 25 | import org.thingsboard.server.actors.service.DefaultActorService; |
24 | 26 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
25 | 27 | import org.thingsboard.server.common.data.EntityType; |
... | ... | @@ -58,6 +60,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
58 | 60 | |
59 | 61 | private RuleNodeId firstId; |
60 | 62 | private RuleNodeCtx firstNode; |
63 | + private boolean started; | |
61 | 64 | |
62 | 65 | RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext |
63 | 66 | , LoggingAdapter logger, ActorRef parent, ActorRef self) { |
... | ... | @@ -71,14 +74,19 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
71 | 74 | |
72 | 75 | @Override |
73 | 76 | public void start(ActorContext context) throws Exception { |
74 | - RuleChain ruleChain = service.findRuleChainById(entityId); | |
75 | - List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId); | |
76 | - // Creating and starting the actors; | |
77 | - for (RuleNode ruleNode : ruleNodeList) { | |
78 | - ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); | |
79 | - nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); | |
77 | + if (!started) { | |
78 | + RuleChain ruleChain = service.findRuleChainById(entityId); | |
79 | + List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId); | |
80 | + // Creating and starting the actors; | |
81 | + for (RuleNode ruleNode : ruleNodeList) { | |
82 | + ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); | |
83 | + nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); | |
84 | + } | |
85 | + initRoutes(ruleChain, ruleNodeList); | |
86 | + started = true; | |
87 | + } else { | |
88 | + onUpdate(context); | |
80 | 89 | } |
81 | - initRoutes(ruleChain, ruleNodeList); | |
82 | 90 | } |
83 | 91 | |
84 | 92 | @Override |
... | ... | @@ -113,6 +121,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
113 | 121 | nodeActors.clear(); |
114 | 122 | nodeRoutes.clear(); |
115 | 123 | context.stop(self); |
124 | + started = false; | |
116 | 125 | } |
117 | 126 | |
118 | 127 | @Override |
... | ... | @@ -157,6 +166,14 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
157 | 166 | pushMsgToNode(firstNode, tbMsg); |
158 | 167 | } |
159 | 168 | |
169 | + public void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg envelope) { | |
170 | + checkActive(); | |
171 | + TbMsg tbMsg = envelope.getTbMsg(); | |
172 | + //TODO: push to queue and act on ack in async way | |
173 | + pushMsgToNode(firstNode, tbMsg); | |
174 | + envelope.getCallbackRef().tell(new RuleEngineQueuePutAckMsg(tbMsg.getId()), self); | |
175 | + } | |
176 | + | |
160 | 177 | void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { |
161 | 178 | checkActive(); |
162 | 179 | RuleNodeId originator = envelope.getOriginator(); |
... | ... | @@ -191,5 +208,4 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
191 | 208 | nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self); |
192 | 209 | } |
193 | 210 | } |
194 | - | |
195 | 211 | } | ... | ... |
... | ... | @@ -31,31 +31,29 @@ import org.thingsboard.server.dao.rule.RuleChainService; |
31 | 31 | public abstract class RuleChainManagerActor extends ContextAwareActor { |
32 | 32 | |
33 | 33 | protected final RuleChainManager ruleChainManager; |
34 | - protected final PluginManager pluginManager; | |
35 | 34 | protected final RuleChainService ruleChainService; |
36 | 35 | |
37 | 36 | public RuleChainManagerActor(ActorSystemContext systemContext, RuleChainManager ruleChainManager, PluginManager pluginManager) { |
38 | 37 | super(systemContext); |
39 | 38 | this.ruleChainManager = ruleChainManager; |
40 | - this.pluginManager = pluginManager; | |
41 | 39 | this.ruleChainService = systemContext.getRuleChainService(); |
42 | 40 | } |
43 | 41 | |
44 | 42 | protected void initRuleChains() { |
45 | - pluginManager.init(this.context()); | |
46 | 43 | ruleChainManager.init(this.context()); |
47 | 44 | } |
48 | 45 | |
49 | 46 | protected ActorRef getEntityActorRef(EntityId entityId) { |
50 | 47 | ActorRef target = null; |
51 | 48 | switch (entityId.getEntityType()) { |
52 | - case PLUGIN: | |
53 | - target = pluginManager.getOrCreateActor(this.context(), (PluginId) entityId); | |
54 | - break; | |
55 | 49 | case RULE_CHAIN: |
56 | 50 | target = ruleChainManager.getOrCreateActor(this.context(), (RuleChainId) entityId); |
57 | 51 | break; |
58 | 52 | } |
59 | 53 | return target; |
60 | 54 | } |
55 | + | |
56 | + protected void broadcast(Object msg) { | |
57 | + ruleChainManager.broadcast(msg); | |
58 | + } | |
61 | 59 | } | ... | ... |
... | ... | @@ -39,7 +39,7 @@ import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
39 | 39 | import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; |
40 | 40 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
41 | 41 | import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; |
42 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
42 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
43 | 43 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
44 | 44 | import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg; |
45 | 45 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
... | ... | @@ -156,7 +156,7 @@ public class DefaultActorService implements ActorService { |
156 | 156 | } |
157 | 157 | |
158 | 158 | @Override |
159 | - public void onMsg(ToDeviceActorMsg msg) { | |
159 | + public void onMsg(DeviceToDeviceActorMsg msg) { | |
160 | 160 | log.trace("Processing device rpc msg: {}", msg); |
161 | 161 | appActor.tell(msg, ActorRef.noSender()); |
162 | 162 | } | ... | ... |
... | ... | @@ -22,12 +22,11 @@ import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
22 | 22 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
23 | 23 | import org.thingsboard.server.common.msg.core.*; |
24 | 24 | import org.thingsboard.server.common.msg.core.SessionCloseMsg; |
25 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
25 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
26 | 26 | import org.thingsboard.server.common.msg.session.*; |
27 | 27 | |
28 | 28 | import akka.actor.ActorContext; |
29 | 29 | import akka.event.LoggingAdapter; |
30 | -import org.thingsboard.server.common.msg.session.ctrl.*; | |
31 | 30 | import org.thingsboard.server.common.msg.session.ex.SessionException; |
32 | 31 | |
33 | 32 | import java.util.HashMap; |
... | ... | @@ -37,7 +36,7 @@ import java.util.Optional; |
37 | 36 | class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
38 | 37 | |
39 | 38 | private boolean firstMsg = true; |
40 | - private Map<Integer, ToDeviceActorMsg> pendingMap = new HashMap<>(); | |
39 | + private Map<Integer, DeviceToDeviceActorMsg> pendingMap = new HashMap<>(); | |
41 | 40 | private Optional<ServerAddress> currentTargetServer; |
42 | 41 | private boolean subscribedToAttributeUpdates; |
43 | 42 | private boolean subscribedToRpcCommands; |
... | ... | @@ -53,7 +52,7 @@ class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
53 | 52 | toDeviceMsg(new SessionOpenMsg()).ifPresent(m -> forwardToAppActor(ctx, m)); |
54 | 53 | firstMsg = false; |
55 | 54 | } |
56 | - ToDeviceActorMsg pendingMsg = toDeviceMsg(msg); | |
55 | + DeviceToDeviceActorMsg pendingMsg = toDeviceMsg(msg); | |
57 | 56 | FromDeviceMsg fromDeviceMsg = pendingMsg.getPayload(); |
58 | 57 | switch (fromDeviceMsg.getMsgType()) { |
59 | 58 | case POST_TELEMETRY_REQUEST: |
... | ... | @@ -86,8 +85,8 @@ class ASyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
86 | 85 | @Override |
87 | 86 | public void processToDeviceMsg(ActorContext context, ToDeviceMsg msg) { |
88 | 87 | try { |
89 | - if (msg.getMsgType() != MsgType.SESSION_CLOSE) { | |
90 | - switch (msg.getMsgType()) { | |
88 | + if (msg.getSessionMsgType() != SessionMsgType.SESSION_CLOSE) { | |
89 | + switch (msg.getSessionMsgType()) { | |
91 | 90 | case STATUS_CODE_RESPONSE: |
92 | 91 | case GET_ATTRIBUTES_RESPONSE: |
93 | 92 | ResponseMsg responseMsg = (ResponseMsg) msg; | ... | ... |
... | ... | @@ -22,8 +22,8 @@ import org.thingsboard.server.common.data.id.DeviceId; |
22 | 22 | import org.thingsboard.server.common.data.id.SessionId; |
23 | 23 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
24 | 24 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
25 | -import org.thingsboard.server.common.msg.device.BasicToDeviceActorMsg; | |
26 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
25 | +import org.thingsboard.server.common.msg.device.BasicDeviceToDeviceActorMsg; | |
26 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
27 | 27 | import org.thingsboard.server.common.msg.session.*; |
28 | 28 | import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
29 | 29 | |
... | ... | @@ -37,7 +37,7 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP |
37 | 37 | |
38 | 38 | protected final SessionId sessionId; |
39 | 39 | protected SessionContext sessionCtx; |
40 | - protected ToDeviceActorMsg toDeviceActorMsgPrototype; | |
40 | + protected DeviceToDeviceActorMsg deviceToDeviceActorMsgPrototype; | |
41 | 41 | |
42 | 42 | protected AbstractSessionActorMsgProcessor(ActorSystemContext ctx, LoggingAdapter logger, SessionId sessionId) { |
43 | 43 | super(ctx, logger); |
... | ... | @@ -64,29 +64,29 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP |
64 | 64 | |
65 | 65 | protected void updateSessionCtx(ToDeviceActorSessionMsg msg, SessionType type) { |
66 | 66 | sessionCtx = msg.getSessionMsg().getSessionContext(); |
67 | - toDeviceActorMsgPrototype = new BasicToDeviceActorMsg(msg, type); | |
67 | + deviceToDeviceActorMsgPrototype = new BasicDeviceToDeviceActorMsg(msg, type); | |
68 | 68 | } |
69 | 69 | |
70 | - protected ToDeviceActorMsg toDeviceMsg(ToDeviceActorSessionMsg msg) { | |
70 | + protected DeviceToDeviceActorMsg toDeviceMsg(ToDeviceActorSessionMsg msg) { | |
71 | 71 | AdaptorToSessionActorMsg adaptorMsg = msg.getSessionMsg(); |
72 | - return new BasicToDeviceActorMsg(toDeviceActorMsgPrototype, adaptorMsg.getMsg()); | |
72 | + return new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, adaptorMsg.getMsg()); | |
73 | 73 | } |
74 | 74 | |
75 | - protected Optional<ToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) { | |
76 | - if (toDeviceActorMsgPrototype != null) { | |
77 | - return Optional.of(new BasicToDeviceActorMsg(toDeviceActorMsgPrototype, msg)); | |
75 | + protected Optional<DeviceToDeviceActorMsg> toDeviceMsg(FromDeviceMsg msg) { | |
76 | + if (deviceToDeviceActorMsgPrototype != null) { | |
77 | + return Optional.of(new BasicDeviceToDeviceActorMsg(deviceToDeviceActorMsgPrototype, msg)); | |
78 | 78 | } else { |
79 | 79 | return Optional.empty(); |
80 | 80 | } |
81 | 81 | } |
82 | 82 | |
83 | - protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, ToDeviceActorMsg toForward) { | |
83 | + protected Optional<ServerAddress> forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward) { | |
84 | 84 | Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); |
85 | 85 | forwardToAppActor(ctx, toForward, address); |
86 | 86 | return address; |
87 | 87 | } |
88 | 88 | |
89 | - protected Optional<ServerAddress> forwardToAppActorIfAdressChanged(ActorContext ctx, ToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) { | |
89 | + protected Optional<ServerAddress> forwardToAppActorIfAdressChanged(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> oldAddress) { | |
90 | 90 | Optional<ServerAddress> newAddress = systemContext.getRoutingService().resolveById(toForward.getDeviceId()); |
91 | 91 | if (!newAddress.equals(oldAddress)) { |
92 | 92 | if (newAddress.isPresent()) { |
... | ... | @@ -99,7 +99,7 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP |
99 | 99 | return newAddress; |
100 | 100 | } |
101 | 101 | |
102 | - protected void forwardToAppActor(ActorContext ctx, ToDeviceActorMsg toForward, Optional<ServerAddress> address) { | |
102 | + protected void forwardToAppActor(ActorContext ctx, DeviceToDeviceActorMsg toForward, Optional<ServerAddress> address) { | |
103 | 103 | if (address.isPresent()) { |
104 | 104 | systemContext.getRpcService().tell(address.get(), |
105 | 105 | toForward.toOtherAddress(systemContext.getRoutingService().getCurrentServer())); |
... | ... | @@ -114,6 +114,6 @@ abstract class AbstractSessionActorMsgProcessor extends AbstractContextAwareMsgP |
114 | 114 | } |
115 | 115 | |
116 | 116 | public DeviceId getDeviceId() { |
117 | - return toDeviceActorMsgPrototype.getDeviceId(); | |
117 | + return deviceToDeviceActorMsgPrototype.getDeviceId(); | |
118 | 118 | } |
119 | 119 | } | ... | ... |
... | ... | @@ -20,7 +20,7 @@ import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
20 | 20 | import org.thingsboard.server.common.data.id.SessionId; |
21 | 21 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
22 | 22 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
23 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
23 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
24 | 24 | import org.thingsboard.server.common.msg.session.*; |
25 | 25 | import org.thingsboard.server.common.msg.session.ToDeviceActorSessionMsg; |
26 | 26 | import org.thingsboard.server.common.msg.session.ctrl.SessionCloseMsg; |
... | ... | @@ -32,7 +32,7 @@ import akka.event.LoggingAdapter; |
32 | 32 | import java.util.Optional; |
33 | 33 | |
34 | 34 | class SyncMsgProcessor extends AbstractSessionActorMsgProcessor { |
35 | - private ToDeviceActorMsg pendingMsg; | |
35 | + private DeviceToDeviceActorMsg pendingMsg; | |
36 | 36 | private Optional<ServerAddress> currentTargetServer; |
37 | 37 | private boolean pendingResponse; |
38 | 38 | ... | ... |
... | ... | @@ -17,10 +17,9 @@ package org.thingsboard.server.actors.tenant; |
17 | 17 | |
18 | 18 | import akka.actor.ActorRef; |
19 | 19 | import akka.actor.Props; |
20 | -import akka.event.Logging; | |
21 | -import akka.event.LoggingAdapter; | |
22 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 21 | import org.thingsboard.server.actors.device.DeviceActor; |
22 | +import org.thingsboard.server.actors.device.DeviceActorToRuleEngineMsg; | |
24 | 23 | import org.thingsboard.server.actors.plugin.PluginTerminationMsg; |
25 | 24 | import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; |
26 | 25 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
... | ... | @@ -30,7 +29,8 @@ import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager; |
30 | 29 | import org.thingsboard.server.common.data.id.DeviceId; |
31 | 30 | import org.thingsboard.server.common.data.id.TenantId; |
32 | 31 | import org.thingsboard.server.common.msg.TbActorMsg; |
33 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
32 | +import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; | |
33 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
34 | 34 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
35 | 35 | import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
36 | 36 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
... | ... | @@ -64,63 +64,47 @@ public class TenantActor extends RuleChainManagerActor { |
64 | 64 | @Override |
65 | 65 | protected boolean process(TbActorMsg msg) { |
66 | 66 | switch (msg.getMsgType()) { |
67 | + case CLUSTER_EVENT_MSG: | |
68 | + broadcast(msg); | |
69 | + break; | |
67 | 70 | case COMPONENT_LIFE_CYCLE_MSG: |
68 | 71 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
69 | 72 | break; |
70 | 73 | case SERVICE_TO_RULE_ENGINE_MSG: |
71 | 74 | onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); |
72 | 75 | break; |
76 | + case DEVICE_ACTOR_TO_RULE_ENGINE_MSG: | |
77 | + onDeviceActorToRuleEngineMsg((DeviceActorToRuleEngineMsg) msg); | |
78 | + break; | |
79 | + case DEVICE_SESSION_TO_DEVICE_ACTOR_MSG: | |
80 | + case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: | |
81 | + case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: | |
82 | + case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: | |
83 | + case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: | |
84 | + onToDeviceActorMsg((DeviceAwareMsg) msg); | |
85 | + break; | |
73 | 86 | default: |
74 | 87 | return false; |
75 | 88 | } |
76 | 89 | return true; |
77 | 90 | } |
78 | 91 | |
79 | - private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { | |
80 | - ruleChainManager.getRootChainActor().tell(msg, self()); | |
81 | - } | |
82 | - | |
83 | - | |
84 | -// @Override | |
85 | -// public void onReceive(Object msg) throws Exception { | |
86 | -// logger.debug("[{}] Received message: {}", tenantId, msg); | |
87 | -// if (msg instanceof ToDeviceActorMsg) { | |
88 | -// onToDeviceActorMsg((ToDeviceActorMsg) msg); | |
89 | -// } else if (msg instanceof ToPluginActorMsg) { | |
90 | -// onToPluginMsg((ToPluginActorMsg) msg); | |
91 | -// } else if (msg instanceof ToDeviceActorNotificationMsg) { | |
92 | -// onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg); | |
93 | -// } else if (msg instanceof ClusterEventMsg) { | |
94 | -// broadcast(msg); | |
95 | -// } else if (msg instanceof ComponentLifecycleMsg) { | |
96 | -// onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
97 | -// } else if (msg instanceof PluginTerminationMsg) { | |
98 | -// onPluginTerminated((PluginTerminationMsg) msg); | |
99 | -// } else { | |
100 | -// logger.warning("[{}] Unknown message: {}!", tenantId, msg); | |
101 | -// } | |
102 | -// } | |
103 | - | |
104 | - private void broadcast(Object msg) { | |
105 | - pluginManager.broadcast(msg); | |
92 | + @Override | |
93 | + protected void broadcast(Object msg) { | |
94 | + super.broadcast(msg); | |
106 | 95 | deviceActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
107 | 96 | } |
108 | 97 | |
109 | - private void onToDeviceActorMsg(ToDeviceActorMsg msg) { | |
110 | - getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); | |
98 | + private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { | |
99 | + ruleChainManager.getRootChainActor().tell(msg, self()); | |
111 | 100 | } |
112 | 101 | |
113 | - private void onToDeviceActorMsg(ToDeviceActorNotificationMsg msg) { | |
114 | - getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); | |
102 | + private void onDeviceActorToRuleEngineMsg(DeviceActorToRuleEngineMsg msg) { | |
103 | + ruleChainManager.getRootChainActor().tell(msg, self()); | |
115 | 104 | } |
116 | 105 | |
117 | - private void onToPluginMsg(ToPluginActorMsg msg) { | |
118 | - if (msg.getPluginTenantId().equals(tenantId)) { | |
119 | - ActorRef pluginActor = pluginManager.getOrCreateActor(this.context(), msg.getPluginId()); | |
120 | - pluginActor.tell(msg, ActorRef.noSender()); | |
121 | - } else { | |
122 | - context().parent().tell(msg, ActorRef.noSender()); | |
123 | - } | |
106 | + private void onToDeviceActorMsg(DeviceAwareMsg msg) { | |
107 | + getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); | |
124 | 108 | } |
125 | 109 | |
126 | 110 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
... | ... | @@ -132,11 +116,6 @@ public class TenantActor extends RuleChainManagerActor { |
132 | 116 | } |
133 | 117 | } |
134 | 118 | |
135 | - private void onPluginTerminated(PluginTerminationMsg msg) { | |
136 | - pluginManager.remove(msg.getId()); | |
137 | - } | |
138 | - | |
139 | - | |
140 | 119 | private ActorRef getOrCreateDeviceActor(DeviceId deviceId) { |
141 | 120 | return deviceActors.computeIfAbsent(deviceId, k -> context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId)) |
142 | 121 | .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), deviceId.toString())); | ... | ... |
... | ... | @@ -606,7 +606,7 @@ public abstract class BaseController { |
606 | 606 | auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo); |
607 | 607 | } |
608 | 608 | |
609 | - protected static Exception toException(Throwable error) { | |
609 | + public static Exception toException(Throwable error) { | |
610 | 610 | return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); |
611 | 611 | } |
612 | 612 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.controller; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | +import com.google.common.util.concurrent.FutureCallback; | |
21 | +import lombok.extern.slf4j.Slf4j; | |
22 | +import org.springframework.beans.factory.annotation.Autowired; | |
23 | +import org.springframework.http.HttpStatus; | |
24 | +import org.springframework.http.ResponseEntity; | |
25 | +import org.springframework.security.access.prepost.PreAuthorize; | |
26 | +import org.springframework.web.bind.annotation.PathVariable; | |
27 | +import org.springframework.web.bind.annotation.RequestBody; | |
28 | +import org.springframework.web.bind.annotation.RequestMapping; | |
29 | +import org.springframework.web.bind.annotation.RequestMethod; | |
30 | +import org.springframework.web.bind.annotation.ResponseBody; | |
31 | +import org.springframework.web.bind.annotation.RestController; | |
32 | +import org.springframework.web.context.request.async.DeferredResult; | |
33 | +import org.thingsboard.server.actors.plugin.ValidationResult; | |
34 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
35 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
36 | +import org.thingsboard.server.common.data.id.DeviceId; | |
37 | +import org.thingsboard.server.common.data.id.TenantId; | |
38 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | |
39 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
40 | +import org.thingsboard.server.extensions.api.exception.ToErrorResponseEntity; | |
41 | +import org.thingsboard.server.extensions.api.plugins.PluginConstants; | |
42 | +import org.thingsboard.server.common.data.rpc.RpcRequest; | |
43 | +import org.thingsboard.server.service.rpc.LocalRequestMetaData; | |
44 | +import org.thingsboard.server.service.rpc.DeviceRpcService; | |
45 | +import org.thingsboard.server.service.security.AccessValidator; | |
46 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
47 | + | |
48 | +import javax.annotation.Nullable; | |
49 | +import javax.annotation.PostConstruct; | |
50 | +import javax.annotation.PreDestroy; | |
51 | +import java.io.IOException; | |
52 | +import java.util.Optional; | |
53 | +import java.util.UUID; | |
54 | +import java.util.concurrent.ExecutorService; | |
55 | +import java.util.concurrent.Executors; | |
56 | + | |
57 | +/** | |
58 | + * Created by ashvayka on 22.03.18. | |
59 | + */ | |
60 | +@RestController | |
61 | +@RequestMapping(PluginConstants.RPC_URL_PREFIX) | |
62 | +@Slf4j | |
63 | +public class RpcController extends BaseController { | |
64 | + | |
65 | + public static final int DEFAULT_TIMEOUT = 10000; | |
66 | + protected final ObjectMapper jsonMapper = new ObjectMapper(); | |
67 | + | |
68 | + @Autowired | |
69 | + private DeviceRpcService deviceRpcService; | |
70 | + | |
71 | + @Autowired | |
72 | + private AccessValidator accessValidator; | |
73 | + | |
74 | + private ExecutorService executor; | |
75 | + | |
76 | + @PostConstruct | |
77 | + public void initExecutor() { | |
78 | + executor = Executors.newSingleThreadExecutor(); | |
79 | + } | |
80 | + | |
81 | + @PreDestroy | |
82 | + public void shutdownExecutor() { | |
83 | + if (executor != null) { | |
84 | + executor.shutdownNow(); | |
85 | + } | |
86 | + } | |
87 | + | |
88 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
89 | + @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) | |
90 | + @ResponseBody | |
91 | + public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { | |
92 | + return handleDeviceRPCRequest(true, new DeviceId(UUID.fromString(deviceIdStr)), requestBody); | |
93 | + } | |
94 | + | |
95 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") | |
96 | + @RequestMapping(value = "/twoway/{deviceId}", method = RequestMethod.POST) | |
97 | + @ResponseBody | |
98 | + public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(@PathVariable("deviceId") String deviceIdStr, @RequestBody String requestBody) throws ThingsboardException { | |
99 | + return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody); | |
100 | + } | |
101 | + | |
102 | + | |
103 | + private DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody) throws ThingsboardException { | |
104 | + try { | |
105 | + JsonNode rpcRequestBody = jsonMapper.readTree(requestBody); | |
106 | + RpcRequest cmd = new RpcRequest(rpcRequestBody.get("method").asText(), | |
107 | + jsonMapper.writeValueAsString(rpcRequestBody.get("params"))); | |
108 | + | |
109 | + if (rpcRequestBody.has("timeout")) { | |
110 | + cmd.setTimeout(rpcRequestBody.get("timeout").asLong()); | |
111 | + } | |
112 | + SecurityUser currentUser = getCurrentUser(); | |
113 | + TenantId tenantId = currentUser.getTenantId(); | |
114 | + final DeferredResult<ResponseEntity> response = new DeferredResult<>(); | |
115 | + long timeout = System.currentTimeMillis() + (cmd.getTimeout() != null ? cmd.getTimeout() : DEFAULT_TIMEOUT); | |
116 | + ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(cmd.getMethodName(), cmd.getRequestData()); | |
117 | + accessValidator.validate(currentUser, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() { | |
118 | + @Override | |
119 | + public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) { | |
120 | + | |
121 | + ToDeviceRpcRequest rpcRequest = new ToDeviceRpcRequest(UUID.randomUUID(), | |
122 | + tenantId, | |
123 | + deviceId, | |
124 | + oneWay, | |
125 | + timeout, | |
126 | + body | |
127 | + ); | |
128 | + deviceRpcService.process(rpcRequest, new LocalRequestMetaData(rpcRequest, currentUser, result)); | |
129 | + } | |
130 | + | |
131 | + @Override | |
132 | + public void onFailure(Throwable e) { | |
133 | + ResponseEntity entity; | |
134 | + if (e instanceof ToErrorResponseEntity) { | |
135 | + entity = ((ToErrorResponseEntity) e).toErrorResponseEntity(); | |
136 | + } else { | |
137 | + entity = new ResponseEntity(HttpStatus.UNAUTHORIZED); | |
138 | + } | |
139 | + deviceRpcService.logRpcCall(currentUser, deviceId, body, oneWay, Optional.empty(), e); | |
140 | + response.setResult(entity); | |
141 | + } | |
142 | + })); | |
143 | + return response; | |
144 | + } catch (IOException ioe) { | |
145 | + throw new ThingsboardException("Invalid request body", ioe, ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
146 | + } | |
147 | + } | |
148 | + | |
149 | +} | ... | ... |
... | ... | @@ -15,21 +15,34 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | +import lombok.extern.slf4j.Slf4j; | |
18 | 19 | import org.springframework.beans.factory.annotation.Autowired; |
19 | 20 | import org.springframework.http.HttpStatus; |
20 | 21 | import org.springframework.security.access.prepost.PreAuthorize; |
21 | -import org.springframework.web.bind.annotation.*; | |
22 | +import org.springframework.web.bind.annotation.PathVariable; | |
23 | +import org.springframework.web.bind.annotation.RequestBody; | |
24 | +import org.springframework.web.bind.annotation.RequestMapping; | |
25 | +import org.springframework.web.bind.annotation.RequestMethod; | |
26 | +import org.springframework.web.bind.annotation.RequestParam; | |
27 | +import org.springframework.web.bind.annotation.ResponseBody; | |
28 | +import org.springframework.web.bind.annotation.ResponseStatus; | |
29 | +import org.springframework.web.bind.annotation.RestController; | |
22 | 30 | import org.thingsboard.server.common.data.Tenant; |
31 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
23 | 32 | import org.thingsboard.server.common.data.id.TenantId; |
24 | 33 | import org.thingsboard.server.common.data.page.TextPageData; |
25 | 34 | import org.thingsboard.server.common.data.page.TextPageLink; |
26 | 35 | import org.thingsboard.server.dao.tenant.TenantService; |
27 | -import org.thingsboard.server.common.data.exception.ThingsboardException; | |
36 | +import org.thingsboard.server.service.install.InstallScripts; | |
28 | 37 | |
29 | 38 | @RestController |
30 | 39 | @RequestMapping("/api") |
40 | +@Slf4j | |
31 | 41 | public class TenantController extends BaseController { |
32 | - | |
42 | + | |
43 | + @Autowired | |
44 | + private InstallScripts installScripts; | |
45 | + | |
33 | 46 | @Autowired |
34 | 47 | private TenantService tenantService; |
35 | 48 | |
... | ... | @@ -49,10 +62,15 @@ public class TenantController extends BaseController { |
49 | 62 | |
50 | 63 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
51 | 64 | @RequestMapping(value = "/tenant", method = RequestMethod.POST) |
52 | - @ResponseBody | |
65 | + @ResponseBody | |
53 | 66 | public Tenant saveTenant(@RequestBody Tenant tenant) throws ThingsboardException { |
54 | 67 | try { |
55 | - return checkNotNull(tenantService.saveTenant(tenant)); | |
68 | + boolean newTenant = tenant.getId() == null; | |
69 | + tenant = checkNotNull(tenantService.saveTenant(tenant)); | |
70 | + if (newTenant) { | |
71 | + installScripts.createDefaultRuleChains(tenant.getId()); | |
72 | + } | |
73 | + return tenant; | |
56 | 74 | } catch (Exception e) { |
57 | 75 | throw handleException(e); |
58 | 76 | } |
... | ... | @@ -72,7 +90,7 @@ public class TenantController extends BaseController { |
72 | 90 | } |
73 | 91 | |
74 | 92 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
75 | - @RequestMapping(value = "/tenants", params = { "limit" }, method = RequestMethod.GET) | |
93 | + @RequestMapping(value = "/tenants", params = {"limit"}, method = RequestMethod.GET) | |
76 | 94 | @ResponseBody |
77 | 95 | public TextPageData<Tenant> getTenants(@RequestParam int limit, |
78 | 96 | @RequestParam(required = false) String textSearch, |
... | ... | @@ -85,5 +103,5 @@ public class TenantController extends BaseController { |
85 | 103 | throw handleException(e); |
86 | 104 | } |
87 | 105 | } |
88 | - | |
106 | + | |
89 | 107 | } | ... | ... |
... | ... | @@ -131,8 +131,8 @@ public class ThingsboardInstallService { |
131 | 131 | systemDataLoaderService.createSysAdmin(); |
132 | 132 | systemDataLoaderService.createAdminSettings(); |
133 | 133 | systemDataLoaderService.loadSystemWidgets(); |
134 | - systemDataLoaderService.loadSystemPlugins(); | |
135 | - systemDataLoaderService.loadSystemRules(); | |
134 | +// systemDataLoaderService.loadSystemPlugins(); | |
135 | +// systemDataLoaderService.loadSystemRules(); | |
136 | 136 | |
137 | 137 | if (loadDemo) { |
138 | 138 | log.info("Loading demo data..."); | ... | ... |
... | ... | @@ -19,7 +19,6 @@ import com.google.protobuf.ByteString; |
19 | 19 | import io.grpc.Server; |
20 | 20 | import io.grpc.ServerBuilder; |
21 | 21 | import io.grpc.stub.StreamObserver; |
22 | -import lombok.Setter; | |
23 | 22 | import lombok.extern.slf4j.Slf4j; |
24 | 23 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 24 | import org.springframework.stereotype.Service; |
... | ... | @@ -27,29 +26,24 @@ import org.springframework.util.SerializationUtils; |
27 | 26 | import org.thingsboard.server.actors.rpc.RpcBroadcastMsg; |
28 | 27 | import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; |
29 | 28 | import org.thingsboard.server.actors.rpc.RpcSessionTellMsg; |
30 | -import org.thingsboard.server.actors.service.ActorService; | |
31 | 29 | import org.thingsboard.server.common.data.id.EntityId; |
32 | 30 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
33 | 31 | import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
34 | 32 | import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; |
35 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
33 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
36 | 34 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
37 | 35 | import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; |
38 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest; | |
39 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | |
36 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
40 | 37 | import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg; |
41 | 38 | import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; |
42 | 39 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
43 | 40 | import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; |
44 | -import org.thingsboard.server.service.cluster.discovery.DiscoveryService; | |
45 | 41 | import org.thingsboard.server.service.cluster.discovery.ServerInstance; |
46 | 42 | import org.thingsboard.server.service.cluster.discovery.ServerInstanceService; |
47 | -import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | |
43 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; | |
48 | 44 | |
49 | -import javax.annotation.PostConstruct; | |
50 | 45 | import javax.annotation.PreDestroy; |
51 | 46 | import java.io.IOException; |
52 | -import java.util.Set; | |
53 | 47 | import java.util.UUID; |
54 | 48 | import java.util.concurrent.ConcurrentHashMap; |
55 | 49 | import java.util.concurrent.ConcurrentMap; |
... | ... | @@ -124,7 +118,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI |
124 | 118 | } |
125 | 119 | |
126 | 120 | @Override |
127 | - public void tell(ServerAddress serverAddress, ToDeviceActorMsg toForward) { | |
121 | + public void tell(ServerAddress serverAddress, DeviceToDeviceActorMsg toForward) { | |
128 | 122 | ClusterAPIProtos.ToRpcServerMessage msg = ClusterAPIProtos.ToRpcServerMessage.newBuilder() |
129 | 123 | .setToDeviceActorRpcMsg(toProtoMsg(toForward)).build(); |
130 | 124 | tell(serverAddress, msg); |
... | ... | @@ -138,7 +132,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI |
138 | 132 | } |
139 | 133 | |
140 | 134 | @Override |
141 | - public void tell(ServerAddress serverAddress, ToDeviceRpcRequestPluginMsg toForward) { | |
135 | + public void tell(ServerAddress serverAddress, ToDeviceRpcRequestMsg toForward) { | |
142 | 136 | ClusterAPIProtos.ToRpcServerMessage msg = ClusterAPIProtos.ToRpcServerMessage.newBuilder() |
143 | 137 | .setToDeviceRpcRequestRpcMsg(toProtoMsg(toForward)).build(); |
144 | 138 | tell(serverAddress, msg); |
... | ... | @@ -190,7 +184,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI |
190 | 184 | } |
191 | 185 | } |
192 | 186 | |
193 | - private static ClusterAPIProtos.ToDeviceActorRpcMessage toProtoMsg(ToDeviceActorMsg msg) { | |
187 | + private static ClusterAPIProtos.ToDeviceActorRpcMessage toProtoMsg(DeviceToDeviceActorMsg msg) { | |
194 | 188 | return ClusterAPIProtos.ToDeviceActorRpcMessage.newBuilder().setData( |
195 | 189 | ByteString.copyFrom(SerializationUtils.serialize(msg)) |
196 | 190 | ).build(); |
... | ... | @@ -202,15 +196,10 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI |
202 | 196 | ).build(); |
203 | 197 | } |
204 | 198 | |
205 | - private static ClusterAPIProtos.ToDeviceRpcRequestRpcMessage toProtoMsg(ToDeviceRpcRequestPluginMsg msg) { | |
199 | + private static ClusterAPIProtos.ToDeviceRpcRequestRpcMessage toProtoMsg(ToDeviceRpcRequestMsg msg) { | |
206 | 200 | ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.Builder builder = ClusterAPIProtos.ToDeviceRpcRequestRpcMessage.newBuilder(); |
207 | 201 | ToDeviceRpcRequest request = msg.getMsg(); |
208 | 202 | |
209 | - builder.setAddress(ClusterAPIProtos.PluginAddress.newBuilder() | |
210 | - .setTenantId(toUid(msg.getPluginTenantId().getId())) | |
211 | - .setPluginId(toUid(msg.getPluginId().getId())) | |
212 | - .build()); | |
213 | - | |
214 | 203 | builder.setDeviceTenantId(toUid(msg.getTenantId())); |
215 | 204 | builder.setDeviceId(toUid(msg.getDeviceId())); |
216 | 205 | |
... | ... | @@ -227,11 +216,6 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI |
227 | 216 | ClusterAPIProtos.ToPluginRpcResponseRpcMessage.Builder builder = ClusterAPIProtos.ToPluginRpcResponseRpcMessage.newBuilder(); |
228 | 217 | FromDeviceRpcResponse request = msg.getResponse(); |
229 | 218 | |
230 | - builder.setAddress(ClusterAPIProtos.PluginAddress.newBuilder() | |
231 | - .setTenantId(toUid(msg.getPluginTenantId().getId())) | |
232 | - .setPluginId(toUid(msg.getPluginId().getId())) | |
233 | - .build()); | |
234 | - | |
235 | 219 | builder.setMsgId(toUid(request.getId())); |
236 | 220 | request.getResponse().ifPresent(builder::setResponse); |
237 | 221 | request.getError().ifPresent(e -> builder.setError(e.name())); | ... | ... |
... | ... | @@ -19,12 +19,12 @@ import io.grpc.stub.StreamObserver; |
19 | 19 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
20 | 20 | import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
21 | 21 | import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; |
22 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
22 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
23 | 23 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
24 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | |
25 | 24 | import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg; |
26 | 25 | import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; |
27 | 26 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
27 | +import org.thingsboard.server.service.rpc.ToDeviceRpcRequestMsg; | |
28 | 28 | |
29 | 29 | import java.util.UUID; |
30 | 30 | |
... | ... | @@ -35,13 +35,13 @@ public interface ClusterRpcService { |
35 | 35 | |
36 | 36 | void init(RpcMsgListener listener); |
37 | 37 | |
38 | - void tell(ServerAddress serverAddress, ToDeviceActorMsg toForward); | |
38 | + void tell(ServerAddress serverAddress, DeviceToDeviceActorMsg toForward); | |
39 | 39 | |
40 | 40 | void tell(ServerAddress serverAddress, ToDeviceSessionActorMsg toForward); |
41 | 41 | |
42 | 42 | void tell(ServerAddress serverAddress, ToDeviceActorNotificationMsg toForward); |
43 | 43 | |
44 | - void tell(ServerAddress serverAddress, ToDeviceRpcRequestPluginMsg toForward); | |
44 | + void tell(ServerAddress serverAddress, ToDeviceRpcRequestMsg toForward); | |
45 | 45 | |
46 | 46 | void tell(ServerAddress serverAddress, ToPluginRpcResponseDeviceMsg toForward); |
47 | 47 | |
... | ... | @@ -50,4 +50,5 @@ public interface ClusterRpcService { |
50 | 50 | void broadcast(ToAllNodesMsg msg); |
51 | 51 | |
52 | 52 | void onSessionCreated(UUID msgUid, StreamObserver<ClusterAPIProtos.ToRpcServerMessage> inputStream); |
53 | + | |
53 | 54 | } | ... | ... |
... | ... | @@ -20,18 +20,16 @@ import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; |
20 | 20 | import org.thingsboard.server.actors.rpc.RpcSessionTellMsg; |
21 | 21 | import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
22 | 22 | import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; |
23 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
23 | +import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg; | |
24 | 24 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
25 | 25 | import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg; |
26 | -import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; | |
27 | -import org.thingsboard.server.gen.cluster.ClusterAPIProtos; | |
28 | 26 | |
29 | 27 | /** |
30 | 28 | * @author Andrew Shvayka |
31 | 29 | */ |
32 | 30 | public interface RpcMsgListener { |
33 | 31 | |
34 | - void onMsg(ToDeviceActorMsg msg); | |
32 | + void onMsg(DeviceToDeviceActorMsg msg); | |
35 | 33 | |
36 | 34 | void onMsg(ToDeviceActorNotificationMsg msg); |
37 | 35 | ... | ... |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -60,21 +60,12 @@ import java.nio.file.Paths; |
60 | 60 | @Slf4j |
61 | 61 | public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
62 | 62 | |
63 | - private static final String JSON_DIR = "json"; | |
64 | - private static final String SYSTEM_DIR = "system"; | |
65 | - private static final String DEMO_DIR = "demo"; | |
66 | - private static final String WIDGET_BUNDLES_DIR = "widget_bundles"; | |
67 | - private static final String PLUGINS_DIR = "plugins"; | |
68 | - private static final String RULES_DIR = "rules"; | |
69 | - private static final String DASHBOARDS_DIR = "dashboards"; | |
70 | - | |
71 | 63 | private static final ObjectMapper objectMapper = new ObjectMapper(); |
72 | - public static final String JSON_EXT = ".json"; | |
73 | 64 | public static final String CUSTOMER_CRED = "customer"; |
74 | 65 | public static final String DEFAULT_DEVICE_TYPE = "default"; |
75 | 66 | |
76 | - @Value("${install.data_dir}") | |
77 | - private String dataDir; | |
67 | + @Autowired | |
68 | + private InstallScripts installScripts; | |
78 | 69 | |
79 | 70 | @Autowired |
80 | 71 | private BCryptPasswordEncoder passwordEncoder; |
... | ... | @@ -89,15 +80,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
89 | 80 | private WidgetsBundleService widgetsBundleService; |
90 | 81 | |
91 | 82 | @Autowired |
92 | - private WidgetTypeService widgetTypeService; | |
93 | - | |
94 | - @Autowired | |
95 | - private PluginService pluginService; | |
96 | - | |
97 | - @Autowired | |
98 | - private RuleService ruleService; | |
99 | - | |
100 | - @Autowired | |
101 | 83 | private TenantService tenantService; |
102 | 84 | |
103 | 85 | @Autowired |
... | ... | @@ -109,9 +91,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
109 | 91 | @Autowired |
110 | 92 | private DeviceCredentialsService deviceCredentialsService; |
111 | 93 | |
112 | - @Autowired | |
113 | - private DashboardService dashboardService; | |
114 | - | |
115 | 94 | @Bean |
116 | 95 | protected BCryptPasswordEncoder passwordEncoder() { |
117 | 96 | return new BCryptPasswordEncoder(); |
... | ... | @@ -147,55 +126,12 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
147 | 126 | } |
148 | 127 | |
149 | 128 | @Override |
150 | - public void loadSystemWidgets() throws Exception { | |
151 | - Path widgetBundlesDir = Paths.get(dataDir, JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR); | |
152 | - try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) { | |
153 | - dirStream.forEach( | |
154 | - path -> { | |
155 | - try { | |
156 | - JsonNode widgetsBundleDescriptorJson = objectMapper.readTree(path.toFile()); | |
157 | - JsonNode widgetsBundleJson = widgetsBundleDescriptorJson.get("widgetsBundle"); | |
158 | - WidgetsBundle widgetsBundle = objectMapper.treeToValue(widgetsBundleJson, WidgetsBundle.class); | |
159 | - WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); | |
160 | - JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes"); | |
161 | - widgetTypesArrayJson.forEach( | |
162 | - widgetTypeJson -> { | |
163 | - try { | |
164 | - WidgetType widgetType = objectMapper.treeToValue(widgetTypeJson, WidgetType.class); | |
165 | - widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); | |
166 | - widgetTypeService.saveWidgetType(widgetType); | |
167 | - } catch (Exception e) { | |
168 | - log.error("Unable to load widget type from json: [{}]", path.toString()); | |
169 | - throw new RuntimeException("Unable to load widget type from json", e); | |
170 | - } | |
171 | - } | |
172 | - ); | |
173 | - } catch (Exception e) { | |
174 | - log.error("Unable to load widgets bundle from json: [{}]", path.toString()); | |
175 | - throw new RuntimeException("Unable to load widgets bundle from json", e); | |
176 | - } | |
177 | - } | |
178 | - ); | |
179 | - } | |
180 | - } | |
181 | - | |
182 | - @Override | |
183 | - public void loadSystemPlugins() throws Exception { | |
184 | - loadPlugins(Paths.get(dataDir, JSON_DIR, SYSTEM_DIR, PLUGINS_DIR), null); | |
185 | - } | |
186 | - | |
187 | - | |
188 | - @Override | |
189 | - public void loadSystemRules() throws Exception { | |
190 | -// loadRules(Paths.get(dataDir, JSON_DIR, SYSTEM_DIR, RULES_DIR), null); | |
191 | - } | |
192 | - | |
193 | - @Override | |
194 | 129 | public void loadDemoData() throws Exception { |
195 | 130 | Tenant demoTenant = new Tenant(); |
196 | 131 | demoTenant.setRegion("Global"); |
197 | 132 | demoTenant.setTitle("Tenant"); |
198 | 133 | demoTenant = tenantService.saveTenant(demoTenant); |
134 | + installScripts.createDefaultRuleChains(demoTenant.getId()); | |
199 | 135 | createUser(Authority.TENANT_ADMIN, demoTenant.getId(), null, "tenant@thingsboard.org", "tenant"); |
200 | 136 | |
201 | 137 | Customer customerA = new Customer(); |
... | ... | @@ -227,9 +163,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
227 | 163 | createDevice(demoTenant.getId(), null, DEFAULT_DEVICE_TYPE, "Raspberry Pi Demo Device", "RASPBERRY_PI_DEMO_TOKEN", "Demo device that is used in " + |
228 | 164 | "Raspberry Pi GPIO control sample application"); |
229 | 165 | |
230 | - loadPlugins(Paths.get(dataDir, JSON_DIR, DEMO_DIR, PLUGINS_DIR), demoTenant.getId()); | |
231 | -// loadRules(Paths.get(dataDir, JSON_DIR, DEMO_DIR, RULES_DIR), demoTenant.getId()); | |
232 | - loadDashboards(Paths.get(dataDir, JSON_DIR, DEMO_DIR, DASHBOARDS_DIR), demoTenant.getId(), null); | |
166 | + installScripts.loadDashboards(demoTenant.getId(), null); | |
233 | 167 | } |
234 | 168 | |
235 | 169 | @Override |
... | ... | @@ -240,6 +174,11 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
240 | 174 | } |
241 | 175 | } |
242 | 176 | |
177 | + @Override | |
178 | + public void loadSystemWidgets() throws Exception { | |
179 | + installScripts.loadSystemWidgets(); | |
180 | + } | |
181 | + | |
243 | 182 | private User createUser(Authority authority, |
244 | 183 | TenantId tenantId, |
245 | 184 | CustomerId customerId, |
... | ... | @@ -282,72 +221,4 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
282 | 221 | return device; |
283 | 222 | } |
284 | 223 | |
285 | - private void loadPlugins(Path pluginsDir, TenantId tenantId) throws Exception{ | |
286 | - try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(pluginsDir, path -> path.toString().endsWith(JSON_EXT))) { | |
287 | - dirStream.forEach( | |
288 | - path -> { | |
289 | - try { | |
290 | - JsonNode pluginJson = objectMapper.readTree(path.toFile()); | |
291 | - PluginMetaData plugin = objectMapper.treeToValue(pluginJson, PluginMetaData.class); | |
292 | - plugin.setTenantId(tenantId); | |
293 | - if (plugin.getState() == ComponentLifecycleState.ACTIVE) { | |
294 | - plugin.setState(ComponentLifecycleState.SUSPENDED); | |
295 | - PluginMetaData savedPlugin = pluginService.savePlugin(plugin); | |
296 | - pluginService.activatePluginById(savedPlugin.getId()); | |
297 | - } else { | |
298 | - pluginService.savePlugin(plugin); | |
299 | - } | |
300 | - } catch (Exception e) { | |
301 | - log.error("Unable to load plugin from json: [{}]", path.toString()); | |
302 | - throw new RuntimeException("Unable to load plugin from json", e); | |
303 | - } | |
304 | - } | |
305 | - ); | |
306 | - } | |
307 | - } | |
308 | - | |
309 | - private void loadRules(Path rulesDir, TenantId tenantId) throws Exception { | |
310 | - try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(rulesDir, path -> path.toString().endsWith(JSON_EXT))) { | |
311 | - dirStream.forEach( | |
312 | - path -> { | |
313 | - try { | |
314 | - JsonNode ruleJson = objectMapper.readTree(path.toFile()); | |
315 | - RuleMetaData rule = objectMapper.treeToValue(ruleJson, RuleMetaData.class); | |
316 | - rule.setTenantId(tenantId); | |
317 | - if (rule.getState() == ComponentLifecycleState.ACTIVE) { | |
318 | - rule.setState(ComponentLifecycleState.SUSPENDED); | |
319 | - RuleMetaData savedRule = ruleService.saveRule(rule); | |
320 | - ruleService.activateRuleById(savedRule.getId()); | |
321 | - } else { | |
322 | - ruleService.saveRule(rule); | |
323 | - } | |
324 | - } catch (Exception e) { | |
325 | - log.error("Unable to load rule from json: [{}]", path.toString()); | |
326 | - throw new RuntimeException("Unable to load rule from json", e); | |
327 | - } | |
328 | - } | |
329 | - ); | |
330 | - } | |
331 | - } | |
332 | - | |
333 | - private void loadDashboards(Path dashboardsDir, TenantId tenantId, CustomerId customerId) throws Exception { | |
334 | - try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) { | |
335 | - dirStream.forEach( | |
336 | - path -> { | |
337 | - try { | |
338 | - JsonNode dashboardJson = objectMapper.readTree(path.toFile()); | |
339 | - Dashboard dashboard = objectMapper.treeToValue(dashboardJson, Dashboard.class); | |
340 | - dashboard.setTenantId(tenantId); | |
341 | - Dashboard savedDashboard = dashboardService.saveDashboard(dashboard); | |
342 | - if (customerId != null && !customerId.isNullUid()) { | |
343 | - dashboardService.assignDashboardToCustomer(savedDashboard.getId(), customerId); | |
344 | - } | |
345 | - } catch (Exception e) { | |
346 | - log.error("Unable to load dashboard from json: [{}]", path.toString()); | |
347 | - throw new RuntimeException("Unable to load dashboard from json", e); | |
348 | - } | |
349 | - } | |
350 | - ); | |
351 | - } | |
352 | - } | |
353 | 224 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.install; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import lombok.Getter; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.springframework.beans.factory.annotation.Autowired; | |
22 | +import org.springframework.beans.factory.annotation.Value; | |
23 | +import org.springframework.stereotype.Component; | |
24 | +import org.springframework.util.StringUtils; | |
25 | +import org.thingsboard.server.common.data.Dashboard; | |
26 | +import org.thingsboard.server.common.data.id.CustomerId; | |
27 | +import org.thingsboard.server.common.data.id.TenantId; | |
28 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
29 | +import org.thingsboard.server.common.data.rule.RuleChainMetaData; | |
30 | +import org.thingsboard.server.common.data.widget.WidgetType; | |
31 | +import org.thingsboard.server.common.data.widget.WidgetsBundle; | |
32 | +import org.thingsboard.server.dao.dashboard.DashboardService; | |
33 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
34 | +import org.thingsboard.server.dao.widget.WidgetTypeService; | |
35 | +import org.thingsboard.server.dao.widget.WidgetsBundleService; | |
36 | + | |
37 | +import java.io.IOException; | |
38 | +import java.nio.file.DirectoryStream; | |
39 | +import java.nio.file.Files; | |
40 | +import java.nio.file.Path; | |
41 | +import java.nio.file.Paths; | |
42 | + | |
43 | +import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper; | |
44 | + | |
45 | +/** | |
46 | + * Created by ashvayka on 18.04.18. | |
47 | + */ | |
48 | +@Component | |
49 | +@Slf4j | |
50 | +public class InstallScripts { | |
51 | + | |
52 | + public static final String APP_DIR = "application"; | |
53 | + public static final String SRC_DIR = "src"; | |
54 | + public static final String MAIN_DIR = "main"; | |
55 | + public static final String DATA_DIR = "data"; | |
56 | + public static final String JSON_DIR = "json"; | |
57 | + public static final String SYSTEM_DIR = "system"; | |
58 | + public static final String TENANT_DIR = "tenant"; | |
59 | + public static final String DEMO_DIR = "demo"; | |
60 | + public static final String RULE_CHAINS_DIR = "rule_chains"; | |
61 | + public static final String WIDGET_BUNDLES_DIR = "widget_bundles"; | |
62 | + public static final String DASHBOARDS_DIR = "dashboards"; | |
63 | + | |
64 | + public static final String JSON_EXT = ".json"; | |
65 | + | |
66 | + @Value("${install.data_dir:}") | |
67 | + private String dataDir; | |
68 | + | |
69 | + @Autowired | |
70 | + private RuleChainService ruleChainService; | |
71 | + | |
72 | + @Autowired | |
73 | + private DashboardService dashboardService; | |
74 | + | |
75 | + @Autowired | |
76 | + private WidgetTypeService widgetTypeService; | |
77 | + | |
78 | + @Autowired | |
79 | + private WidgetsBundleService widgetsBundleService; | |
80 | + | |
81 | + public Path getTenantRuleChainsDir() { | |
82 | + return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR); | |
83 | + } | |
84 | + | |
85 | + public String getDataDir() { | |
86 | + if (!StringUtils.isEmpty(dataDir)) { | |
87 | + return dataDir; | |
88 | + } else { | |
89 | + String workDir = System.getProperty("user.dir"); | |
90 | + if (workDir.endsWith("application")) { | |
91 | + return Paths.get(workDir, SRC_DIR, MAIN_DIR, DATA_DIR).toString(); | |
92 | + } else { | |
93 | + Path dataDirPath = Paths.get(workDir, APP_DIR, SRC_DIR, MAIN_DIR, DATA_DIR); | |
94 | + if (Files.exists(dataDirPath)) { | |
95 | + return dataDirPath.toString(); | |
96 | + } else { | |
97 | + throw new RuntimeException("Not valid working directory: " + workDir + ". Please use either root project directory, application module directory or specify valid \"install.data_dir\" ENV variable to avoid automatic data directory lookup!"); | |
98 | + } | |
99 | + } | |
100 | + } | |
101 | + } | |
102 | + | |
103 | + public void createDefaultRuleChains(TenantId tenantId) throws IOException { | |
104 | + Path tenantChainsDir = getTenantRuleChainsDir(); | |
105 | + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(tenantChainsDir, path -> path.toString().endsWith(InstallScripts.JSON_EXT))) { | |
106 | + dirStream.forEach( | |
107 | + path -> { | |
108 | + try { | |
109 | + JsonNode ruleChainJson = objectMapper.readTree(path.toFile()); | |
110 | + RuleChain ruleChain = objectMapper.treeToValue(ruleChainJson.get("ruleChain"), RuleChain.class); | |
111 | + RuleChainMetaData ruleChainMetaData = objectMapper.treeToValue(ruleChainJson.get("metadata"), RuleChainMetaData.class); | |
112 | + | |
113 | + ruleChain.setTenantId(tenantId); | |
114 | + ruleChain = ruleChainService.saveRuleChain(ruleChain); | |
115 | + | |
116 | + ruleChainMetaData.setRuleChainId(ruleChain.getId()); | |
117 | + ruleChainService.saveRuleChainMetaData(ruleChainMetaData); | |
118 | + } catch (Exception e) { | |
119 | + log.error("Unable to load rule chain from json: [{}]", path.toString()); | |
120 | + throw new RuntimeException("Unable to load rule chain from json", e); | |
121 | + } | |
122 | + } | |
123 | + ); | |
124 | + } | |
125 | + } | |
126 | + | |
127 | + public void loadSystemWidgets() throws Exception { | |
128 | + Path widgetBundlesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR); | |
129 | + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(JSON_EXT))) { | |
130 | + dirStream.forEach( | |
131 | + path -> { | |
132 | + try { | |
133 | + JsonNode widgetsBundleDescriptorJson = objectMapper.readTree(path.toFile()); | |
134 | + JsonNode widgetsBundleJson = widgetsBundleDescriptorJson.get("widgetsBundle"); | |
135 | + WidgetsBundle widgetsBundle = objectMapper.treeToValue(widgetsBundleJson, WidgetsBundle.class); | |
136 | + WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); | |
137 | + JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes"); | |
138 | + widgetTypesArrayJson.forEach( | |
139 | + widgetTypeJson -> { | |
140 | + try { | |
141 | + WidgetType widgetType = objectMapper.treeToValue(widgetTypeJson, WidgetType.class); | |
142 | + widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); | |
143 | + widgetTypeService.saveWidgetType(widgetType); | |
144 | + } catch (Exception e) { | |
145 | + log.error("Unable to load widget type from json: [{}]", path.toString()); | |
146 | + throw new RuntimeException("Unable to load widget type from json", e); | |
147 | + } | |
148 | + } | |
149 | + ); | |
150 | + } catch (Exception e) { | |
151 | + log.error("Unable to load widgets bundle from json: [{}]", path.toString()); | |
152 | + throw new RuntimeException("Unable to load widgets bundle from json", e); | |
153 | + } | |
154 | + } | |
155 | + ); | |
156 | + } | |
157 | + } | |
158 | + | |
159 | + public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception { | |
160 | + Path dashboardsDir = Paths.get(getDataDir(), JSON_DIR, DEMO_DIR, DASHBOARDS_DIR); | |
161 | + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) { | |
162 | + dirStream.forEach( | |
163 | + path -> { | |
164 | + try { | |
165 | + JsonNode dashboardJson = objectMapper.readTree(path.toFile()); | |
166 | + Dashboard dashboard = objectMapper.treeToValue(dashboardJson, Dashboard.class); | |
167 | + dashboard.setTenantId(tenantId); | |
168 | + Dashboard savedDashboard = dashboardService.saveDashboard(dashboard); | |
169 | + if (customerId != null && !customerId.isNullUid()) { | |
170 | + dashboardService.assignDashboardToCustomer(savedDashboard.getId(), customerId); | |
171 | + } | |
172 | + } catch (Exception e) { | |
173 | + log.error("Unable to load dashboard from json: [{}]", path.toString()); | |
174 | + throw new RuntimeException("Unable to load dashboard from json", e); | |
175 | + } | |
176 | + } | |
177 | + ); | |
178 | + } | |
179 | + } | |
180 | + | |
181 | + | |
182 | +} | ... | ... |
... | ... | @@ -23,10 +23,6 @@ public interface SystemDataLoaderService { |
23 | 23 | |
24 | 24 | void loadSystemWidgets() throws Exception; |
25 | 25 | |
26 | - void loadSystemPlugins() throws Exception; | |
27 | - | |
28 | - void loadSystemRules() throws Exception; | |
29 | - | |
30 | 26 | void loadDemoData() throws Exception; |
31 | 27 | |
32 | 28 | void deleteSystemWidgetBundle(String bundleAlias) throws Exception; | ... | ... |
application/src/main/java/org/thingsboard/server/service/rpc/DefaultDeviceRpcService.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.service.rpc; | |
17 | + | |
18 | +import akka.actor.ActorRef; | |
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.springframework.beans.factory.annotation.Autowired; | |
22 | +import org.springframework.http.HttpStatus; | |
23 | +import org.springframework.http.ResponseEntity; | |
24 | +import org.springframework.stereotype.Service; | |
25 | +import org.springframework.util.StringUtils; | |
26 | +import org.springframework.web.context.request.async.DeferredResult; | |
27 | +import org.thingsboard.server.actors.service.ActorService; | |
28 | +import org.thingsboard.server.common.data.audit.ActionType; | |
29 | +import org.thingsboard.server.common.data.id.DeviceId; | |
30 | +import org.thingsboard.server.common.data.id.EntityId; | |
31 | +import org.thingsboard.server.common.data.id.UUIDBased; | |
32 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | |
33 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
34 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
35 | +import org.thingsboard.server.controller.BaseController; | |
36 | +import org.thingsboard.server.dao.audit.AuditLogService; | |
37 | +import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; | |
38 | +import org.thingsboard.server.extensions.api.plugins.msg.RpcError; | |
39 | +import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | |
40 | +import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | |
41 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
42 | + | |
43 | +import javax.annotation.PostConstruct; | |
44 | +import javax.annotation.PreDestroy; | |
45 | +import java.io.IOException; | |
46 | +import java.util.Optional; | |
47 | +import java.util.UUID; | |
48 | +import java.util.concurrent.ConcurrentHashMap; | |
49 | +import java.util.concurrent.ConcurrentMap; | |
50 | +import java.util.concurrent.Executors; | |
51 | +import java.util.concurrent.ScheduledExecutorService; | |
52 | +import java.util.concurrent.TimeUnit; | |
53 | +import java.util.function.BiConsumer; | |
54 | + | |
55 | +/** | |
56 | + * Created by ashvayka on 27.03.18. | |
57 | + */ | |
58 | +@Service | |
59 | +@Slf4j | |
60 | +public class DefaultDeviceRpcService implements DeviceRpcService { | |
61 | + | |
62 | + private static final ObjectMapper jsonMapper = new ObjectMapper(); | |
63 | + | |
64 | + @Autowired | |
65 | + private ClusterRoutingService routingService; | |
66 | + | |
67 | + @Autowired | |
68 | + private ClusterRpcService rpcService; | |
69 | + | |
70 | + @Autowired | |
71 | + private ActorService actorService; | |
72 | + | |
73 | + @Autowired | |
74 | + private AuditLogService auditLogService; | |
75 | + | |
76 | + private ScheduledExecutorService rpcCallBackExecutor; | |
77 | + | |
78 | + private final ConcurrentMap<UUID, LocalRequestMetaData> localRpcRequests = new ConcurrentHashMap<>(); | |
79 | + | |
80 | + | |
81 | + @PostConstruct | |
82 | + public void initExecutor() { | |
83 | + rpcCallBackExecutor = Executors.newSingleThreadScheduledExecutor(); | |
84 | + } | |
85 | + | |
86 | + @PreDestroy | |
87 | + public void shutdownExecutor() { | |
88 | + if (rpcCallBackExecutor != null) { | |
89 | + rpcCallBackExecutor.shutdownNow(); | |
90 | + } | |
91 | + } | |
92 | + | |
93 | + @Override | |
94 | + public void process(ToDeviceRpcRequest request, LocalRequestMetaData metaData) { | |
95 | + log.trace("[{}] Processing local rpc call for device [{}]", request.getTenantId(), request.getDeviceId()); | |
96 | + sendRpcRequest(request); | |
97 | + UUID requestId = request.getId(); | |
98 | + localRpcRequests.put(requestId, metaData); | |
99 | + long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()); | |
100 | + log.error("[{}] processing the request: [{}]", this.hashCode(), requestId); | |
101 | + rpcCallBackExecutor.schedule(() -> { | |
102 | + log.error("[{}] timeout the request: [{}]", this.hashCode(), requestId); | |
103 | + LocalRequestMetaData localMetaData = localRpcRequests.remove(requestId); | |
104 | + if (localMetaData != null) { | |
105 | + reply(localMetaData, new FromDeviceRpcResponse(requestId, null, RpcError.TIMEOUT)); | |
106 | + } | |
107 | + }, timeout, TimeUnit.MILLISECONDS); | |
108 | + } | |
109 | + | |
110 | + @Override | |
111 | + public void process(ToDeviceRpcRequest request, ServerAddress originator) { | |
112 | +// if (pluginServerAddress.isPresent()) { | |
113 | +// systemContext.getRpcService().tell(pluginServerAddress.get(), responsePluginMsg); | |
114 | +// logger.debug("[{}] Rpc command response sent to remote plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId()); | |
115 | +// } else { | |
116 | +// context.parent().tell(responsePluginMsg, ActorRef.noSender()); | |
117 | +// logger.debug("[{}] Rpc command response sent to local plugin actor [{}]!", deviceId, requestMd.getMsg().getMsg().getId()); | |
118 | +// } | |
119 | + } | |
120 | + | |
121 | + @Override | |
122 | + public void process(FromDeviceRpcResponse response) { | |
123 | + log.error("[{}] response the request: [{}]", this.hashCode(), response.getId()); | |
124 | + //TODO: send to another server if needed. | |
125 | + UUID requestId = response.getId(); | |
126 | + LocalRequestMetaData md = localRpcRequests.remove(requestId); | |
127 | + if (md != null) { | |
128 | + log.trace("[{}] Processing local rpc response from device [{}]", requestId, md.getRequest().getDeviceId()); | |
129 | + reply(md, response); | |
130 | + } else { | |
131 | + log.trace("[{}] Unknown or stale rpc response received [{}]", requestId, response); | |
132 | + } | |
133 | + } | |
134 | + | |
135 | + public void reply(LocalRequestMetaData rpcRequest, FromDeviceRpcResponse response) { | |
136 | + Optional<RpcError> rpcError = response.getError(); | |
137 | + DeferredResult<ResponseEntity> responseWriter = rpcRequest.getResponseWriter(); | |
138 | + if (rpcError.isPresent()) { | |
139 | + logRpcCall(rpcRequest, rpcError, null); | |
140 | + RpcError error = rpcError.get(); | |
141 | + switch (error) { | |
142 | + case TIMEOUT: | |
143 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT)); | |
144 | + break; | |
145 | + case NO_ACTIVE_CONNECTION: | |
146 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.CONFLICT)); | |
147 | + break; | |
148 | + default: | |
149 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT)); | |
150 | + break; | |
151 | + } | |
152 | + } else { | |
153 | + Optional<String> responseData = response.getResponse(); | |
154 | + if (responseData.isPresent() && !StringUtils.isEmpty(responseData.get())) { | |
155 | + String data = responseData.get(); | |
156 | + try { | |
157 | + logRpcCall(rpcRequest, rpcError, null); | |
158 | + responseWriter.setResult(new ResponseEntity<>(jsonMapper.readTree(data), HttpStatus.OK)); | |
159 | + } catch (IOException e) { | |
160 | + log.debug("Failed to decode device response: {}", data, e); | |
161 | + logRpcCall(rpcRequest, rpcError, e); | |
162 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.NOT_ACCEPTABLE)); | |
163 | + } | |
164 | + } else { | |
165 | + logRpcCall(rpcRequest, rpcError, null); | |
166 | + responseWriter.setResult(new ResponseEntity<>(HttpStatus.OK)); | |
167 | + } | |
168 | + } | |
169 | + } | |
170 | + | |
171 | + private void sendRpcRequest(ToDeviceRpcRequest msg) { | |
172 | + log.trace("[{}] Forwarding msg {} to device actor!", msg.getDeviceId(), msg); | |
173 | + ToDeviceRpcRequestMsg rpcMsg = new ToDeviceRpcRequestMsg(msg); | |
174 | + forward(msg.getDeviceId(), rpcMsg, rpcService::tell); | |
175 | + } | |
176 | + | |
177 | + private void forward(DeviceId deviceId, ToDeviceRpcRequestMsg msg, BiConsumer<ServerAddress, ToDeviceRpcRequestMsg> rpcFunction) { | |
178 | + Optional<ServerAddress> instance = routingService.resolveById(deviceId); | |
179 | + if (instance.isPresent()) { | |
180 | + log.trace("[{}] Forwarding msg {} to remote device actor!", msg.getTenantId(), msg); | |
181 | + rpcFunction.accept(instance.get(), msg); | |
182 | + } else { | |
183 | + log.trace("[{}] Forwarding msg {} to local device actor!", msg.getTenantId(), msg); | |
184 | + actorService.onMsg(msg); | |
185 | + } | |
186 | + } | |
187 | + | |
188 | + private void logRpcCall(LocalRequestMetaData rpcRequest, Optional<RpcError> rpcError, Throwable e) { | |
189 | + logRpcCall(rpcRequest.getUser(), rpcRequest.getRequest().getDeviceId(), rpcRequest.getRequest().getBody(), rpcRequest.getRequest().isOneway(), rpcError, null); | |
190 | + } | |
191 | + | |
192 | + @Override | |
193 | + public void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e) { | |
194 | + String rpcErrorStr = ""; | |
195 | + if (rpcError.isPresent()) { | |
196 | + rpcErrorStr = "RPC Error: " + rpcError.get().name(); | |
197 | + } | |
198 | + String method = body.getMethod(); | |
199 | + String params = body.getParams(); | |
200 | + | |
201 | + auditLogService.logEntityAction( | |
202 | + user.getTenantId(), | |
203 | + user.getCustomerId(), | |
204 | + user.getId(), | |
205 | + user.getName(), | |
206 | + (UUIDBased & EntityId) entityId, | |
207 | + null, | |
208 | + ActionType.RPC_CALL, | |
209 | + BaseController.toException(e), | |
210 | + rpcErrorStr, | |
211 | + oneWay, | |
212 | + method, | |
213 | + params); | |
214 | + } | |
215 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/service/rpc/DeviceRpcService.java
renamed from
application/src/test/java/org/thingsboard/server/controller/nosql/RuleControllerNoSqlTest.java
... | ... | @@ -13,14 +13,28 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.controller.nosql; | |
16 | +package org.thingsboard.server.service.rpc; | |
17 | 17 | |
18 | -import org.thingsboard.server.controller.BaseRuleControllerTest; | |
19 | -import org.thingsboard.server.dao.service.DaoNoSqlTest; | |
18 | +import org.thingsboard.server.common.data.id.EntityId; | |
19 | +import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; | |
20 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
21 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
22 | +import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; | |
23 | +import org.thingsboard.server.extensions.api.plugins.msg.RpcError; | |
24 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
25 | + | |
26 | +import java.util.Optional; | |
20 | 27 | |
21 | 28 | /** |
22 | - * Created by Valerii Sosliuk on 6/28/2017. | |
29 | + * Created by ashvayka on 16.04.18. | |
23 | 30 | */ |
24 | -@DaoNoSqlTest | |
25 | -public class RuleControllerNoSqlTest extends BaseRuleControllerTest { | |
31 | +public interface DeviceRpcService { | |
32 | + | |
33 | + void process(ToDeviceRpcRequest request, LocalRequestMetaData metaData); | |
34 | + | |
35 | + void process(ToDeviceRpcRequest request, ServerAddress originator); | |
36 | + | |
37 | + void process(FromDeviceRpcResponse response); | |
38 | + | |
39 | + void logRpcCall(SecurityUser user, EntityId entityId, ToDeviceRpcRequestBody body, boolean oneWay, Optional<RpcError> rpcError, Throwable e); | |
26 | 40 | } | ... | ... |
application/src/main/java/org/thingsboard/server/service/rpc/LocalRequestMetaData.java
renamed from
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/rpc/LocalRequestMetaData.java
... | ... | @@ -13,18 +13,20 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.extensions.core.plugin.rpc; | |
16 | +package org.thingsboard.server.service.rpc; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | import org.springframework.http.ResponseEntity; |
20 | 20 | import org.springframework.web.context.request.async.DeferredResult; |
21 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest; | |
21 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
22 | +import org.thingsboard.server.service.security.model.SecurityUser; | |
22 | 23 | |
23 | 24 | /** |
24 | - * @author Andrew Shvayka | |
25 | + * Created by ashvayka on 16.04.18. | |
25 | 26 | */ |
26 | 27 | @Data |
27 | 28 | public class LocalRequestMetaData { |
28 | 29 | private final ToDeviceRpcRequest request; |
30 | + private final SecurityUser user; | |
29 | 31 | private final DeferredResult<ResponseEntity> responseWriter; |
30 | 32 | } | ... | ... |
application/src/main/java/org/thingsboard/server/service/rpc/ToDeviceRpcRequestMsg.java
renamed from
extensions-api/src/main/java/org/thingsboard/server/extensions/api/plugins/msg/ToDeviceRpcRequestPluginMsg.java
... | ... | @@ -13,36 +13,33 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.extensions.api.plugins.msg; | |
16 | +package org.thingsboard.server.service.rpc; | |
17 | 17 | |
18 | 18 | import lombok.Getter; |
19 | 19 | import lombok.RequiredArgsConstructor; |
20 | 20 | import lombok.ToString; |
21 | 21 | import org.thingsboard.server.common.data.id.DeviceId; |
22 | -import org.thingsboard.server.common.data.id.PluginId; | |
23 | 22 | import org.thingsboard.server.common.data.id.TenantId; |
23 | +import org.thingsboard.server.common.msg.MsgType; | |
24 | 24 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
25 | +import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; | |
25 | 26 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
26 | 27 | |
27 | 28 | import java.util.Optional; |
28 | 29 | |
29 | 30 | /** |
30 | - * @author Andrew Shvayka | |
31 | + * Created by ashvayka on 16.04.18. | |
31 | 32 | */ |
32 | 33 | @ToString |
33 | 34 | @RequiredArgsConstructor |
34 | -public class ToDeviceRpcRequestPluginMsg implements ToDeviceActorNotificationMsg { | |
35 | +public class ToDeviceRpcRequestMsg implements ToDeviceActorNotificationMsg { | |
35 | 36 | |
36 | 37 | private final ServerAddress serverAddress; |
37 | 38 | @Getter |
38 | - private final PluginId pluginId; | |
39 | - @Getter | |
40 | - private final TenantId pluginTenantId; | |
41 | - @Getter | |
42 | 39 | private final ToDeviceRpcRequest msg; |
43 | 40 | |
44 | - public ToDeviceRpcRequestPluginMsg(PluginId pluginId, TenantId pluginTenantId, ToDeviceRpcRequest msg) { | |
45 | - this(null, pluginId, pluginTenantId, msg); | |
41 | + public ToDeviceRpcRequestMsg(ToDeviceRpcRequest msg) { | |
42 | + this(null, msg); | |
46 | 43 | } |
47 | 44 | |
48 | 45 | public Optional<ServerAddress> getServerAddress() { |
... | ... | @@ -58,5 +55,9 @@ public class ToDeviceRpcRequestPluginMsg implements ToDeviceActorNotificationMsg |
58 | 55 | public TenantId getTenantId() { |
59 | 56 | return msg.getTenantId(); |
60 | 57 | } |
61 | -} | |
62 | 58 | |
59 | + @Override | |
60 | + public MsgType getMsgType() { | |
61 | + return MsgType.DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG; | |
62 | + } | |
63 | +} | ... | ... |
... | ... | @@ -25,6 +25,7 @@ import org.springframework.http.ResponseEntity; |
25 | 25 | import org.springframework.stereotype.Component; |
26 | 26 | import org.springframework.web.context.request.async.DeferredResult; |
27 | 27 | import org.thingsboard.server.actors.plugin.ValidationResult; |
28 | +import org.thingsboard.server.common.data.BaseData; | |
28 | 29 | import org.thingsboard.server.common.data.Customer; |
29 | 30 | import org.thingsboard.server.common.data.Device; |
30 | 31 | import org.thingsboard.server.common.data.Tenant; |
... | ... | @@ -35,8 +36,10 @@ import org.thingsboard.server.common.data.id.DeviceId; |
35 | 36 | import org.thingsboard.server.common.data.id.EntityId; |
36 | 37 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
37 | 38 | import org.thingsboard.server.common.data.id.RuleChainId; |
39 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
38 | 40 | import org.thingsboard.server.common.data.id.TenantId; |
39 | 41 | import org.thingsboard.server.common.data.rule.RuleChain; |
42 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
40 | 43 | import org.thingsboard.server.controller.HttpValidationCallback; |
41 | 44 | import org.thingsboard.server.dao.alarm.AlarmService; |
42 | 45 | import org.thingsboard.server.dao.asset.AssetService; |
... | ... | @@ -140,7 +143,7 @@ public class AccessValidator { |
140 | 143 | return response; |
141 | 144 | } |
142 | 145 | |
143 | - public <T> void validate(SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
146 | + public void validate(SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
144 | 147 | switch (entityId.getEntityType()) { |
145 | 148 | case DEVICE: |
146 | 149 | validateDevice(currentUser, entityId, callback); |
... | ... | @@ -177,14 +180,14 @@ public class AccessValidator { |
177 | 180 | } else if (currentUser.isCustomerUser() && !device.getCustomerId().equals(currentUser.getCustomerId())) { |
178 | 181 | return ValidationResult.accessDenied("Device doesn't belong to the current Customer!"); |
179 | 182 | } else { |
180 | - return ValidationResult.ok(); | |
183 | + return ValidationResult.ok(device); | |
181 | 184 | } |
182 | 185 | } |
183 | 186 | }), executor); |
184 | 187 | } |
185 | 188 | } |
186 | 189 | |
187 | - private <T> void validateAsset(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
190 | + private void validateAsset(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
188 | 191 | if (currentUser.isSystemAdmin()) { |
189 | 192 | callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); |
190 | 193 | } else { |
... | ... | @@ -198,15 +201,14 @@ public class AccessValidator { |
198 | 201 | } else if (currentUser.isCustomerUser() && !asset.getCustomerId().equals(currentUser.getCustomerId())) { |
199 | 202 | return ValidationResult.accessDenied("Asset doesn't belong to the current Customer!"); |
200 | 203 | } else { |
201 | - return ValidationResult.ok(); | |
204 | + return ValidationResult.ok(asset); | |
202 | 205 | } |
203 | 206 | } |
204 | 207 | }), executor); |
205 | 208 | } |
206 | 209 | } |
207 | 210 | |
208 | - | |
209 | - private <T> void validateRuleChain(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
211 | + private void validateRuleChain(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
210 | 212 | if (currentUser.isCustomerUser()) { |
211 | 213 | callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); |
212 | 214 | } else { |
... | ... | @@ -220,14 +222,40 @@ public class AccessValidator { |
220 | 222 | } else if (currentUser.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) { |
221 | 223 | return ValidationResult.accessDenied("Rule chain is not in system scope!"); |
222 | 224 | } else { |
223 | - return ValidationResult.ok(); | |
225 | + return ValidationResult.ok(ruleChain); | |
226 | + } | |
227 | + } | |
228 | + }), executor); | |
229 | + } | |
230 | + } | |
231 | + | |
232 | + private void validateRule(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
233 | + if (currentUser.isCustomerUser()) { | |
234 | + callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | |
235 | + } else { | |
236 | + ListenableFuture<RuleNode> ruleNodeFuture = ruleChainService.findRuleNodeByIdAsync(new RuleNodeId(entityId.getId())); | |
237 | + Futures.addCallback(ruleNodeFuture, getCallback(callback, ruleNodeTmp -> { | |
238 | + RuleNode ruleNode = ruleNodeTmp; | |
239 | + if (ruleNode == null) { | |
240 | + return ValidationResult.entityNotFound("Rule node with requested id wasn't found!"); | |
241 | + } else if (ruleNode.getRuleChainId() == null) { | |
242 | + return ValidationResult.entityNotFound("Rule chain with requested node id wasn't found!"); | |
243 | + } else { | |
244 | + //TODO: make async | |
245 | + RuleChain ruleChain = ruleChainService.findRuleChainById(ruleNode.getRuleChainId()); | |
246 | + if (currentUser.isTenantAdmin() && !ruleChain.getTenantId().equals(currentUser.getTenantId())) { | |
247 | + return ValidationResult.accessDenied("Rule chain doesn't belong to the current Tenant!"); | |
248 | + } else if (currentUser.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) { | |
249 | + return ValidationResult.accessDenied("Rule chain is not in system scope!"); | |
250 | + } else { | |
251 | + return ValidationResult.ok(ruleNode); | |
224 | 252 | } |
225 | 253 | } |
226 | 254 | }), executor); |
227 | 255 | } |
228 | 256 | } |
229 | 257 | |
230 | - private <T> void validateCustomer(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
258 | + private void validateCustomer(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
231 | 259 | if (currentUser.isSystemAdmin()) { |
232 | 260 | callback.onSuccess(ValidationResult.accessDenied(SYSTEM_ADMINISTRATOR_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); |
233 | 261 | } else { |
... | ... | @@ -241,18 +269,18 @@ public class AccessValidator { |
241 | 269 | } else if (currentUser.isCustomerUser() && !customer.getId().equals(currentUser.getCustomerId())) { |
242 | 270 | return ValidationResult.accessDenied("Customer doesn't relate to the currently authorized customer user!"); |
243 | 271 | } else { |
244 | - return ValidationResult.ok(); | |
272 | + return ValidationResult.ok(customer); | |
245 | 273 | } |
246 | 274 | } |
247 | 275 | }), executor); |
248 | 276 | } |
249 | 277 | } |
250 | 278 | |
251 | - private <T> void validateTenant(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
279 | + private void validateTenant(final SecurityUser currentUser, EntityId entityId, FutureCallback<ValidationResult> callback) { | |
252 | 280 | if (currentUser.isCustomerUser()) { |
253 | 281 | callback.onSuccess(ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); |
254 | 282 | } else if (currentUser.isSystemAdmin()) { |
255 | - callback.onSuccess(ValidationResult.ok()); | |
283 | + callback.onSuccess(ValidationResult.ok(null)); | |
256 | 284 | } else { |
257 | 285 | ListenableFuture<Tenant> tenantFuture = tenantService.findTenantByIdAsync(new TenantId(entityId.getId())); |
258 | 286 | Futures.addCallback(tenantFuture, getCallback(callback, tenant -> { |
... | ... | @@ -261,13 +289,13 @@ public class AccessValidator { |
261 | 289 | } else if (!tenant.getId().equals(currentUser.getTenantId())) { |
262 | 290 | return ValidationResult.accessDenied("Tenant doesn't relate to the currently authorized user!"); |
263 | 291 | } else { |
264 | - return ValidationResult.ok(); | |
292 | + return ValidationResult.ok(tenant); | |
265 | 293 | } |
266 | 294 | }), executor); |
267 | 295 | } |
268 | 296 | } |
269 | 297 | |
270 | - private <T> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult> transformer) { | |
298 | + private <T, V> FutureCallback<T> getCallback(FutureCallback<ValidationResult> callback, Function<T, ValidationResult<V>> transformer) { | |
271 | 299 | return new FutureCallback<T>() { |
272 | 300 | @Override |
273 | 301 | public void onSuccess(@Nullable T result) { | ... | ... |
... | ... | @@ -61,7 +61,6 @@ message ConnectRpcMessage { |
61 | 61 | } |
62 | 62 | |
63 | 63 | message ToDeviceRpcRequestRpcMessage { |
64 | - PluginAddress address = 1; | |
65 | 64 | Uid deviceTenantId = 2; |
66 | 65 | Uid deviceId = 3; |
67 | 66 | |
... | ... | @@ -73,8 +72,6 @@ message ToDeviceRpcRequestRpcMessage { |
73 | 72 | } |
74 | 73 | |
75 | 74 | message ToPluginRpcResponseRpcMessage { |
76 | - PluginAddress address = 1; | |
77 | - | |
78 | 75 | Uid msgId = 2; |
79 | 76 | string response = 3; |
80 | 77 | string error = 4; | ... | ... |
... | ... | @@ -207,18 +207,7 @@ actors: |
207 | 207 | sync: |
208 | 208 | # Default timeout for processing request using synchronous session (HTTP, CoAP) in milliseconds |
209 | 209 | timeout: "${ACTORS_SESSION_SYNC_TIMEOUT:10000}" |
210 | - plugin: | |
211 | - # Default timeout for termination of the plugin actor after it is stopped | |
212 | - termination.delay: "${ACTORS_PLUGIN_TERMINATION_DELAY:60000}" | |
213 | - # Default timeout for processing of particular message by particular plugin | |
214 | - processing.timeout: "${ACTORS_PLUGIN_TIMEOUT:60000}" | |
215 | - # Errors for particular actor are persisted once per specified amount of milliseconds | |
216 | - error_persist_frequency: "${ACTORS_PLUGIN_ERROR_FREQUENCY:3000}" | |
217 | 210 | rule: |
218 | - # Default timeout for termination of the rule actor after it is stopped | |
219 | - termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}" | |
220 | - # Errors for particular actor are persisted once per specified amount of milliseconds | |
221 | - error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}" | |
222 | 211 | # Specify thread pool size for database request callbacks executor service |
223 | 212 | db_callback_thread_pool_size: "${ACTORS_RULE_DB_CALLBACK_THREAD_POOL_SIZE:1}" |
224 | 213 | # Specify thread pool size for javascript executor service |
... | ... | @@ -235,6 +224,11 @@ actors: |
235 | 224 | # Enable/disable actor statistics |
236 | 225 | enabled: "${ACTORS_STATISTICS_ENABLED:true}" |
237 | 226 | persist_frequency: "${ACTORS_STATISTICS_PERSIST_FREQUENCY:3600000}" |
227 | + queue: | |
228 | + # Enable/disable persistence of un-processed messages to the queue | |
229 | + enabled: "${ACTORS_QUEUE_ENABLED:true}" | |
230 | + # Maximum allowed timeout for persistence into the queue | |
231 | + timeout: "${ACTORS_QUEUE_PERSISTENCE_TIMEOUT:30000}" | |
238 | 232 | |
239 | 233 | cache: |
240 | 234 | # caffeine or redis | ... | ... |
application/src/test/java/org/thingsboard/server/actors/ActorsTestSuite.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors; | |
17 | - | |
18 | -import org.junit.extensions.cpsuite.ClasspathSuite; | |
19 | -import org.junit.runner.RunWith; | |
20 | - | |
21 | -/** | |
22 | - * @author Andrew Shvayka | |
23 | - */ | |
24 | -@RunWith(ClasspathSuite.class) | |
25 | -@ClasspathSuite.ClassnameFilters({"org.thingsboard.server.actors.*Test"}) | |
26 | -public class ActorsTestSuite { | |
27 | -} |
application/src/test/java/org/thingsboard/server/actors/DefaultActorServiceTest.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors; | |
17 | - | |
18 | -import static org.mockito.Matchers.any; | |
19 | -import static org.mockito.Mockito.mock; | |
20 | -import static org.mockito.Mockito.verify; | |
21 | -import static org.mockito.Mockito.when; | |
22 | - | |
23 | -import java.util.*; | |
24 | - | |
25 | -import com.google.common.util.concurrent.Futures; | |
26 | -import org.thingsboard.server.actors.service.DefaultActorService; | |
27 | -import org.thingsboard.server.common.data.id.*; | |
28 | -import org.thingsboard.server.common.data.kv.TsKvEntry; | |
29 | -import org.thingsboard.server.common.data.page.TextPageData; | |
30 | -import org.thingsboard.server.common.data.plugin.ComponentDescriptor; | |
31 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
32 | -import org.thingsboard.server.common.data.plugin.ComponentType; | |
33 | -import org.thingsboard.server.common.msg.session.*; | |
34 | -import org.thingsboard.server.dao.attributes.AttributesService; | |
35 | -import org.thingsboard.server.dao.event.EventService; | |
36 | -import org.thingsboard.server.gen.discovery.ServerInstanceProtos; | |
37 | -import org.thingsboard.server.service.cluster.discovery.DiscoveryService; | |
38 | -import org.thingsboard.server.service.cluster.discovery.ServerInstance; | |
39 | -import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; | |
40 | -import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; | |
41 | -import org.thingsboard.server.service.component.ComponentDiscoveryService; | |
42 | -import org.thingsboard.server.common.transport.auth.DeviceAuthResult; | |
43 | -import org.thingsboard.server.common.transport.auth.DeviceAuthService; | |
44 | -import org.thingsboard.server.common.data.DataConstants; | |
45 | -import org.thingsboard.server.common.data.Device; | |
46 | -import org.thingsboard.server.common.data.Tenant; | |
47 | -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; | |
48 | -import org.thingsboard.server.common.data.kv.KvEntry; | |
49 | -import org.thingsboard.server.common.data.kv.StringDataEntry; | |
50 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
51 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
52 | -import org.thingsboard.server.common.data.security.DeviceCredentialsFilter; | |
53 | -import org.thingsboard.server.common.data.security.DeviceTokenCredentials; | |
54 | -import org.thingsboard.server.common.msg.core.BasicTelemetryUploadRequest; | |
55 | -import org.thingsboard.server.dao.device.DeviceService; | |
56 | -import org.thingsboard.server.dao.model.ModelConstants; | |
57 | -import org.thingsboard.server.dao.plugin.PluginService; | |
58 | -import org.thingsboard.server.dao.rule.RuleService; | |
59 | -import org.thingsboard.server.dao.tenant.TenantService; | |
60 | -import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
61 | -import org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin; | |
62 | -import org.junit.After; | |
63 | -import org.junit.Before; | |
64 | -import org.junit.Test; | |
65 | -import org.mockito.Mockito; | |
66 | -import org.springframework.test.util.ReflectionTestUtils; | |
67 | - | |
68 | -import com.fasterxml.jackson.databind.JsonNode; | |
69 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
70 | - | |
71 | -public class DefaultActorServiceTest { | |
72 | - | |
73 | - private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); | |
74 | - | |
75 | - private static final String PLUGIN_ID = "9fb2e951-e298-4acb-913a-db69af8a15f4"; | |
76 | - private static final String FILTERS_CONFIGURATION = | |
77 | - "[{\"clazz\":\"org.thingsboard.server.extensions.core.filter.MsgTypeFilter\", \"name\":\"TelemetryFilter\", \"configuration\": {\"messageTypes\":[\"POST_TELEMETRY\",\"POST_ATTRIBUTES\",\"GET_ATTRIBUTES\"]}}]"; | |
78 | - private static final String ACTION_CONFIGURATION = "{\"pluginToken\":\"telemetry\", \"clazz\":\"org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction\", \"name\":\"TelemetryMsgConverterAction\", \"configuration\":{}}"; | |
79 | - private static final String PLUGIN_CONFIGURATION = "{}"; | |
80 | - private DefaultActorService actorService; | |
81 | - private ActorSystemContext actorContext; | |
82 | - | |
83 | - private PluginService pluginService; | |
84 | - private RuleService ruleService; | |
85 | - private DeviceAuthService deviceAuthService; | |
86 | - private DeviceService deviceService; | |
87 | - private TimeseriesService tsService; | |
88 | - private TenantService tenantService; | |
89 | - private ClusterRpcService rpcService; | |
90 | - private DiscoveryService discoveryService; | |
91 | - private ClusterRoutingService routingService; | |
92 | - private AttributesService attributesService; | |
93 | - private ComponentDiscoveryService componentService; | |
94 | - private EventService eventService; | |
95 | - private ServerInstance serverInstance; | |
96 | - | |
97 | - private RuleMetaData ruleMock; | |
98 | - private PluginMetaData pluginMock; | |
99 | - private RuleId ruleId = new RuleId(UUID.randomUUID()); | |
100 | - private PluginId pluginId = new PluginId(UUID.fromString(PLUGIN_ID)); | |
101 | - private TenantId tenantId = new TenantId(UUID.randomUUID()); | |
102 | - | |
103 | - | |
104 | - @Before | |
105 | - public void before() throws Exception { | |
106 | - actorService = new DefaultActorService(); | |
107 | - actorContext = new ActorSystemContext(); | |
108 | - | |
109 | - tenantService = mock(TenantService.class); | |
110 | - pluginService = mock(PluginService.class); | |
111 | - ruleService = mock(RuleService.class); | |
112 | - deviceAuthService = mock(DeviceAuthService.class); | |
113 | - deviceService = mock(DeviceService.class); | |
114 | - tsService = mock(TimeseriesService.class); | |
115 | - rpcService = mock(ClusterRpcService.class); | |
116 | - discoveryService = mock(DiscoveryService.class); | |
117 | - routingService = mock(ClusterRoutingService.class); | |
118 | - attributesService = mock(AttributesService.class); | |
119 | - componentService = mock(ComponentDiscoveryService.class); | |
120 | - eventService = mock(EventService.class); | |
121 | - serverInstance = new ServerInstance(ServerInstanceProtos.ServerInfo.newBuilder().setHost("localhost").setPort(8080).build()); | |
122 | - | |
123 | - ReflectionTestUtils.setField(actorService, "actorContext", actorContext); | |
124 | - ReflectionTestUtils.setField(actorService, "rpcService", rpcService); | |
125 | - ReflectionTestUtils.setField(actorService, "discoveryService", discoveryService); | |
126 | - | |
127 | - ReflectionTestUtils.setField(actorContext, "syncSessionTimeout", 10000L); | |
128 | - ReflectionTestUtils.setField(actorContext, "pluginActorTerminationDelay", 10000L); | |
129 | - ReflectionTestUtils.setField(actorContext, "pluginErrorPersistFrequency", 10000L); | |
130 | - ReflectionTestUtils.setField(actorContext, "ruleActorTerminationDelay", 10000L); | |
131 | - ReflectionTestUtils.setField(actorContext, "ruleErrorPersistFrequency", 10000L); | |
132 | - ReflectionTestUtils.setField(actorContext, "pluginProcessingTimeout", 60000L); | |
133 | - ReflectionTestUtils.setField(actorContext, "tenantService", tenantService); | |
134 | - ReflectionTestUtils.setField(actorContext, "pluginService", pluginService); | |
135 | - ReflectionTestUtils.setField(actorContext, "ruleService", ruleService); | |
136 | - ReflectionTestUtils.setField(actorContext, "deviceAuthService", deviceAuthService); | |
137 | - ReflectionTestUtils.setField(actorContext, "deviceService", deviceService); | |
138 | - ReflectionTestUtils.setField(actorContext, "tsService", tsService); | |
139 | - ReflectionTestUtils.setField(actorContext, "rpcService", rpcService); | |
140 | - ReflectionTestUtils.setField(actorContext, "discoveryService", discoveryService); | |
141 | - ReflectionTestUtils.setField(actorContext, "tsService", tsService); | |
142 | - ReflectionTestUtils.setField(actorContext, "routingService", routingService); | |
143 | - ReflectionTestUtils.setField(actorContext, "attributesService", attributesService); | |
144 | - ReflectionTestUtils.setField(actorContext, "componentService", componentService); | |
145 | - ReflectionTestUtils.setField(actorContext, "eventService", eventService); | |
146 | - | |
147 | - | |
148 | - when(routingService.resolveById((EntityId) any())).thenReturn(Optional.empty()); | |
149 | - | |
150 | - when(discoveryService.getCurrentServer()).thenReturn(serverInstance); | |
151 | - | |
152 | - ruleMock = mock(RuleMetaData.class); | |
153 | - when(ruleMock.getId()).thenReturn(ruleId); | |
154 | - when(ruleMock.getState()).thenReturn(ComponentLifecycleState.ACTIVE); | |
155 | - when(ruleMock.getPluginToken()).thenReturn("telemetry"); | |
156 | - TextPageData<RuleMetaData> systemRules = new TextPageData<>(Collections.emptyList(), null, false); | |
157 | - TextPageData<RuleMetaData> tenantRules = new TextPageData<>(Collections.singletonList(ruleMock), null, false); | |
158 | - when(ruleService.findSystemRules(any())).thenReturn(systemRules); | |
159 | - when(ruleService.findTenantRules(any(), any())).thenReturn(tenantRules); | |
160 | - when(ruleService.findRuleById(ruleId)).thenReturn(ruleMock); | |
161 | - | |
162 | - pluginMock = mock(PluginMetaData.class); | |
163 | - when(pluginMock.getTenantId()).thenReturn(SYSTEM_TENANT); | |
164 | - when(pluginMock.getId()).thenReturn(pluginId); | |
165 | - when(pluginMock.getState()).thenReturn(ComponentLifecycleState.ACTIVE); | |
166 | - TextPageData<PluginMetaData> systemPlugins = new TextPageData<>(Collections.singletonList(pluginMock), null, false); | |
167 | - TextPageData<PluginMetaData> tenantPlugins = new TextPageData<>(Collections.emptyList(), null, false); | |
168 | - when(pluginService.findSystemPlugins(any())).thenReturn(systemPlugins); | |
169 | - when(pluginService.findTenantPlugins(any(), any())).thenReturn(tenantPlugins); | |
170 | - when(pluginService.findPluginByApiToken("telemetry")).thenReturn(pluginMock); | |
171 | - when(pluginService.findPluginById(pluginId)).thenReturn(pluginMock); | |
172 | - | |
173 | - TextPageData<Tenant> tenants = new TextPageData<>(Collections.emptyList(), null, false); | |
174 | - when(tenantService.findTenants(any())).thenReturn(tenants); | |
175 | - } | |
176 | - | |
177 | - private void initActorSystem() { | |
178 | - actorService.initActorSystem(); | |
179 | - } | |
180 | - | |
181 | - @After | |
182 | - public void after() { | |
183 | - actorService.stopActorSystem(); | |
184 | - } | |
185 | - | |
186 | - @Test | |
187 | - public void testBasicPostWithSyncSession() throws Exception { | |
188 | - SessionContext ssnCtx = mock(SessionContext.class); | |
189 | - KvEntry entry1 = new StringDataEntry("key1", "value1"); | |
190 | - KvEntry entry2 = new StringDataEntry("key2", "value2"); | |
191 | - BasicTelemetryUploadRequest telemetry = new BasicTelemetryUploadRequest(); | |
192 | - long ts = 42; | |
193 | - telemetry.add(ts, entry1); | |
194 | - telemetry.add(ts, entry2); | |
195 | - BasicAdaptorToSessionActorMsg msg = new BasicAdaptorToSessionActorMsg(ssnCtx, telemetry); | |
196 | - | |
197 | - DeviceId deviceId = new DeviceId(UUID.randomUUID()); | |
198 | - | |
199 | - DeviceCredentialsFilter filter = new DeviceTokenCredentials("token1"); | |
200 | - Device device = mock(Device.class); | |
201 | - | |
202 | - when(device.getId()).thenReturn(deviceId); | |
203 | - when(device.getTenantId()).thenReturn(tenantId); | |
204 | - when(ssnCtx.getSessionId()).thenReturn(new DummySessionID("session1")); | |
205 | - when(ssnCtx.getSessionType()).thenReturn(SessionType.SYNC); | |
206 | - when(deviceAuthService.process(filter)).thenReturn(DeviceAuthResult.of(deviceId)); | |
207 | - when(deviceService.findDeviceById(deviceId)).thenReturn(device); | |
208 | - | |
209 | - ObjectMapper ruleMapper = new ObjectMapper(); | |
210 | - when(ruleMock.getFilters()).thenReturn(ruleMapper.readTree(FILTERS_CONFIGURATION)); | |
211 | - when(ruleMock.getAction()).thenReturn(ruleMapper.readTree(ACTION_CONFIGURATION)); | |
212 | - | |
213 | - ComponentDescriptor filterComp = new ComponentDescriptor(); | |
214 | - filterComp.setClazz("org.thingsboard.server.extensions.core.filter.MsgTypeFilter"); | |
215 | - filterComp.setType(ComponentType.FILTER); | |
216 | - when(componentService.getComponent("org.thingsboard.server.extensions.core.filter.MsgTypeFilter")) | |
217 | - .thenReturn(Optional.of(filterComp)); | |
218 | - | |
219 | - ComponentDescriptor actionComp = new ComponentDescriptor(); | |
220 | - actionComp.setClazz("org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction"); | |
221 | - actionComp.setType(ComponentType.ACTION); | |
222 | - when(componentService.getComponent("org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction")) | |
223 | - .thenReturn(Optional.of(actionComp)); | |
224 | - | |
225 | - ObjectMapper pluginMapper = new ObjectMapper(); | |
226 | - JsonNode pluginAdditionalInfo = pluginMapper.readTree(PLUGIN_CONFIGURATION); | |
227 | - when(pluginMock.getConfiguration()).thenReturn(pluginAdditionalInfo); | |
228 | - when(pluginMock.getClazz()).thenReturn(TelemetryStoragePlugin.class.getName()); | |
229 | - | |
230 | - when(attributesService.findAll(deviceId, DataConstants.CLIENT_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList())); | |
231 | - when(attributesService.findAll(deviceId, DataConstants.SHARED_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList())); | |
232 | - when(attributesService.findAll(deviceId, DataConstants.SERVER_SCOPE)).thenReturn(Futures.immediateFuture(Collections.emptyList())); | |
233 | - | |
234 | - initActorSystem(); | |
235 | - Thread.sleep(1000); | |
236 | - actorService.process(new BasicToDeviceActorSessionMsg(device, msg)); | |
237 | - | |
238 | - // Check that device data was saved to DB; | |
239 | - List<TsKvEntry> expected = new ArrayList<>(); | |
240 | - expected.add(new BasicTsKvEntry(ts, entry1)); | |
241 | - expected.add(new BasicTsKvEntry(ts, entry2)); | |
242 | - verify(tsService, Mockito.timeout(5000)).save(deviceId, expected, 0L); | |
243 | - } | |
244 | - | |
245 | -} |
application/src/test/java/org/thingsboard/server/actors/DummySessionID.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors; | |
17 | - | |
18 | -import org.thingsboard.server.common.data.id.SessionId; | |
19 | - | |
20 | -public class DummySessionID implements SessionId { | |
21 | - | |
22 | - @Override | |
23 | - public String toString() { | |
24 | - return id; | |
25 | - } | |
26 | - | |
27 | - private final String id; | |
28 | - | |
29 | - public DummySessionID(String id) { | |
30 | - this.id = id; | |
31 | - } | |
32 | - | |
33 | - @Override | |
34 | - public String toUidStr() { | |
35 | - return id; | |
36 | - } | |
37 | - | |
38 | - @Override | |
39 | - public int hashCode() { | |
40 | - final int prime = 31; | |
41 | - int result = 1; | |
42 | - result = prime * result + ((id == null) ? 0 : id.hashCode()); | |
43 | - return result; | |
44 | - } | |
45 | - | |
46 | - @Override | |
47 | - public boolean equals(Object obj) { | |
48 | - if (this == obj) | |
49 | - return true; | |
50 | - if (obj == null) | |
51 | - return false; | |
52 | - if (getClass() != obj.getClass()) | |
53 | - return false; | |
54 | - DummySessionID other = (DummySessionID) obj; | |
55 | - if (id == null) { | |
56 | - if (other.id != null) | |
57 | - return false; | |
58 | - } else if (!id.equals(other.id)) | |
59 | - return false; | |
60 | - return true; | |
61 | - } | |
62 | - | |
63 | -} |
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.core.type.TypeReference; |
19 | +import com.fasterxml.jackson.databind.JsonNode; | |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
19 | 21 | import org.thingsboard.server.common.data.DataConstants; |
20 | 22 | import org.thingsboard.server.common.data.Event; |
21 | 23 | import org.thingsboard.server.common.data.id.EntityId; |
... | ... | @@ -25,12 +27,18 @@ import org.thingsboard.server.common.data.page.TimePageData; |
25 | 27 | import org.thingsboard.server.common.data.page.TimePageLink; |
26 | 28 | import org.thingsboard.server.common.data.rule.RuleChain; |
27 | 29 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
30 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
31 | + | |
32 | +import java.io.IOException; | |
28 | 33 | |
29 | 34 | /** |
30 | 35 | * Created by ashvayka on 20.03.18. |
31 | 36 | */ |
32 | 37 | public class AbstractRuleEngineControllerTest extends AbstractControllerTest { |
33 | 38 | |
39 | + @Autowired | |
40 | + protected RuleChainService ruleChainService; | |
41 | + | |
34 | 42 | protected RuleChain saveRuleChain(RuleChain ruleChain) throws Exception { |
35 | 43 | return doPost("/api/ruleChain", ruleChain, RuleChain.class); |
36 | 44 | } |
... | ... | @@ -53,4 +61,13 @@ public class AbstractRuleEngineControllerTest extends AbstractControllerTest { |
53 | 61 | new TypeReference<TimePageData<Event>>() { |
54 | 62 | }, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG_RULE_NODE, tenantId.getId()); |
55 | 63 | } |
64 | + | |
65 | + protected JsonNode getMetadata(Event outEvent) { | |
66 | + String metaDataStr = outEvent.getBody().get("metadata").asText(); | |
67 | + try { | |
68 | + return mapper.readTree(metaDataStr); | |
69 | + } catch (IOException e) { | |
70 | + throw new RuntimeException(e); | |
71 | + } | |
72 | + } | |
56 | 73 | } | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import org.junit.After; |
20 | 20 | import org.junit.Assert; |
21 | 21 | import org.junit.Before; |
22 | 22 | import org.junit.Test; |
23 | +import org.thingsboard.rule.engine.filter.TbJsFilterNode; | |
23 | 24 | import org.thingsboard.server.common.data.Tenant; |
24 | 25 | import org.thingsboard.server.common.data.User; |
25 | 26 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
... | ... | @@ -35,7 +36,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. |
35 | 36 | |
36 | 37 | public abstract class BaseComponentDescriptorControllerTest extends AbstractControllerTest { |
37 | 38 | |
38 | - private static final int AMOUNT_OF_DEFAULT_PLUGINS_DESCRIPTORS = 5; | |
39 | + private static final int AMOUNT_OF_DEFAULT_FILTER_NODES = 3; | |
39 | 40 | private Tenant savedTenant; |
40 | 41 | private User tenantAdmin; |
41 | 42 | |
... | ... | @@ -69,38 +70,28 @@ public abstract class BaseComponentDescriptorControllerTest extends AbstractCont |
69 | 70 | @Test |
70 | 71 | public void testGetByClazz() throws Exception { |
71 | 72 | ComponentDescriptor descriptor = |
72 | - doGet("/api/component/" + TelemetryStoragePlugin.class.getName(), ComponentDescriptor.class); | |
73 | + doGet("/api/component/" + TbJsFilterNode.class.getName(), ComponentDescriptor.class); | |
73 | 74 | |
74 | 75 | Assert.assertNotNull(descriptor); |
75 | 76 | Assert.assertNotNull(descriptor.getId()); |
76 | 77 | Assert.assertNotNull(descriptor.getName()); |
77 | 78 | Assert.assertEquals(ComponentScope.TENANT, descriptor.getScope()); |
78 | - Assert.assertEquals(ComponentType.PLUGIN, descriptor.getType()); | |
79 | + Assert.assertEquals(ComponentType.FILTER, descriptor.getType()); | |
79 | 80 | Assert.assertEquals(descriptor.getClazz(), descriptor.getClazz()); |
80 | 81 | } |
81 | 82 | |
82 | 83 | @Test |
83 | 84 | public void testGetByType() throws Exception { |
84 | 85 | List<ComponentDescriptor> descriptors = readResponse( |
85 | - doGet("/api/components/" + ComponentType.PLUGIN).andExpect(status().isOk()), new TypeReference<List<ComponentDescriptor>>() { | |
86 | + doGet("/api/components/" + ComponentType.FILTER).andExpect(status().isOk()), new TypeReference<List<ComponentDescriptor>>() { | |
86 | 87 | }); |
87 | 88 | |
88 | 89 | Assert.assertNotNull(descriptors); |
89 | - Assert.assertEquals(AMOUNT_OF_DEFAULT_PLUGINS_DESCRIPTORS, descriptors.size()); | |
90 | + Assert.assertEquals(AMOUNT_OF_DEFAULT_FILTER_NODES, descriptors.size()); | |
90 | 91 | |
91 | 92 | for (ComponentType type : ComponentType.values()) { |
92 | 93 | doGet("/api/components/" + type).andExpect(status().isOk()); |
93 | 94 | } |
94 | 95 | } |
95 | 96 | |
96 | - @Test | |
97 | - public void testGetActionsByType() throws Exception { | |
98 | - List<ComponentDescriptor> descriptors = readResponse( | |
99 | - doGet("/api/components/actions/" + TelemetryStoragePlugin.class.getName()).andExpect(status().isOk()), new TypeReference<List<ComponentDescriptor>>() { | |
100 | - }); | |
101 | - | |
102 | - Assert.assertNotNull(descriptors); | |
103 | - Assert.assertEquals(1, descriptors.size()); | |
104 | - Assert.assertEquals(TelemetryPluginAction.class.getName(), descriptors.get(0).getClazz()); | |
105 | - } | |
106 | 97 | } | ... | ... |
application/src/test/java/org/thingsboard/server/controller/BasePluginControllerTest.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.controller; | |
17 | - | |
18 | -import com.fasterxml.jackson.core.type.TypeReference; | |
19 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | -import org.junit.After; | |
21 | -import org.junit.Assert; | |
22 | -import org.junit.Before; | |
23 | -import org.junit.Test; | |
24 | -import org.thingsboard.server.common.data.Tenant; | |
25 | -import org.thingsboard.server.common.data.User; | |
26 | -import org.thingsboard.server.common.data.page.TextPageData; | |
27 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
28 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
29 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
30 | -import org.thingsboard.server.common.data.security.Authority; | |
31 | -import org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin; | |
32 | - | |
33 | -import java.util.ArrayList; | |
34 | -import java.util.Collections; | |
35 | -import java.util.List; | |
36 | -import java.util.stream.Collectors; | |
37 | - | |
38 | -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |
39 | - | |
40 | -public abstract class BasePluginControllerTest extends AbstractControllerTest { | |
41 | - | |
42 | - private IdComparator<PluginMetaData> idComparator = new IdComparator<>(); | |
43 | - | |
44 | - private final ObjectMapper mapper = new ObjectMapper(); | |
45 | - private Tenant savedTenant; | |
46 | - private User tenantAdmin; | |
47 | - | |
48 | - @Before | |
49 | - public void beforeTest() throws Exception { | |
50 | - loginSysAdmin(); | |
51 | - | |
52 | - Tenant tenant = new Tenant(); | |
53 | - tenant.setTitle("My tenant"); | |
54 | - savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
55 | - Assert.assertNotNull(savedTenant); | |
56 | - | |
57 | - tenantAdmin = new User(); | |
58 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
59 | - tenantAdmin.setTenantId(savedTenant.getId()); | |
60 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
61 | - tenantAdmin.setFirstName("Joe"); | |
62 | - tenantAdmin.setLastName("Downs"); | |
63 | - | |
64 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
65 | - } | |
66 | - | |
67 | - @After | |
68 | - public void afterTest() throws Exception { | |
69 | - loginSysAdmin(); | |
70 | - | |
71 | - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
72 | - .andExpect(status().isOk()); | |
73 | - } | |
74 | - | |
75 | - @Test | |
76 | - public void testSavePlugin() throws Exception { | |
77 | - PluginMetaData plugin = new PluginMetaData(); | |
78 | - doPost("/api/plugin", plugin).andExpect(status().isBadRequest()); | |
79 | - plugin.setName("My plugin"); | |
80 | - doPost("/api/plugin", plugin).andExpect(status().isBadRequest()); | |
81 | - plugin.setApiToken("myplugin"); | |
82 | - doPost("/api/plugin", plugin).andExpect(status().isBadRequest()); | |
83 | - plugin.setConfiguration(mapper.readTree("{}")); | |
84 | - doPost("/api/plugin", plugin).andExpect(status().isBadRequest()); | |
85 | - plugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
86 | - PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class); | |
87 | - | |
88 | - Assert.assertNotNull(savedPlugin); | |
89 | - Assert.assertNotNull(savedPlugin.getId()); | |
90 | - Assert.assertTrue(savedPlugin.getCreatedTime() > 0); | |
91 | - Assert.assertEquals(savedTenant.getId(), savedPlugin.getTenantId()); | |
92 | - } | |
93 | - | |
94 | - @Test | |
95 | - public void testFindPluginById() throws Exception { | |
96 | - PluginMetaData plugin = new PluginMetaData(); | |
97 | - plugin.setName("My plugin"); | |
98 | - plugin.setApiToken("myplugin"); | |
99 | - plugin.setConfiguration(mapper.readTree("{}")); | |
100 | - plugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
101 | - | |
102 | - PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class); | |
103 | - PluginMetaData foundPlugin = doGet("/api/plugin/" + savedPlugin.getId().getId().toString(), PluginMetaData.class); | |
104 | - Assert.assertNotNull(foundPlugin); | |
105 | - Assert.assertEquals(savedPlugin, foundPlugin); | |
106 | - } | |
107 | - | |
108 | - @Test | |
109 | - public void testActivatePlugin() throws Exception { | |
110 | - PluginMetaData plugin = new PluginMetaData(); | |
111 | - plugin.setName("My plugin"); | |
112 | - plugin.setApiToken("myplugin"); | |
113 | - plugin.setConfiguration(mapper.readTree("{}")); | |
114 | - plugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
115 | - | |
116 | - PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class); | |
117 | - | |
118 | - doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk()); | |
119 | - } | |
120 | - | |
121 | - @Test | |
122 | - public void testSuspendPlugin() throws Exception { | |
123 | - PluginMetaData plugin = new PluginMetaData(); | |
124 | - plugin.setName("My plugin"); | |
125 | - plugin.setApiToken("myplugin"); | |
126 | - plugin.setConfiguration(mapper.readTree("{}")); | |
127 | - plugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
128 | - | |
129 | - PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class); | |
130 | - | |
131 | - doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk()); | |
132 | - | |
133 | - RuleMetaData rule = BaseRuleControllerTest.createRuleMetaData(savedPlugin); | |
134 | - RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class); | |
135 | - doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isOk()); | |
136 | - | |
137 | - doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/suspend").andExpect(status().isBadRequest()); | |
138 | - | |
139 | - doPost("/api/rule/" + savedRule.getId().getId().toString() + "/suspend").andExpect(status().isOk()); | |
140 | - | |
141 | - doPost("/api/plugin/" + savedPlugin.getId().getId().toString() + "/suspend").andExpect(status().isOk()); | |
142 | - } | |
143 | - | |
144 | - @Test | |
145 | - public void testDeletePluginById() throws Exception { | |
146 | - PluginMetaData plugin = new PluginMetaData(); | |
147 | - plugin.setName("My plugin"); | |
148 | - plugin.setApiToken("myplugin"); | |
149 | - plugin.setConfiguration(mapper.readTree("{}")); | |
150 | - plugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
151 | - | |
152 | - PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class); | |
153 | - | |
154 | - RuleMetaData rule = BaseRuleControllerTest.createRuleMetaData(savedPlugin); | |
155 | - RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class); | |
156 | - | |
157 | - doDelete("/api/plugin/" + savedPlugin.getId().getId()).andExpect(status().isBadRequest()); | |
158 | - | |
159 | - doDelete("/api/rule/" + savedRule.getId().getId()).andExpect(status().isOk()); | |
160 | - | |
161 | - doDelete("/api/plugin/" + savedPlugin.getId().getId()).andExpect(status().isOk()); | |
162 | - doGet("/api/plugin/" + savedPlugin.getId().getId().toString()).andExpect(status().isNotFound()); | |
163 | - } | |
164 | - | |
165 | - @Test | |
166 | - public void testFindPluginByToken() throws Exception { | |
167 | - PluginMetaData plugin = new PluginMetaData(); | |
168 | - plugin.setName("My plugin"); | |
169 | - plugin.setApiToken("myplugin"); | |
170 | - plugin.setConfiguration(mapper.readTree("{}")); | |
171 | - plugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
172 | - | |
173 | - PluginMetaData savedPlugin = doPost("/api/plugin", plugin, PluginMetaData.class); | |
174 | - PluginMetaData foundPlugin = doGet("/api/plugin/token/" + "myplugin", PluginMetaData.class); | |
175 | - Assert.assertNotNull(foundPlugin); | |
176 | - Assert.assertEquals(savedPlugin, foundPlugin); | |
177 | - } | |
178 | - | |
179 | - @Test | |
180 | - public void testFindCurrentTenantPlugins() throws Exception { | |
181 | - List<PluginMetaData> plugins = testPluginsCreation("/api/plugin"); | |
182 | - for (PluginMetaData plugin : plugins) { | |
183 | - doDelete("/api/plugin/" + plugin.getId().getId()).andExpect(status().isOk()); | |
184 | - } | |
185 | - } | |
186 | - | |
187 | - @Test | |
188 | - public void testFindSystemPlugins() throws Exception { | |
189 | - loginSysAdmin(); | |
190 | - List<PluginMetaData> plugins = testPluginsCreation("/api/plugin/system"); | |
191 | - for (PluginMetaData plugin : plugins) { | |
192 | - doDelete("/api/plugin/" + plugin.getId().getId()).andExpect(status().isOk()); | |
193 | - } | |
194 | - } | |
195 | - | |
196 | - private List<PluginMetaData> testPluginsCreation(String url) throws Exception { | |
197 | - List<PluginMetaData> plugins = new ArrayList<>(); | |
198 | - for (int i = 0; i < 111; i++) { | |
199 | - PluginMetaData plugin = new PluginMetaData(); | |
200 | - plugin.setName("My plugin"); | |
201 | - plugin.setApiToken("myplugin" + i); | |
202 | - plugin.setConfiguration(mapper.readTree("{}")); | |
203 | - plugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
204 | - plugins.add(doPost("/api/plugin", plugin, PluginMetaData.class)); | |
205 | - } | |
206 | - | |
207 | - List<PluginMetaData> loadedPlugins = new ArrayList<>(); | |
208 | - TextPageLink pageLink = new TextPageLink(23); | |
209 | - TextPageData<PluginMetaData> pageData; | |
210 | - do { | |
211 | - pageData = doGetTypedWithPageLink(url + "?", | |
212 | - new TypeReference<TextPageData<PluginMetaData>>() { | |
213 | - }, pageLink); | |
214 | - loadedPlugins.addAll(pageData.getData()); | |
215 | - if (pageData.hasNext()) { | |
216 | - pageLink = pageData.getNextPageLink(); | |
217 | - } | |
218 | - } while (pageData.hasNext()); | |
219 | - | |
220 | - loadedPlugins = loadedPlugins.stream() | |
221 | - .filter(p -> !p.getName().equals("System Telemetry Plugin")) | |
222 | - .filter(p -> !p.getName().equals("Mail Sender Plugin")) | |
223 | - .filter(p -> !p.getName().equals("System RPC Plugin")) | |
224 | - .collect(Collectors.toList()); | |
225 | - | |
226 | - Collections.sort(plugins, idComparator); | |
227 | - Collections.sort(loadedPlugins, idComparator); | |
228 | - | |
229 | - Assert.assertEquals(plugins, loadedPlugins); | |
230 | - return loadedPlugins; | |
231 | - } | |
232 | -} |
application/src/test/java/org/thingsboard/server/controller/BaseRuleControllerTest.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.controller; | |
17 | - | |
18 | -import com.fasterxml.jackson.core.type.TypeReference; | |
19 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | -import org.junit.After; | |
21 | -import org.junit.Assert; | |
22 | -import org.junit.Before; | |
23 | -import org.junit.Test; | |
24 | -import org.thingsboard.server.common.data.Tenant; | |
25 | -import org.thingsboard.server.common.data.User; | |
26 | -import org.thingsboard.server.common.data.page.TextPageData; | |
27 | -import org.thingsboard.server.common.data.page.TextPageLink; | |
28 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
29 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
30 | -import org.thingsboard.server.common.data.security.Authority; | |
31 | -import org.thingsboard.server.extensions.core.plugin.telemetry.TelemetryStoragePlugin; | |
32 | - | |
33 | -import java.io.IOException; | |
34 | -import java.util.ArrayList; | |
35 | -import java.util.Collections; | |
36 | -import java.util.List; | |
37 | -import java.util.stream.Collectors; | |
38 | - | |
39 | -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |
40 | - | |
41 | -public abstract class BaseRuleControllerTest extends AbstractControllerTest { | |
42 | - | |
43 | - private IdComparator<RuleMetaData> idComparator = new IdComparator<>(); | |
44 | - | |
45 | - private static final ObjectMapper mapper = new ObjectMapper(); | |
46 | - private Tenant savedTenant; | |
47 | - private User tenantAdmin; | |
48 | - private PluginMetaData sysPlugin; | |
49 | - private PluginMetaData tenantPlugin; | |
50 | - | |
51 | - @Before | |
52 | - public void beforeTest() throws Exception { | |
53 | - loginSysAdmin(); | |
54 | - | |
55 | - sysPlugin = new PluginMetaData(); | |
56 | - sysPlugin.setName("Sys plugin"); | |
57 | - sysPlugin.setApiToken("sysplugin"); | |
58 | - sysPlugin.setConfiguration(mapper.readTree("{}")); | |
59 | - sysPlugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
60 | - sysPlugin = doPost("/api/plugin", sysPlugin, PluginMetaData.class); | |
61 | - | |
62 | - Tenant tenant = new Tenant(); | |
63 | - tenant.setTitle("My tenant"); | |
64 | - savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
65 | - Assert.assertNotNull(savedTenant); | |
66 | - | |
67 | - tenantAdmin = new User(); | |
68 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
69 | - tenantAdmin.setTenantId(savedTenant.getId()); | |
70 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
71 | - tenantAdmin.setFirstName("Joe"); | |
72 | - tenantAdmin.setLastName("Downs"); | |
73 | - | |
74 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
75 | - | |
76 | - tenantPlugin = new PluginMetaData(); | |
77 | - tenantPlugin.setName("My plugin"); | |
78 | - tenantPlugin.setApiToken("myplugin"); | |
79 | - tenantPlugin.setConfiguration(mapper.readTree("{}")); | |
80 | - tenantPlugin.setClazz(TelemetryStoragePlugin.class.getName()); | |
81 | - tenantPlugin = doPost("/api/plugin", tenantPlugin, PluginMetaData.class); | |
82 | - } | |
83 | - | |
84 | - @After | |
85 | - public void afterTest() throws Exception { | |
86 | - loginSysAdmin(); | |
87 | - | |
88 | - doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
89 | - .andExpect(status().isOk()); | |
90 | - | |
91 | - doDelete("/api/plugin/" + sysPlugin.getId().getId()).andExpect(status().isOk()); | |
92 | - } | |
93 | - | |
94 | - @Test | |
95 | - public void testSaveRule() throws Exception { | |
96 | - RuleMetaData rule = new RuleMetaData(); | |
97 | - doPost("/api/rule", rule).andExpect(status().isBadRequest()); | |
98 | - rule.setName("My Rule"); | |
99 | - doPost("/api/rule", rule).andExpect(status().isBadRequest()); | |
100 | - rule.setPluginToken(tenantPlugin.getApiToken()); | |
101 | - doPost("/api/rule", rule).andExpect(status().isBadRequest()); | |
102 | - rule.setFilters(mapper.readTree("[{\"clazz\":\"org.thingsboard.server.extensions.core.filter.MsgTypeFilter\", " + | |
103 | - "\"name\":\"TelemetryFilter\", " + | |
104 | - "\"configuration\": {\"messageTypes\":[\"POST_TELEMETRY\",\"POST_ATTRIBUTES\",\"GET_ATTRIBUTES\"]}}]")); | |
105 | - doPost("/api/rule", rule).andExpect(status().isBadRequest()); | |
106 | - rule.setAction(mapper.readTree("{\"clazz\":\"org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction\", \"name\":\"TelemetryMsgConverterAction\", \"configuration\":{\"timeUnit\":\"DAYS\", \"ttlValue\":1}}")); | |
107 | - | |
108 | - RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class); | |
109 | - Assert.assertNotNull(savedRule); | |
110 | - Assert.assertNotNull(savedRule.getId()); | |
111 | - Assert.assertTrue(savedRule.getCreatedTime() > 0); | |
112 | - Assert.assertEquals(savedTenant.getId(), savedRule.getTenantId()); | |
113 | - } | |
114 | - | |
115 | - @Test | |
116 | - public void testFindRuleById() throws Exception { | |
117 | - RuleMetaData rule = createRuleMetaData(tenantPlugin); | |
118 | - RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class); | |
119 | - | |
120 | - RuleMetaData foundRule = doGet("/api/rule/" + savedRule.getId().getId().toString(), RuleMetaData.class); | |
121 | - Assert.assertNotNull(foundRule); | |
122 | - Assert.assertEquals(savedRule, foundRule); | |
123 | - } | |
124 | - | |
125 | - @Test | |
126 | - public void testFindRuleByPluginToken() throws Exception { | |
127 | - RuleMetaData rule = createRuleMetaData(tenantPlugin); | |
128 | - RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class); | |
129 | - | |
130 | - List<RuleMetaData> foundRules = doGetTyped("/api/rule/token/" + savedRule.getPluginToken(), | |
131 | - new TypeReference<List<RuleMetaData>>() { | |
132 | - }); | |
133 | - Assert.assertNotNull(foundRules); | |
134 | - Assert.assertEquals(1, foundRules.size()); | |
135 | - Assert.assertEquals(savedRule, foundRules.get(0)); | |
136 | - } | |
137 | - | |
138 | - @Test | |
139 | - public void testActivateRule() throws Exception { | |
140 | - RuleMetaData rule = createRuleMetaData(tenantPlugin); | |
141 | - RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class); | |
142 | - | |
143 | - doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isBadRequest()); | |
144 | - | |
145 | - doPost("/api/plugin/" + tenantPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk()); | |
146 | - | |
147 | - doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isOk()); | |
148 | - } | |
149 | - | |
150 | - @Test | |
151 | - public void testSuspendRule() throws Exception { | |
152 | - RuleMetaData rule = createRuleMetaData(tenantPlugin); | |
153 | - RuleMetaData savedRule = doPost("/api/rule", rule, RuleMetaData.class); | |
154 | - | |
155 | - doPost("/api/plugin/" + tenantPlugin.getId().getId().toString() + "/activate").andExpect(status().isOk()); | |
156 | - doPost("/api/rule/" + savedRule.getId().getId().toString() + "/activate").andExpect(status().isOk()); | |
157 | - doPost("/api/rule/" + savedRule.getId().getId().toString() + "/suspend").andExpect(status().isOk()); | |
158 | - } | |
159 | - | |
160 | - @Test | |
161 | - public void testFindSystemRules() throws Exception { | |
162 | - loginSysAdmin(); | |
163 | - List<RuleMetaData> rules = testRulesCreation("/api/rule/system", sysPlugin); | |
164 | - for (RuleMetaData rule : rules) { | |
165 | - doDelete("/api/rule/" + rule.getId().getId()).andExpect(status().isOk()); | |
166 | - } | |
167 | - loginTenantAdmin(); | |
168 | - } | |
169 | - | |
170 | - @Test | |
171 | - public void testFindCurrentTenantPlugins() throws Exception { | |
172 | - List<RuleMetaData> rules = testRulesCreation("/api/rule", tenantPlugin); | |
173 | - for (RuleMetaData rule : rules) { | |
174 | - doDelete("/api/rule/" + rule.getId().getId()).andExpect(status().isOk()); | |
175 | - } | |
176 | - } | |
177 | - | |
178 | - @Test | |
179 | - public void testFindTenantPlugins() throws Exception { | |
180 | - List<RuleMetaData> rules = testRulesCreation("/api/rule", tenantPlugin); | |
181 | - loginSysAdmin(); | |
182 | - List<RuleMetaData> loadedRules = new ArrayList<>(); | |
183 | - TextPageLink pageLink = new TextPageLink(3); | |
184 | - TextPageData<RuleMetaData> pageData; | |
185 | - do { | |
186 | - pageData = doGetTypedWithPageLink("/api/rule/tenant/" + savedTenant.getId().getId().toString() + "?", | |
187 | - new TypeReference<TextPageData<RuleMetaData>>() { | |
188 | - }, pageLink); | |
189 | - loadedRules.addAll(pageData.getData()); | |
190 | - if (pageData.hasNext()) { | |
191 | - pageLink = pageData.getNextPageLink(); | |
192 | - } | |
193 | - } while (pageData.hasNext()); | |
194 | - | |
195 | - Collections.sort(rules, idComparator); | |
196 | - Collections.sort(loadedRules, idComparator); | |
197 | - | |
198 | - Assert.assertEquals(rules, loadedRules); | |
199 | - | |
200 | - for (RuleMetaData rule : rules) { | |
201 | - doDelete("/api/rule/" + rule.getId().getId()).andExpect(status().isOk()); | |
202 | - } | |
203 | - } | |
204 | - | |
205 | - private List<RuleMetaData> testRulesCreation(String url, PluginMetaData plugin) throws Exception { | |
206 | - List<RuleMetaData> rules = new ArrayList<>(); | |
207 | - for (int i = 0; i < 6; i++) { | |
208 | - RuleMetaData rule = createRuleMetaData(plugin); | |
209 | - rule.setPluginToken(plugin.getApiToken()); | |
210 | - rule.setName(rule.getName() + i); | |
211 | - rules.add(doPost("/api/rule", rule, RuleMetaData.class)); | |
212 | - } | |
213 | - | |
214 | - List<RuleMetaData> loadedRules = new ArrayList<>(); | |
215 | - TextPageLink pageLink = new TextPageLink(3); | |
216 | - TextPageData<RuleMetaData> pageData; | |
217 | - do { | |
218 | - pageData = doGetTypedWithPageLink(url + "?", | |
219 | - new TypeReference<TextPageData<RuleMetaData>>() { | |
220 | - }, pageLink); | |
221 | - loadedRules.addAll(pageData.getData()); | |
222 | - if (pageData.hasNext()) { | |
223 | - pageLink = pageData.getNextPageLink(); | |
224 | - } | |
225 | - } while (pageData.hasNext()); | |
226 | - | |
227 | - loadedRules = loadedRules.stream().filter(p -> !p.getName().equals("System Telemetry Rule")).collect(Collectors.toList()); | |
228 | - | |
229 | - Collections.sort(rules, idComparator); | |
230 | - Collections.sort(loadedRules, idComparator); | |
231 | - | |
232 | - Assert.assertEquals(rules, loadedRules); | |
233 | - return loadedRules; | |
234 | - } | |
235 | - | |
236 | - public static RuleMetaData createRuleMetaData(PluginMetaData plugin) throws IOException { | |
237 | - RuleMetaData rule = new RuleMetaData(); | |
238 | - rule.setName("My Rule"); | |
239 | - rule.setPluginToken(plugin.getApiToken()); | |
240 | - rule.setFilters(mapper.readTree("[{\"clazz\":\"org.thingsboard.server.extensions.core.filter.MsgTypeFilter\", " + | |
241 | - "\"name\":\"TelemetryFilter\", " + | |
242 | - "\"configuration\": {\"messageTypes\":[\"POST_TELEMETRY\",\"POST_ATTRIBUTES\",\"GET_ATTRIBUTES\"]}}]")); | |
243 | - rule.setAction(mapper.readTree("{\"clazz\":\"org.thingsboard.server.extensions.core.action.telemetry.TelemetryPluginAction\", \"name\":\"TelemetryMsgConverterAction\", " + | |
244 | - "\"configuration\":{\"timeUnit\":\"DAYS\", \"ttlValue\":1}}")); | |
245 | - return rule; | |
246 | - } | |
247 | -} |
... | ... | @@ -80,6 +80,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
80 | 80 | } |
81 | 81 | } |
82 | 82 | |
83 | + @Ignore | |
83 | 84 | @Test |
84 | 85 | public void testServerMqttOneWayRpc() throws Exception { |
85 | 86 | Device device = new Device(); |
... | ... | @@ -106,6 +107,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
106 | 107 | Assert.assertTrue(StringUtils.isEmpty(result)); |
107 | 108 | } |
108 | 109 | |
110 | + @Ignore | |
109 | 111 | @Test |
110 | 112 | public void testServerMqttOneWayRpcDeviceOffline() throws Exception { |
111 | 113 | Device device = new Device(); | ... | ... |
... | ... | @@ -24,7 +24,8 @@ import java.util.Arrays; |
24 | 24 | |
25 | 25 | @RunWith(ClasspathSuite.class) |
26 | 26 | @ClasspathSuite.ClassnameFilters({ |
27 | - "org.thingsboard.server.rules.flow.*Test"}) | |
27 | + "org.thingsboard.server.rules.flow.*Test", | |
28 | + "org.thingsboard.server.rules.lifecycle.*Test"}) | |
28 | 29 | public class RuleEngineSqlTestSuite { |
29 | 30 | |
30 | 31 | @ClassRule | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.rules.flow; |
17 | 17 | |
18 | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | 20 | import lombok.Data; |
20 | 21 | import lombok.extern.slf4j.Slf4j; |
21 | 22 | import org.junit.After; |
... | ... | @@ -28,6 +29,7 @@ import org.thingsboard.server.actors.service.ActorService; |
28 | 29 | import org.thingsboard.server.common.data.*; |
29 | 30 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
30 | 31 | import org.thingsboard.server.common.data.kv.StringDataEntry; |
32 | +import org.thingsboard.server.common.data.page.TextPageLink; | |
31 | 33 | import org.thingsboard.server.common.data.page.TimePageData; |
32 | 34 | import org.thingsboard.server.common.data.rule.RuleChain; |
33 | 35 | import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
... | ... | @@ -40,6 +42,7 @@ import org.thingsboard.server.controller.AbstractRuleEngineControllerTest; |
40 | 42 | import org.thingsboard.server.dao.attributes.AttributesService; |
41 | 43 | import org.thingsboard.server.dao.rule.RuleChainService; |
42 | 44 | |
45 | +import java.io.IOException; | |
43 | 46 | import java.util.Arrays; |
44 | 47 | import java.util.Collections; |
45 | 48 | |
... | ... | @@ -60,9 +63,6 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
60 | 63 | @Autowired |
61 | 64 | protected AttributesService attributesService; |
62 | 65 | |
63 | - @Autowired | |
64 | - protected RuleChainService ruleChainService; | |
65 | - | |
66 | 66 | @Before |
67 | 67 | public void beforeTest() throws Exception { |
68 | 68 | loginSysAdmin(); |
... | ... | @@ -71,6 +71,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
71 | 71 | tenant.setTitle("My tenant"); |
72 | 72 | savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
73 | 73 | Assert.assertNotNull(savedTenant); |
74 | + ruleChainService.deleteRuleChainsByTenantId(savedTenant.getId()); | |
74 | 75 | |
75 | 76 | tenantAdmin = new User(); |
76 | 77 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -166,7 +167,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
166 | 167 | Assert.assertEquals(ruleChain.getFirstRuleNodeId(), outEvent.getEntityId()); |
167 | 168 | Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText()); |
168 | 169 | |
169 | - Assert.assertEquals("serverAttributeValue1", outEvent.getBody().get("metadata").get("ss.serverAttributeKey1").asText()); | |
170 | + Assert.assertEquals("serverAttributeValue1", getMetadata(outEvent).get("ss_serverAttributeKey1").asText()); | |
170 | 171 | |
171 | 172 | RuleChain finalRuleChain = ruleChain; |
172 | 173 | RuleNode lastRuleNode = metaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get(); |
... | ... | @@ -183,8 +184,8 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
183 | 184 | Assert.assertEquals(lastRuleNode.getId(), outEvent.getEntityId()); |
184 | 185 | Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText()); |
185 | 186 | |
186 | - Assert.assertEquals("serverAttributeValue1", outEvent.getBody().get("metadata").get("ss.serverAttributeKey1").asText()); | |
187 | - Assert.assertEquals("serverAttributeValue2", outEvent.getBody().get("metadata").get("ss.serverAttributeKey2").asText()); | |
187 | + Assert.assertEquals("serverAttributeValue1", getMetadata(outEvent).get("ss_serverAttributeKey1").asText()); | |
188 | + Assert.assertEquals("serverAttributeValue2", getMetadata(outEvent).get("ss_serverAttributeKey2").asText()); | |
188 | 189 | } |
189 | 190 | |
190 | 191 | } | ... | ... |
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | package org.thingsboard.server.rules.lifecycle; |
17 | 17 | |
18 | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | 20 | import lombok.extern.slf4j.Slf4j; |
20 | 21 | import org.junit.After; |
21 | 22 | import org.junit.Assert; |
... | ... | @@ -42,6 +43,7 @@ import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; |
42 | 43 | import org.thingsboard.server.controller.AbstractRuleEngineControllerTest; |
43 | 44 | import org.thingsboard.server.dao.attributes.AttributesService; |
44 | 45 | |
46 | +import java.io.IOException; | |
45 | 47 | import java.util.Collections; |
46 | 48 | |
47 | 49 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
... | ... | @@ -69,6 +71,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac |
69 | 71 | tenant.setTitle("My tenant"); |
70 | 72 | savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
71 | 73 | Assert.assertNotNull(savedTenant); |
74 | + ruleChainService.deleteRuleChainsByTenantId(savedTenant.getId()); | |
72 | 75 | |
73 | 76 | tenantAdmin = new User(); |
74 | 77 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -152,7 +155,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac |
152 | 155 | Assert.assertEquals(ruleChain.getFirstRuleNodeId(), outEvent.getEntityId()); |
153 | 156 | Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText()); |
154 | 157 | |
155 | - Assert.assertEquals("serverAttributeValue", outEvent.getBody().get("metadata").get("ss.serverAttributeKey").asText()); | |
158 | + Assert.assertEquals("serverAttributeValue", getMetadata(outEvent).get("ss_serverAttributeKey").asText()); | |
156 | 159 | } |
157 | 160 | |
158 | 161 | } | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/rpc/RpcRequest.java
renamed from
extensions-core/src/main/java/org/thingsboard/server/extensions/core/plugin/rpc/cmd/RpcRequest.java
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.extensions.core.plugin.rpc.cmd; | |
16 | +package org.thingsboard.server.common.data.rpc; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/rpc/ToDeviceRpcRequestBody.java
renamed from
extensions-api/src/main/java/org/thingsboard/server/extensions/api/plugins/msg/ToDeviceRpcRequestBody.java
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.extensions.api.plugins.msg; | |
16 | +package org.thingsboard.server.common.data.rpc; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | ... | ... |
... | ... | @@ -22,6 +22,7 @@ import lombok.EqualsAndHashCode; |
22 | 22 | import lombok.extern.slf4j.Slf4j; |
23 | 23 | import org.thingsboard.server.common.data.HasName; |
24 | 24 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; |
25 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
25 | 26 | import org.thingsboard.server.common.data.id.RuleNodeId; |
26 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | 28 | |
... | ... | @@ -32,6 +33,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl |
32 | 33 | |
33 | 34 | private static final long serialVersionUID = -5656679015121235465L; |
34 | 35 | |
36 | + private RuleChainId ruleChainId; | |
35 | 37 | private String type; |
36 | 38 | private String name; |
37 | 39 | private boolean debugMode; |
... | ... | @@ -49,8 +51,10 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl |
49 | 51 | |
50 | 52 | public RuleNode(RuleNode ruleNode) { |
51 | 53 | super(ruleNode); |
54 | + this.ruleChainId = ruleNode.getRuleChainId(); | |
52 | 55 | this.type = ruleNode.getType(); |
53 | 56 | this.name = ruleNode.getName(); |
57 | + this.debugMode = ruleNode.isDebugMode(); | |
54 | 58 | this.setConfiguration(ruleNode.getConfiguration()); |
55 | 59 | } |
56 | 60 | ... | ... |
... | ... | @@ -18,27 +18,30 @@ package org.thingsboard.server.common.msg; |
18 | 18 | /** |
19 | 19 | * Created by ashvayka on 15.03.18. |
20 | 20 | */ |
21 | +//TODO: add all "See" references | |
21 | 22 | public enum MsgType { |
22 | 23 | |
23 | 24 | /** |
25 | + * ADDED/UPDATED/DELETED events for server nodes. | |
26 | + * | |
27 | + * See {@link org.thingsboard.server.common.msg.cluster.ClusterEventMsg} | |
28 | + */ | |
29 | + CLUSTER_EVENT_MSG, | |
30 | + | |
31 | + /** | |
24 | 32 | * ADDED/UPDATED/DELETED events for main entities. |
25 | 33 | * |
26 | - * @See {@link org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg} | |
34 | + * See {@link org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg} | |
27 | 35 | */ |
28 | 36 | COMPONENT_LIFE_CYCLE_MSG, |
29 | 37 | |
30 | 38 | /** |
31 | 39 | * Misc messages from the REST API/SERVICE layer to the new rule engine. |
32 | 40 | * |
33 | - * @See {@link org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg} | |
41 | + * See {@link org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg} | |
34 | 42 | */ |
35 | 43 | SERVICE_TO_RULE_ENGINE_MSG, |
36 | 44 | |
37 | - | |
38 | - SESSION_TO_DEVICE_ACTOR_MSG, | |
39 | - DEVICE_ACTOR_TO_SESSION_MSG, | |
40 | - | |
41 | - | |
42 | 45 | /** |
43 | 46 | * Message that is sent by RuleChainActor to RuleActor with command to process TbMsg. |
44 | 47 | */ |
... | ... | @@ -59,4 +62,31 @@ public enum MsgType { |
59 | 62 | */ |
60 | 63 | RULE_TO_SELF_MSG, |
61 | 64 | |
65 | + /** | |
66 | + * Message that is sent by Session Actor to Device Actor. Represents messages from the device itself. | |
67 | + */ | |
68 | + DEVICE_SESSION_TO_DEVICE_ACTOR_MSG, | |
69 | + | |
70 | + DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG, | |
71 | + | |
72 | + DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG, | |
73 | + | |
74 | + DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG, | |
75 | + | |
76 | + DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG, | |
77 | + | |
78 | + DEVICE_ACTOR_RPC_TIMEOUT_MSG, | |
79 | + | |
80 | + DEVICE_ACTOR_QUEUE_TIMEOUT_MSG, | |
81 | + | |
82 | + /** | |
83 | + * Message that is sent from the Device Actor to Rule Engine. Requires acknowledgement | |
84 | + */ | |
85 | + DEVICE_ACTOR_TO_RULE_ENGINE_MSG, | |
86 | + | |
87 | + /** | |
88 | + * Message that is sent from Rule Engine to the Device Actor when message is successfully pushed to queue. | |
89 | + */ | |
90 | + RULE_ENGINE_QUEUE_PUT_ACK_MSG; | |
91 | + | |
62 | 92 | } | ... | ... |
... | ... | @@ -31,10 +31,10 @@ import java.util.concurrent.ConcurrentHashMap; |
31 | 31 | @NoArgsConstructor |
32 | 32 | public final class TbMsgMetaData implements Serializable { |
33 | 33 | |
34 | - private Map<String, String> data = new ConcurrentHashMap<>(); | |
34 | + private final Map<String, String> data = new ConcurrentHashMap<>(); | |
35 | 35 | |
36 | 36 | public TbMsgMetaData(Map<String, String> data) { |
37 | - this.data = data; | |
37 | + this.data.putAll(data); | |
38 | 38 | } |
39 | 39 | |
40 | 40 | public String getValue(String key) { | ... | ... |
... | ... | @@ -16,14 +16,20 @@ |
16 | 16 | package org.thingsboard.server.common.msg.cluster; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | +import org.thingsboard.server.common.msg.MsgType; | |
20 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
19 | 21 | |
20 | 22 | /** |
21 | 23 | * @author Andrew Shvayka |
22 | 24 | */ |
23 | 25 | @Data |
24 | -public final class ClusterEventMsg { | |
26 | +public final class ClusterEventMsg implements TbActorMsg { | |
25 | 27 | |
26 | 28 | private final ServerAddress serverAddress; |
27 | 29 | private final boolean added; |
28 | 30 | |
31 | + @Override | |
32 | + public MsgType getMsgType() { | |
33 | + return MsgType.CLUSTER_EVENT_MSG; | |
34 | + } | |
29 | 35 | } | ... | ... |
... | ... | @@ -16,14 +16,14 @@ |
16 | 16 | package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
19 | -import org.thingsboard.server.common.msg.session.MsgType; | |
19 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | 20 | |
21 | 21 | /** |
22 | 22 | * @author Andrew Shvayka |
23 | 23 | */ |
24 | 24 | public class AttributesSubscribeMsg implements FromDeviceMsg { |
25 | 25 | @Override |
26 | - public MsgType getMsgType() { | |
27 | - return MsgType.SUBSCRIBE_ATTRIBUTES_REQUEST; | |
26 | + public SessionMsgType getMsgType() { | |
27 | + return SessionMsgType.SUBSCRIBE_ATTRIBUTES_REQUEST; | |
28 | 28 | } |
29 | 29 | } | ... | ... |
... | ... | @@ -16,14 +16,15 @@ |
16 | 16 | package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
19 | -import org.thingsboard.server.common.msg.session.MsgType; | |
19 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | 21 | |
21 | 22 | /** |
22 | 23 | * @author Andrew Shvayka |
23 | 24 | */ |
24 | 25 | public class AttributesUnsubscribeMsg implements FromDeviceMsg { |
25 | 26 | @Override |
26 | - public MsgType getMsgType() { | |
27 | - return MsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST; | |
27 | + public SessionMsgType getMsgType() { | |
28 | + return SessionMsgType.UNSUBSCRIBE_ATTRIBUTES_REQUEST; | |
28 | 29 | } |
29 | 30 | } | ... | ... |
... | ... | @@ -17,7 +17,8 @@ package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import lombok.ToString; |
19 | 19 | import org.thingsboard.server.common.msg.kv.AttributesKVMsg; |
20 | -import org.thingsboard.server.common.msg.session.MsgType; | |
20 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
21 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
21 | 22 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
22 | 23 | |
23 | 24 | @ToString |
... | ... | @@ -36,9 +37,8 @@ public class AttributesUpdateNotification implements ToDeviceMsg { |
36 | 37 | return true; |
37 | 38 | } |
38 | 39 | |
39 | - @Override | |
40 | - public MsgType getMsgType() { | |
41 | - return MsgType.ATTRIBUTES_UPDATE_NOTIFICATION; | |
40 | + public SessionMsgType getSessionMsgType() { | |
41 | + return SessionMsgType.ATTRIBUTES_UPDATE_NOTIFICATION; | |
42 | 42 | } |
43 | 43 | |
44 | 44 | public AttributesKVMsg getData() { | ... | ... |
common/message/src/main/java/org/thingsboard/server/common/msg/core/AttributesUpdateRequest.java
renamed from
common/message/src/main/java/org/thingsboard/server/common/msg/core/UpdateAttributesRequest.java
... | ... | @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
21 | 21 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
22 | 22 | import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; |
23 | 23 | |
24 | -public interface UpdateAttributesRequest extends FromDeviceRequestMsg { | |
24 | +public interface AttributesUpdateRequest extends FromDeviceRequestMsg { | |
25 | 25 | |
26 | 26 | Set<AttributeKvEntry> getAttributes(); |
27 | 27 | ... | ... |
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicAttributesUpdateRequest.java
renamed from
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicUpdateAttributesRequest.java
... | ... | @@ -20,19 +20,19 @@ import java.util.LinkedHashSet; |
20 | 20 | import java.util.Set; |
21 | 21 | |
22 | 22 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
23 | -import org.thingsboard.server.common.msg.session.MsgType; | |
23 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
24 | 24 | |
25 | -public class BasicUpdateAttributesRequest extends BasicRequest implements UpdateAttributesRequest { | |
25 | +public class BasicAttributesUpdateRequest extends BasicRequest implements AttributesUpdateRequest { | |
26 | 26 | |
27 | 27 | private static final long serialVersionUID = 1L; |
28 | 28 | |
29 | 29 | private final Set<AttributeKvEntry> data; |
30 | 30 | |
31 | - public BasicUpdateAttributesRequest() { | |
31 | + public BasicAttributesUpdateRequest() { | |
32 | 32 | this(DEFAULT_REQUEST_ID); |
33 | 33 | } |
34 | 34 | |
35 | - public BasicUpdateAttributesRequest(Integer requestId) { | |
35 | + public BasicAttributesUpdateRequest(Integer requestId) { | |
36 | 36 | super(requestId); |
37 | 37 | this.data = new LinkedHashSet<>(); |
38 | 38 | } |
... | ... | @@ -46,8 +46,8 @@ public class BasicUpdateAttributesRequest extends BasicRequest implements Update |
46 | 46 | } |
47 | 47 | |
48 | 48 | @Override |
49 | - public MsgType getMsgType() { | |
50 | - return MsgType.POST_ATTRIBUTES_REQUEST; | |
49 | + public SessionMsgType getMsgType() { | |
50 | + return SessionMsgType.POST_ATTRIBUTES_REQUEST; | |
51 | 51 | } |
52 | 52 | |
53 | 53 | @Override |
... | ... | @@ -57,7 +57,7 @@ public class BasicUpdateAttributesRequest extends BasicRequest implements Update |
57 | 57 | |
58 | 58 | @Override |
59 | 59 | public String toString() { |
60 | - return "BasicUpdateAttributesRequest [data=" + data + "]"; | |
60 | + return "BasicAttributesUpdateRequest [data=" + data + "]"; | |
61 | 61 | } |
62 | 62 | |
63 | 63 | } | ... | ... |
... | ... | @@ -15,26 +15,27 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | -import org.thingsboard.server.common.msg.session.MsgType; | |
18 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
19 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
19 | 20 | |
20 | 21 | public class BasicCommandAckResponse extends BasicResponseMsg<Integer> implements StatusCodeResponse { |
21 | 22 | |
22 | 23 | private static final long serialVersionUID = 1L; |
23 | 24 | |
24 | - public static BasicCommandAckResponse onSuccess(MsgType requestMsgType, Integer requestId) { | |
25 | + public static BasicCommandAckResponse onSuccess(SessionMsgType requestMsgType, Integer requestId) { | |
25 | 26 | return BasicCommandAckResponse.onSuccess(requestMsgType, requestId, 200); |
26 | 27 | } |
27 | 28 | |
28 | - public static BasicCommandAckResponse onSuccess(MsgType requestMsgType, Integer requestId, Integer code) { | |
29 | + public static BasicCommandAckResponse onSuccess(SessionMsgType requestMsgType, Integer requestId, Integer code) { | |
29 | 30 | return new BasicCommandAckResponse(requestMsgType, requestId, true, null, code); |
30 | 31 | } |
31 | 32 | |
32 | - public static BasicCommandAckResponse onError(MsgType requestMsgType, Integer requestId, Exception error) { | |
33 | + public static BasicCommandAckResponse onError(SessionMsgType requestMsgType, Integer requestId, Exception error) { | |
33 | 34 | return new BasicCommandAckResponse(requestMsgType, requestId, false, error, null); |
34 | 35 | } |
35 | 36 | |
36 | - private BasicCommandAckResponse(MsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) { | |
37 | - super(requestMsgType, requestId, MsgType.TO_DEVICE_RPC_RESPONSE_ACK, success, error, code); | |
37 | + private BasicCommandAckResponse(SessionMsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) { | |
38 | + super(requestMsgType, requestId, SessionMsgType.TO_DEVICE_RPC_RESPONSE_ACK, success, error, code); | |
38 | 39 | } |
39 | 40 | |
40 | 41 | @Override | ... | ... |
... | ... | @@ -16,7 +16,8 @@ |
16 | 16 | package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import lombok.ToString; |
19 | -import org.thingsboard.server.common.msg.session.MsgType; | |
19 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | 21 | |
21 | 22 | import java.util.Collections; |
22 | 23 | import java.util.Optional; |
... | ... | @@ -41,8 +42,8 @@ public class BasicGetAttributesRequest extends BasicRequest implements GetAttrib |
41 | 42 | } |
42 | 43 | |
43 | 44 | @Override |
44 | - public MsgType getMsgType() { | |
45 | - return MsgType.GET_ATTRIBUTES_REQUEST; | |
45 | + public SessionMsgType getMsgType() { | |
46 | + return SessionMsgType.GET_ATTRIBUTES_REQUEST; | |
46 | 47 | } |
47 | 48 | |
48 | 49 | @Override | ... | ... |
... | ... | @@ -17,23 +17,24 @@ package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import lombok.ToString; |
19 | 19 | import org.thingsboard.server.common.msg.kv.AttributesKVMsg; |
20 | -import org.thingsboard.server.common.msg.session.MsgType; | |
20 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
21 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
21 | 22 | |
22 | 23 | @ToString |
23 | 24 | public class BasicGetAttributesResponse extends BasicResponseMsg<AttributesKVMsg> implements GetAttributesResponse { |
24 | 25 | |
25 | 26 | private static final long serialVersionUID = 1L; |
26 | 27 | |
27 | - public static BasicGetAttributesResponse onSuccess(MsgType requestMsgType, int requestId, AttributesKVMsg code) { | |
28 | + public static BasicGetAttributesResponse onSuccess(SessionMsgType requestMsgType, int requestId, AttributesKVMsg code) { | |
28 | 29 | return new BasicGetAttributesResponse(requestMsgType, requestId, true, null, code); |
29 | 30 | } |
30 | 31 | |
31 | - public static BasicGetAttributesResponse onError(MsgType requestMsgType, int requestId, Exception error) { | |
32 | + public static BasicGetAttributesResponse onError(SessionMsgType requestMsgType, int requestId, Exception error) { | |
32 | 33 | return new BasicGetAttributesResponse(requestMsgType, requestId, false, error, null); |
33 | 34 | } |
34 | 35 | |
35 | - private BasicGetAttributesResponse(MsgType requestMsgType, int requestId, boolean success, Exception error, AttributesKVMsg code) { | |
36 | - super(requestMsgType, requestId, MsgType.GET_ATTRIBUTES_RESPONSE, success, error, code); | |
36 | + private BasicGetAttributesResponse(SessionMsgType requestMsgType, int requestId, boolean success, Exception error, AttributesKVMsg code) { | |
37 | + super(requestMsgType, requestId, SessionMsgType.GET_ATTRIBUTES_RESPONSE, success, error, code); | |
37 | 38 | } |
38 | 39 | |
39 | 40 | } | ... | ... |
... | ... | @@ -18,32 +18,33 @@ package org.thingsboard.server.common.msg.core; |
18 | 18 | import java.io.Serializable; |
19 | 19 | import java.util.Optional; |
20 | 20 | |
21 | -import org.thingsboard.server.common.msg.session.MsgType; | |
21 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
22 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
22 | 23 | |
23 | 24 | |
24 | 25 | public class BasicResponseMsg<T extends Serializable> implements ResponseMsg<T> { |
25 | 26 | |
26 | 27 | private static final long serialVersionUID = 1L; |
27 | 28 | |
28 | - private final MsgType requestMsgType; | |
29 | + private final SessionMsgType requestMsgType; | |
29 | 30 | private final Integer requestId; |
30 | - private final MsgType msgType; | |
31 | + private final SessionMsgType sessionMsgType; | |
31 | 32 | private final boolean success; |
32 | 33 | private final T data; |
33 | 34 | private final Exception error; |
34 | 35 | |
35 | - protected BasicResponseMsg(MsgType requestMsgType, Integer requestId, MsgType msgType, boolean success, Exception error, T data) { | |
36 | + protected BasicResponseMsg(SessionMsgType requestMsgType, Integer requestId, SessionMsgType sessionMsgType, boolean success, Exception error, T data) { | |
36 | 37 | super(); |
37 | 38 | this.requestMsgType = requestMsgType; |
38 | 39 | this.requestId = requestId; |
39 | - this.msgType = msgType; | |
40 | + this.sessionMsgType = sessionMsgType; | |
40 | 41 | this.success = success; |
41 | 42 | this.error = error; |
42 | 43 | this.data = data; |
43 | 44 | } |
44 | 45 | |
45 | 46 | @Override |
46 | - public MsgType getRequestMsgType() { | |
47 | + public SessionMsgType getRequestMsgType() { | |
47 | 48 | return requestMsgType; |
48 | 49 | } |
49 | 50 | |
... | ... | @@ -72,8 +73,7 @@ public class BasicResponseMsg<T extends Serializable> implements ResponseMsg<T> |
72 | 73 | return "BasicResponseMsg [success=" + success + ", data=" + data + ", error=" + error + "]"; |
73 | 74 | } |
74 | 75 | |
75 | - @Override | |
76 | - public MsgType getMsgType() { | |
77 | - return msgType; | |
76 | + public SessionMsgType getSessionMsgType() { | |
77 | + return sessionMsgType; | |
78 | 78 | } |
79 | 79 | } | ... | ... |
... | ... | @@ -16,26 +16,27 @@ |
16 | 16 | package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import lombok.ToString; |
19 | -import org.thingsboard.server.common.msg.session.MsgType; | |
19 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | 21 | |
21 | 22 | @ToString |
22 | 23 | public class BasicStatusCodeResponse extends BasicResponseMsg<Integer> implements StatusCodeResponse { |
23 | 24 | |
24 | 25 | private static final long serialVersionUID = 1L; |
25 | 26 | |
26 | - public static BasicStatusCodeResponse onSuccess(MsgType requestMsgType, Integer requestId) { | |
27 | + public static BasicStatusCodeResponse onSuccess(SessionMsgType requestMsgType, Integer requestId) { | |
27 | 28 | return BasicStatusCodeResponse.onSuccess(requestMsgType, requestId, 0); |
28 | 29 | } |
29 | 30 | |
30 | - public static BasicStatusCodeResponse onSuccess(MsgType requestMsgType, Integer requestId, Integer code) { | |
31 | + public static BasicStatusCodeResponse onSuccess(SessionMsgType requestMsgType, Integer requestId, Integer code) { | |
31 | 32 | return new BasicStatusCodeResponse(requestMsgType, requestId, true, null, code); |
32 | 33 | } |
33 | 34 | |
34 | - public static BasicStatusCodeResponse onError(MsgType requestMsgType, Integer requestId, Exception error) { | |
35 | + public static BasicStatusCodeResponse onError(SessionMsgType requestMsgType, Integer requestId, Exception error) { | |
35 | 36 | return new BasicStatusCodeResponse(requestMsgType, requestId, false, error, null); |
36 | 37 | } |
37 | 38 | |
38 | - private BasicStatusCodeResponse(MsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) { | |
39 | - super(requestMsgType, requestId, MsgType.STATUS_CODE_RESPONSE, success, error, code); | |
39 | + private BasicStatusCodeResponse(SessionMsgType requestMsgType, Integer requestId, boolean success, Exception error, Integer code) { | |
40 | + super(requestMsgType, requestId, SessionMsgType.STATUS_CODE_RESPONSE, success, error, code); | |
40 | 41 | } |
41 | 42 | } | ... | ... |
common/message/src/main/java/org/thingsboard/server/common/msg/core/BasicTelemetryUploadRequest.java
... | ... | @@ -21,7 +21,8 @@ import java.util.List; |
21 | 21 | import java.util.Map; |
22 | 22 | |
23 | 23 | import org.thingsboard.server.common.data.kv.KvEntry; |
24 | -import org.thingsboard.server.common.msg.session.MsgType; | |
24 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
25 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
25 | 26 | |
26 | 27 | public class BasicTelemetryUploadRequest extends BasicRequest implements TelemetryUploadRequest { |
27 | 28 | |
... | ... | @@ -48,8 +49,8 @@ public class BasicTelemetryUploadRequest extends BasicRequest implements Telemet |
48 | 49 | } |
49 | 50 | |
50 | 51 | @Override |
51 | - public MsgType getMsgType() { | |
52 | - return MsgType.POST_TELEMETRY_REQUEST; | |
52 | + public SessionMsgType getMsgType() { | |
53 | + return SessionMsgType.POST_TELEMETRY_REQUEST; | |
53 | 54 | } |
54 | 55 | |
55 | 56 | @Override | ... | ... |
... | ... | @@ -18,12 +18,12 @@ package org.thingsboard.server.common.msg.core; |
18 | 18 | import java.io.Serializable; |
19 | 19 | import java.util.Optional; |
20 | 20 | |
21 | -import org.thingsboard.server.common.msg.session.MsgType; | |
21 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
22 | 22 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
23 | 23 | |
24 | 24 | public interface ResponseMsg<T extends Serializable> extends ToDeviceMsg { |
25 | 25 | |
26 | - MsgType getRequestMsgType(); | |
26 | + SessionMsgType getRequestMsgType(); | |
27 | 27 | |
28 | 28 | Integer getRequestId(); |
29 | 29 | ... | ... |
... | ... | @@ -16,14 +16,15 @@ |
16 | 16 | package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
19 | -import org.thingsboard.server.common.msg.session.MsgType; | |
19 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | 21 | |
21 | 22 | /** |
22 | 23 | * @author Andrew Shvayka |
23 | 24 | */ |
24 | 25 | public class RpcSubscribeMsg implements FromDeviceMsg { |
25 | 26 | @Override |
26 | - public MsgType getMsgType() { | |
27 | - return MsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST; | |
27 | + public SessionMsgType getMsgType() { | |
28 | + return SessionMsgType.SUBSCRIBE_RPC_COMMANDS_REQUEST; | |
28 | 29 | } |
29 | 30 | } | ... | ... |
... | ... | @@ -16,14 +16,15 @@ |
16 | 16 | package org.thingsboard.server.common.msg.core; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
19 | -import org.thingsboard.server.common.msg.session.MsgType; | |
19 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
20 | 21 | |
21 | 22 | /** |
22 | 23 | * @author Andrew Shvayka |
23 | 24 | */ |
24 | 25 | public class RpcUnsubscribeMsg implements FromDeviceMsg { |
25 | 26 | @Override |
26 | - public MsgType getMsgType() { | |
27 | - return MsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST; | |
27 | + public SessionMsgType getMsgType() { | |
28 | + return SessionMsgType.UNSUBSCRIBE_RPC_COMMANDS_REQUEST; | |
28 | 29 | } |
29 | 30 | } | ... | ... |
... | ... | @@ -21,7 +21,7 @@ package org.thingsboard.server.common.msg.core; |
21 | 21 | |
22 | 22 | public enum RuleEngineError { |
23 | 23 | |
24 | - NO_RULES, NO_ACTIVE_RULES, NO_FILTERS_MATCHED, NO_REQUEST_FROM_ACTIONS, NO_TWO_WAY_ACTIONS, NO_RESPONSE_FROM_ACTIONS, PLUGIN_TIMEOUT(true); | |
24 | + QUEUE_PUT_TIMEOUT(true), SERVER_ERROR(true); | |
25 | 25 | |
26 | 26 | private final boolean critical; |
27 | 27 | ... | ... |