Commit 1f39d20ab77ad9ed178f11dc68424879f9732e89
Committed by
GitHub
Merge pull request #296 from thingsboard/feature/rpc-rule
RPC rule feature
Showing
14 changed files
with
414 additions
and
6 deletions
@@ -44,6 +44,7 @@ import org.thingsboard.server.dao.customer.CustomerService; | @@ -44,6 +44,7 @@ import org.thingsboard.server.dao.customer.CustomerService; | ||
44 | import org.thingsboard.server.dao.device.DeviceService; | 44 | import org.thingsboard.server.dao.device.DeviceService; |
45 | import org.thingsboard.server.dao.event.EventService; | 45 | import org.thingsboard.server.dao.event.EventService; |
46 | import org.thingsboard.server.dao.plugin.PluginService; | 46 | import org.thingsboard.server.dao.plugin.PluginService; |
47 | +import org.thingsboard.server.dao.relation.RelationService; | ||
47 | import org.thingsboard.server.dao.rule.RuleService; | 48 | import org.thingsboard.server.dao.rule.RuleService; |
48 | import org.thingsboard.server.dao.tenant.TenantService; | 49 | import org.thingsboard.server.dao.tenant.TenantService; |
49 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 50 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
@@ -110,6 +111,9 @@ public class ActorSystemContext { | @@ -110,6 +111,9 @@ public class ActorSystemContext { | ||
110 | @Getter private AlarmService alarmService; | 111 | @Getter private AlarmService alarmService; |
111 | 112 | ||
112 | @Autowired | 113 | @Autowired |
114 | + @Getter private RelationService relationService; | ||
115 | + | ||
116 | + @Autowired | ||
113 | @Getter @Setter private PluginWebSocketMsgEndpoint wsMsgEndpoint; | 117 | @Getter @Setter private PluginWebSocketMsgEndpoint wsMsgEndpoint; |
114 | 118 | ||
115 | @Value("${actors.session.sync.timeout}") | 119 | @Value("${actors.session.sync.timeout}") |
@@ -33,6 +33,8 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; | @@ -33,6 +33,8 @@ import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
33 | import org.thingsboard.server.common.data.kv.TsKvQuery; | 33 | import org.thingsboard.server.common.data.kv.TsKvQuery; |
34 | import org.thingsboard.server.common.data.page.TextPageLink; | 34 | import org.thingsboard.server.common.data.page.TextPageLink; |
35 | import org.thingsboard.server.common.data.plugin.PluginMetaData; | 35 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
36 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
37 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
36 | import org.thingsboard.server.common.data.rule.RuleMetaData; | 38 | import org.thingsboard.server.common.data.rule.RuleMetaData; |
37 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 39 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
38 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; | 40 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
@@ -395,6 +397,16 @@ public final class PluginProcessingContext implements PluginContext { | @@ -395,6 +397,16 @@ public final class PluginProcessingContext implements PluginContext { | ||
395 | } | 397 | } |
396 | 398 | ||
397 | @Override | 399 | @Override |
400 | + public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType) { | ||
401 | + return this.pluginCtx.relationService.findByFromAndType(from, relationType, RelationTypeGroup.COMMON); | ||
402 | + } | ||
403 | + | ||
404 | + @Override | ||
405 | + public ListenableFuture<List<EntityRelation>> findByToAndType(EntityId from, String relationType) { | ||
406 | + return this.pluginCtx.relationService.findByToAndType(from, relationType, RelationTypeGroup.COMMON); | ||
407 | + } | ||
408 | + | ||
409 | + @Override | ||
398 | public Optional<ServerAddress> resolve(EntityId entityId) { | 410 | public Optional<ServerAddress> resolve(EntityId entityId) { |
399 | return pluginCtx.routingService.resolveById(entityId); | 411 | return pluginCtx.routingService.resolveById(entityId); |
400 | } | 412 | } |
@@ -30,6 +30,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; | @@ -30,6 +30,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; | ||
30 | import org.thingsboard.server.dao.customer.CustomerService; | 30 | import org.thingsboard.server.dao.customer.CustomerService; |
31 | import org.thingsboard.server.dao.device.DeviceService; | 31 | import org.thingsboard.server.dao.device.DeviceService; |
32 | import org.thingsboard.server.dao.plugin.PluginService; | 32 | import org.thingsboard.server.dao.plugin.PluginService; |
33 | +import org.thingsboard.server.dao.relation.RelationService; | ||
33 | import org.thingsboard.server.dao.rule.RuleService; | 34 | import org.thingsboard.server.dao.rule.RuleService; |
34 | import org.thingsboard.server.dao.tenant.TenantService; | 35 | import org.thingsboard.server.dao.tenant.TenantService; |
35 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 36 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
@@ -61,6 +62,7 @@ public final class SharedPluginProcessingContext { | @@ -61,6 +62,7 @@ public final class SharedPluginProcessingContext { | ||
61 | final AttributesService attributesService; | 62 | final AttributesService attributesService; |
62 | final ClusterRpcService rpcService; | 63 | final ClusterRpcService rpcService; |
63 | final ClusterRoutingService routingService; | 64 | final ClusterRoutingService routingService; |
65 | + final RelationService relationService; | ||
64 | final PluginId pluginId; | 66 | final PluginId pluginId; |
65 | final TenantId tenantId; | 67 | final TenantId tenantId; |
66 | 68 | ||
@@ -83,6 +85,7 @@ public final class SharedPluginProcessingContext { | @@ -83,6 +85,7 @@ public final class SharedPluginProcessingContext { | ||
83 | this.pluginService = sysContext.getPluginService(); | 85 | this.pluginService = sysContext.getPluginService(); |
84 | this.customerService = sysContext.getCustomerService(); | 86 | this.customerService = sysContext.getCustomerService(); |
85 | this.tenantService = sysContext.getTenantService(); | 87 | this.tenantService = sysContext.getTenantService(); |
88 | + this.relationService = sysContext.getRelationService(); | ||
86 | } | 89 | } |
87 | 90 | ||
88 | public PluginId getPluginId() { | 91 | public PluginId getPluginId() { |
@@ -7,13 +7,13 @@ | @@ -7,13 +7,13 @@ | ||
7 | </encoder> | 7 | </encoder> |
8 | </appender> | 8 | </appender> |
9 | 9 | ||
10 | - <logger name="org.thingsboard.server" level="INFO"/> | 10 | + <logger name="org.thingsboard.server" level="WARN"/> |
11 | <logger name="org.springframework" level="WARN"/> | 11 | <logger name="org.springframework" level="WARN"/> |
12 | <logger name="org.springframework.boot.test" level="DEBUG"/> | 12 | <logger name="org.springframework.boot.test" level="DEBUG"/> |
13 | <logger name="org.apache.cassandra" level="WARN"/> | 13 | <logger name="org.apache.cassandra" level="WARN"/> |
14 | <logger name="org.cassandraunit" level="INFO"/> | 14 | <logger name="org.cassandraunit" level="INFO"/> |
15 | 15 | ||
16 | - <logger name="akka" level="DEBUG" /> | 16 | + <logger name="akka" level="INFO" /> |
17 | 17 | ||
18 | <root level="WARN"> | 18 | <root level="WARN"> |
19 | <appender-ref ref="console"/> | 19 | <appender-ref ref="console"/> |
@@ -9,8 +9,8 @@ | @@ -9,8 +9,8 @@ | ||
9 | 9 | ||
10 | <logger name="org.thingsboard.server.dao" level="WARN"/> | 10 | <logger name="org.thingsboard.server.dao" level="WARN"/> |
11 | <logger name="org.apache.cassandra" level="WARN"/> | 11 | <logger name="org.apache.cassandra" level="WARN"/> |
12 | - <logger name="org.cassandraunit" level="INFO" /> | ||
13 | - <logger name="org.apache.cassandra" level="INFO" /> | 12 | + <logger name="org.cassandraunit" level="WARN" /> |
13 | + <logger name="org.apache.cassandra" level="WARN" /> | ||
14 | 14 | ||
15 | <root level="WARN"> | 15 | <root level="WARN"> |
16 | <appender-ref ref="console"/> | 16 | <appender-ref ref="console"/> |
@@ -15,11 +15,14 @@ | @@ -15,11 +15,14 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.extensions.api.plugins; | 16 | package org.thingsboard.server.extensions.api.plugins; |
17 | 17 | ||
18 | +import com.google.common.util.concurrent.ListenableFuture; | ||
18 | import org.thingsboard.server.common.data.Device; | 19 | import org.thingsboard.server.common.data.Device; |
19 | import org.thingsboard.server.common.data.id.*; | 20 | import org.thingsboard.server.common.data.id.*; |
20 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 21 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
21 | import org.thingsboard.server.common.data.kv.TsKvEntry; | 22 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
22 | import org.thingsboard.server.common.data.kv.TsKvQuery; | 23 | import org.thingsboard.server.common.data.kv.TsKvQuery; |
24 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
25 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
23 | import org.thingsboard.server.common.msg.cluster.ServerAddress; | 26 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
24 | import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; | 27 | import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; |
25 | import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | 28 | import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; |
@@ -109,4 +112,12 @@ public interface PluginContext { | @@ -109,4 +112,12 @@ public interface PluginContext { | ||
109 | 112 | ||
110 | void getCustomerDevices(TenantId tenantId, CustomerId customerId, int limit, PluginCallback<List<Device>> callback); | 113 | void getCustomerDevices(TenantId tenantId, CustomerId customerId, int limit, PluginCallback<List<Device>> callback); |
111 | 114 | ||
115 | + | ||
116 | + /* | ||
117 | + * Relations API | ||
118 | + * */ | ||
119 | + | ||
120 | + ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType); | ||
121 | + | ||
122 | + ListenableFuture<List<EntityRelation>> findByToAndType(EntityId from, String relationType); | ||
112 | } | 123 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2017 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.extensions.core.action.rpc; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.apache.velocity.Template; | ||
20 | +import org.apache.velocity.VelocityContext; | ||
21 | +import org.apache.velocity.runtime.parser.ParseException; | ||
22 | +import org.springframework.util.StringUtils; | ||
23 | +import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | ||
24 | +import org.thingsboard.server.common.msg.session.ToDeviceMsg; | ||
25 | +import org.thingsboard.server.extensions.api.component.Action; | ||
26 | +import org.thingsboard.server.extensions.api.plugins.PluginAction; | ||
27 | +import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; | ||
28 | +import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; | ||
29 | +import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; | ||
30 | +import org.thingsboard.server.extensions.api.rules.RuleContext; | ||
31 | +import org.thingsboard.server.extensions.api.rules.RuleProcessingMetaData; | ||
32 | +import org.thingsboard.server.extensions.api.rules.SimpleRuleLifecycleComponent; | ||
33 | +import org.thingsboard.server.extensions.core.utils.VelocityUtils; | ||
34 | + | ||
35 | +import java.util.Optional; | ||
36 | + | ||
37 | +/** | ||
38 | + * Created by ashvayka on 14.09.17. | ||
39 | + */ | ||
40 | +@Action(name = "Server Side RPC Call Action", descriptor = "ServerSideRpcCallActionDescriptor.json", configuration = ServerSideRpcCallActionConfiguration.class) | ||
41 | +@Slf4j | ||
42 | +public class ServerSideRpcCallAction extends SimpleRuleLifecycleComponent implements PluginAction<ServerSideRpcCallActionConfiguration> { | ||
43 | + | ||
44 | + private ServerSideRpcCallActionConfiguration configuration; | ||
45 | + private Optional<Template> deviceIdTemplate; | ||
46 | + private Optional<Template> fromDeviceRelationTemplate; | ||
47 | + private Optional<Template> toDeviceRelationTemplate; | ||
48 | + private Optional<Template> rpcCallMethodTemplate; | ||
49 | + private Optional<Template> rpcCallBodyTemplate; | ||
50 | + | ||
51 | + @Override | ||
52 | + public void init(ServerSideRpcCallActionConfiguration configuration) { | ||
53 | + this.configuration = configuration; | ||
54 | + try { | ||
55 | + deviceIdTemplate = toTemplate(configuration.getDeviceIdTemplate(), "Device Id Template"); | ||
56 | + fromDeviceRelationTemplate = toTemplate(configuration.getFromDeviceRelationTemplate(), "From Device Relation Template"); | ||
57 | + toDeviceRelationTemplate = toTemplate(configuration.getToDeviceRelationTemplate(), "To Device Relation Template"); | ||
58 | + rpcCallMethodTemplate = toTemplate(configuration.getRpcCallMethodTemplate(), "RPC Call Method Template"); | ||
59 | + rpcCallBodyTemplate = toTemplate(configuration.getRpcCallBodyTemplate(), "RPC Call Body Template"); | ||
60 | + } catch (ParseException e) { | ||
61 | + log.error("Failed to create templates based on provided configuration!", e); | ||
62 | + throw new RuntimeException("Failed to create templates based on provided configuration!", e); | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
66 | + @Override | ||
67 | + public Optional<RuleToPluginMsg<?>> convert(RuleContext ctx, ToDeviceActorMsg toDeviceActorMsg, RuleProcessingMetaData metadata) { | ||
68 | + String sendFlag = configuration.getSendFlag(); | ||
69 | + if (StringUtils.isEmpty(sendFlag) || (Boolean) metadata.get(sendFlag).orElse(Boolean.FALSE)) { | ||
70 | + VelocityContext context = VelocityUtils.createContext(metadata); | ||
71 | + | ||
72 | + ServerSideRpcCallActionMsg.ServerSideRpcCallActionMsgBuilder builder = ServerSideRpcCallActionMsg.builder(); | ||
73 | + | ||
74 | + deviceIdTemplate.ifPresent(t -> builder.deviceId(VelocityUtils.merge(t, context))); | ||
75 | + fromDeviceRelationTemplate.ifPresent(t -> builder.fromDeviceRelation(VelocityUtils.merge(t, context))); | ||
76 | + toDeviceRelationTemplate.ifPresent(t -> builder.toDeviceRelation(VelocityUtils.merge(t, context))); | ||
77 | + rpcCallMethodTemplate.ifPresent(t -> builder.rpcCallMethod(VelocityUtils.merge(t, context))); | ||
78 | + rpcCallBodyTemplate.ifPresent(t -> builder.rpcCallBody(VelocityUtils.merge(t, context))); | ||
79 | + return Optional.of(new ServerSideRpcCallRuleToPluginActionMsg(toDeviceActorMsg.getTenantId(), toDeviceActorMsg.getCustomerId(), toDeviceActorMsg.getDeviceId(), | ||
80 | + builder.build())); | ||
81 | + } else { | ||
82 | + return Optional.empty(); | ||
83 | + } | ||
84 | + } | ||
85 | + | ||
86 | + private Optional<Template> toTemplate(String source, String name) throws ParseException { | ||
87 | + if (!StringUtils.isEmpty(source)) { | ||
88 | + return Optional.of(VelocityUtils.create(source, name)); | ||
89 | + } else { | ||
90 | + return Optional.empty(); | ||
91 | + } | ||
92 | + } | ||
93 | + | ||
94 | + @Override | ||
95 | + public Optional<ToDeviceMsg> convert(PluginToRuleMsg<?> response) { | ||
96 | + if (response instanceof ResponsePluginToRuleMsg) { | ||
97 | + return Optional.of(((ResponsePluginToRuleMsg) response).getPayload()); | ||
98 | + } | ||
99 | + return Optional.empty(); | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public boolean isOneWayAction() { | ||
104 | + return true; | ||
105 | + } | ||
106 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2017 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.extensions.core.action.rpc; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +/** | ||
21 | + * @author Andrew Shvayka | ||
22 | + */ | ||
23 | +@Data | ||
24 | +public class ServerSideRpcCallActionConfiguration { | ||
25 | + | ||
26 | + private String sendFlag; | ||
27 | + | ||
28 | + private String deviceIdTemplate; | ||
29 | + private String rpcCallMethodTemplate; | ||
30 | + private String rpcCallBodyTemplate; | ||
31 | + private long rpcCallTimeoutInSec; | ||
32 | + private String fromDeviceRelationTemplate; | ||
33 | + private String toDeviceRelationTemplate; | ||
34 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2017 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.extensions.core.action.rpc; | ||
17 | + | ||
18 | +import lombok.Builder; | ||
19 | +import lombok.Data; | ||
20 | + | ||
21 | +import java.io.Serializable; | ||
22 | + | ||
23 | +/** | ||
24 | + * Created by ashvayka on 14.09.17. | ||
25 | + */ | ||
26 | +@Data | ||
27 | +@Builder | ||
28 | +public class ServerSideRpcCallActionMsg implements Serializable { | ||
29 | + | ||
30 | + private String deviceId; | ||
31 | + private String rpcCallMethod; | ||
32 | + private String rpcCallBody; | ||
33 | + private long rpcCallTimeoutInSec; | ||
34 | + | ||
35 | + private String fromDeviceRelation; | ||
36 | + private String toDeviceRelation; | ||
37 | + | ||
38 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2017 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.extensions.core.action.rpc; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
19 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
20 | +import org.thingsboard.server.common.data.id.TenantId; | ||
21 | +import org.thingsboard.server.extensions.api.plugins.msg.AbstractRuleToPluginMsg; | ||
22 | + | ||
23 | +/** | ||
24 | + * Created by ashvayka on 14.09.17. | ||
25 | + */ | ||
26 | +public class ServerSideRpcCallRuleToPluginActionMsg extends AbstractRuleToPluginMsg<ServerSideRpcCallActionMsg> { | ||
27 | + | ||
28 | + public ServerSideRpcCallRuleToPluginActionMsg(TenantId tenantId, CustomerId customerId, DeviceId deviceId, | ||
29 | + ServerSideRpcCallActionMsg payload) { | ||
30 | + super(tenantId, customerId, deviceId, payload); | ||
31 | + } | ||
32 | +} |
@@ -19,15 +19,19 @@ import lombok.extern.slf4j.Slf4j; | @@ -19,15 +19,19 @@ import lombok.extern.slf4j.Slf4j; | ||
19 | import org.thingsboard.server.extensions.api.component.Plugin; | 19 | import org.thingsboard.server.extensions.api.component.Plugin; |
20 | import org.thingsboard.server.extensions.api.plugins.AbstractPlugin; | 20 | import org.thingsboard.server.extensions.api.plugins.AbstractPlugin; |
21 | import org.thingsboard.server.extensions.api.plugins.PluginContext; | 21 | import org.thingsboard.server.extensions.api.plugins.PluginContext; |
22 | +import org.thingsboard.server.extensions.api.plugins.handlers.DefaultRuleMsgHandler; | ||
22 | import org.thingsboard.server.extensions.api.plugins.handlers.RestMsgHandler; | 23 | import org.thingsboard.server.extensions.api.plugins.handlers.RestMsgHandler; |
24 | +import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; | ||
23 | import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; | 25 | import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; |
24 | import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | 26 | import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; |
27 | +import org.thingsboard.server.extensions.core.action.rpc.ServerSideRpcCallAction; | ||
25 | import org.thingsboard.server.extensions.core.plugin.rpc.handlers.RpcRestMsgHandler; | 28 | import org.thingsboard.server.extensions.core.plugin.rpc.handlers.RpcRestMsgHandler; |
29 | +import org.thingsboard.server.extensions.core.plugin.rpc.handlers.RpcRuleMsgHandler; | ||
26 | 30 | ||
27 | /** | 31 | /** |
28 | * @author Andrew Shvayka | 32 | * @author Andrew Shvayka |
29 | */ | 33 | */ |
30 | -@Plugin(name = "RPC Plugin", actions = {}, descriptor = "RpcPluginDescriptor.json", configuration = RpcPluginConfiguration.class) | 34 | +@Plugin(name = "RPC Plugin", actions = {ServerSideRpcCallAction.class}, descriptor = "RpcPluginDescriptor.json", configuration = RpcPluginConfiguration.class) |
31 | @Slf4j | 35 | @Slf4j |
32 | public class RpcPlugin extends AbstractPlugin<RpcPluginConfiguration> { | 36 | public class RpcPlugin extends AbstractPlugin<RpcPluginConfiguration> { |
33 | 37 | ||
@@ -61,6 +65,11 @@ public class RpcPlugin extends AbstractPlugin<RpcPluginConfiguration> { | @@ -61,6 +65,11 @@ public class RpcPlugin extends AbstractPlugin<RpcPluginConfiguration> { | ||
61 | } | 65 | } |
62 | 66 | ||
63 | @Override | 67 | @Override |
68 | + protected RuleMsgHandler getRuleMsgHandler() { | ||
69 | + return new RpcRuleMsgHandler(); | ||
70 | + } | ||
71 | + | ||
72 | + @Override | ||
64 | public void resume(PluginContext ctx) { | 73 | public void resume(PluginContext ctx) { |
65 | 74 | ||
66 | } | 75 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2017 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.extensions.core.plugin.rpc.handlers; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.springframework.util.StringUtils; | ||
20 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
21 | +import org.thingsboard.server.common.data.id.EntityId; | ||
22 | +import org.thingsboard.server.common.data.id.RuleId; | ||
23 | +import org.thingsboard.server.common.data.id.TenantId; | ||
24 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
25 | +import org.thingsboard.server.extensions.api.plugins.PluginCallback; | ||
26 | +import org.thingsboard.server.extensions.api.plugins.PluginContext; | ||
27 | +import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; | ||
28 | +import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; | ||
29 | +import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest; | ||
30 | +import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestBody; | ||
31 | +import org.thingsboard.server.extensions.api.rules.RuleException; | ||
32 | +import org.thingsboard.server.extensions.core.action.rpc.ServerSideRpcCallActionMsg; | ||
33 | +import org.thingsboard.server.extensions.core.action.rpc.ServerSideRpcCallRuleToPluginActionMsg; | ||
34 | + | ||
35 | +import java.util.Collections; | ||
36 | +import java.util.List; | ||
37 | +import java.util.UUID; | ||
38 | +import java.util.concurrent.TimeUnit; | ||
39 | +import java.util.stream.Collectors; | ||
40 | + | ||
41 | +/** | ||
42 | + * Created by ashvayka on 14.09.17. | ||
43 | + */ | ||
44 | +@Slf4j | ||
45 | +public class RpcRuleMsgHandler implements RuleMsgHandler { | ||
46 | + | ||
47 | + @Override | ||
48 | + public void process(PluginContext ctx, TenantId tenantId, RuleId ruleId, RuleToPluginMsg<?> msg) throws RuleException { | ||
49 | + if (msg instanceof ServerSideRpcCallRuleToPluginActionMsg) { | ||
50 | + handle(ctx, tenantId, ruleId, ((ServerSideRpcCallRuleToPluginActionMsg) msg).getPayload()); | ||
51 | + } else { | ||
52 | + throw new RuntimeException("Not supported msg: " + msg + "!"); | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + private void handle(final PluginContext ctx, TenantId tenantId, RuleId ruleId, ServerSideRpcCallActionMsg msg) { | ||
57 | + DeviceId deviceId = new DeviceId(UUID.fromString(msg.getDeviceId())); | ||
58 | + ctx.checkAccess(deviceId, new PluginCallback<Void>() { | ||
59 | + @Override | ||
60 | + public void onSuccess(PluginContext dummy, Void value) { | ||
61 | + try { | ||
62 | + List<EntityId> deviceIds; | ||
63 | + if (StringUtils.isEmpty(msg.getFromDeviceRelation()) && StringUtils.isEmpty(msg.getToDeviceRelation())) { | ||
64 | + deviceIds = Collections.singletonList(deviceId); | ||
65 | + } else if (!StringUtils.isEmpty(msg.getFromDeviceRelation())) { | ||
66 | + List<EntityRelation> relations = ctx.findByFromAndType(deviceId, msg.getFromDeviceRelation()).get(); | ||
67 | + deviceIds = relations.stream().map(EntityRelation::getTo).collect(Collectors.toList()); | ||
68 | + } else { | ||
69 | + List<EntityRelation> relations = ctx.findByToAndType(deviceId, msg.getFromDeviceRelation()).get(); | ||
70 | + deviceIds = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toList()); | ||
71 | + } | ||
72 | + ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(msg.getRpcCallMethod(), msg.getRpcCallBody()); | ||
73 | + long expirationTime = System.currentTimeMillis() + msg.getRpcCallTimeoutInSec(); | ||
74 | + for (EntityId address : deviceIds) { | ||
75 | + DeviceId tmpId = new DeviceId(address.getId()); | ||
76 | + ctx.checkAccess(tmpId, new PluginCallback<Void>() { | ||
77 | + @Override | ||
78 | + public void onSuccess(PluginContext ctx, Void value) { | ||
79 | + ctx.sendRpcRequest(new ToDeviceRpcRequest(UUID.randomUUID(), | ||
80 | + tenantId, tmpId, true, expirationTime, body) | ||
81 | + ); | ||
82 | + log.trace("[{}] Sent RPC Call Action msg", tmpId); | ||
83 | + } | ||
84 | + | ||
85 | + @Override | ||
86 | + public void onFailure(PluginContext ctx, Exception e) { | ||
87 | + log.info("[{}] Failed to process RPC Call Action msg", tmpId, e); | ||
88 | + } | ||
89 | + }); | ||
90 | + } | ||
91 | + } catch (Exception e) { | ||
92 | + log.info("Failed to process RPC Call Action msg", e); | ||
93 | + } | ||
94 | + } | ||
95 | + | ||
96 | + @Override | ||
97 | + public void onFailure(PluginContext dummy, Exception e) { | ||
98 | + log.info("[{}] Failed to process RPC Call Action msg", deviceId, e); | ||
99 | + } | ||
100 | + }); | ||
101 | + } | ||
102 | +} |
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | "type": "object", | 4 | "type": "object", |
5 | "properties": { | 5 | "properties": { |
6 | "sendFlag": { | 6 | "sendFlag": { |
7 | - "title": "Send flag", | 7 | + "title": "Send flag (empty or 'isNewAlarm', 'isExistingAlarm', 'isClearedAlarm', 'isNewOrClearedAlarm')", |
8 | "type": "string" | 8 | "type": "string" |
9 | }, | 9 | }, |
10 | "fromTemplate": { | 10 | "fromTemplate": { |
1 | +{ | ||
2 | + "schema": { | ||
3 | + "title": "Send Mail Action Configuration", | ||
4 | + "type": "object", | ||
5 | + "properties": { | ||
6 | + "sendFlag": { | ||
7 | + "title": "Send flag (empty or 'isNewAlarm', 'isExistingAlarm', 'isClearedAlarm', 'isNewOrClearedAlarm')", | ||
8 | + "type": "string" | ||
9 | + }, | ||
10 | + "deviceIdTemplate": { | ||
11 | + "title": "Device ID template", | ||
12 | + "type": "string", | ||
13 | + "default": "$deviceId" | ||
14 | + }, | ||
15 | + "rpcCallMethodTemplate": { | ||
16 | + "title": "RPC Call template", | ||
17 | + "type": "string" | ||
18 | + }, | ||
19 | + "rpcCallBodyTemplate": { | ||
20 | + "title": "RPC Call Body template", | ||
21 | + "type": "string" | ||
22 | + }, | ||
23 | + "rpcCallTimeoutInSec": { | ||
24 | + "title": "RPC Call timeout in seconds", | ||
25 | + "type": "integer", | ||
26 | + "default": 60 | ||
27 | + }, | ||
28 | + "fromDeviceRelationTemplate": { | ||
29 | + "title": "From Device Relation template", | ||
30 | + "type": "string" | ||
31 | + }, | ||
32 | + "toDeviceRelationTemplate": { | ||
33 | + "title": "To Device Relation template", | ||
34 | + "type": "string" | ||
35 | + } | ||
36 | + }, | ||
37 | + "required": [ | ||
38 | + "deviceIdTemplate", | ||
39 | + "rpcCallMethodTemplate", | ||
40 | + "rpcCallBodyTemplate", | ||
41 | + "rpcCallTimeoutInSec" | ||
42 | + ] | ||
43 | + }, | ||
44 | + "form": [ | ||
45 | + "sendFlag", | ||
46 | + "deviceIdTemplate", | ||
47 | + "rpcCallMethodTemplate", | ||
48 | + { | ||
49 | + "key": "rpcCallBodyTemplate", | ||
50 | + "type": "textarea", | ||
51 | + "rows": 5 | ||
52 | + }, | ||
53 | + "rpcCallTimeoutInSec", | ||
54 | + "fromDeviceRelationTemplate", | ||
55 | + "toDeviceRelationTemplate" | ||
56 | + ] | ||
57 | +} |