Commit 72682dbfb889785589ec8f8c75f025e6ad0d2789
Merge branch 'develop/1.5' of github.com:thingsboard/thingsboard into develop/1.5
Showing
67 changed files
with
1968 additions
and
1276 deletions
Too many changes to show.
To preserve performance only 67 of 336 files are displayed.
... | ... | @@ -54,6 +54,14 @@ |
54 | 54 | <artifactId>extensions-api</artifactId> |
55 | 55 | </dependency> |
56 | 56 | <dependency> |
57 | + <groupId>org.thingsboard.rule-engine</groupId> | |
58 | + <artifactId>rule-engine-api</artifactId> | |
59 | + </dependency> | |
60 | + <dependency> | |
61 | + <groupId>org.thingsboard.rule-engine</groupId> | |
62 | + <artifactId>rule-engine-components</artifactId> | |
63 | + </dependency> | |
64 | + <dependency> | |
57 | 65 | <groupId>org.thingsboard</groupId> |
58 | 66 | <artifactId>extensions-core</artifactId> |
59 | 67 | </dependency> | ... | ... |
... | ... | @@ -69,6 +69,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_chain ( |
69 | 69 | search_text text, |
70 | 70 | first_rule_node_id uuid, |
71 | 71 | root boolean, |
72 | + debug_mode boolean, | |
72 | 73 | configuration text, |
73 | 74 | additional_info text, |
74 | 75 | PRIMARY KEY (id, tenant_id) |
... | ... | @@ -85,9 +86,12 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_node ( |
85 | 86 | id uuid, |
86 | 87 | type text, |
87 | 88 | name text, |
89 | + debug_mode boolean, | |
88 | 90 | search_text text, |
89 | 91 | configuration text, |
90 | 92 | additional_info text, |
91 | 93 | PRIMARY KEY (id) |
92 | 94 | ); |
93 | 95 | |
96 | +ALTER TABLE thingsboard.device ADD last_connect bigint; | |
97 | +ALTER TABLE thingsboard.device ADD last_update bigint; | |
\ No newline at end of file | ... | ... |
... | ... | @@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS rule_chain ( |
21 | 21 | name varchar(255), |
22 | 22 | first_rule_node_id varchar(31), |
23 | 23 | root boolean, |
24 | + debug_mode boolean, | |
24 | 25 | search_text varchar(255), |
25 | 26 | tenant_id varchar(31) |
26 | 27 | ); |
... | ... | @@ -31,5 +32,9 @@ CREATE TABLE IF NOT EXISTS rule_node ( |
31 | 32 | configuration varchar(10000000), |
32 | 33 | type varchar(255), |
33 | 34 | name varchar(255), |
35 | + debug_mode boolean, | |
34 | 36 | search_text varchar(255) |
35 | -); | |
\ No newline at end of file | ||
37 | +); | |
38 | + | |
39 | +ALTER TABLE device ADD COLUMN IF NOT EXISTS last_connect BIGINT; | |
40 | +ALTER TABLE device ADD COLUMN IF NOT EXISTS last_update BIGINT; | |
\ No newline at end of file | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import org.springframework.boot.SpringApplication; |
19 | 19 | import org.springframework.boot.SpringBootConfiguration; |
20 | 20 | import org.springframework.context.annotation.ComponentScan; |
21 | 21 | import org.springframework.scheduling.annotation.EnableAsync; |
22 | +import org.springframework.scheduling.annotation.EnableScheduling; | |
22 | 23 | import springfox.documentation.swagger2.annotations.EnableSwagger2; |
23 | 24 | |
24 | 25 | import java.util.Arrays; |
... | ... | @@ -26,6 +27,7 @@ import java.util.Arrays; |
26 | 27 | @SpringBootConfiguration |
27 | 28 | @EnableAsync |
28 | 29 | @EnableSwagger2 |
30 | +@EnableScheduling | |
29 | 31 | @ComponentScan({"org.thingsboard.server"}) |
30 | 32 | public class ThingsboardServerApplication { |
31 | 33 | ... | ... |
... | ... | @@ -25,15 +25,19 @@ import com.typesafe.config.Config; |
25 | 25 | import com.typesafe.config.ConfigFactory; |
26 | 26 | import lombok.Getter; |
27 | 27 | import lombok.Setter; |
28 | +import lombok.extern.slf4j.Slf4j; | |
28 | 29 | import org.springframework.beans.factory.annotation.Autowired; |
29 | 30 | import org.springframework.beans.factory.annotation.Value; |
30 | 31 | import org.springframework.stereotype.Component; |
32 | +import org.thingsboard.rule.engine.api.ListeningExecutor; | |
33 | +import org.thingsboard.rule.engine.api.MailService; | |
31 | 34 | import org.thingsboard.server.actors.service.ActorService; |
32 | 35 | import org.thingsboard.server.common.data.DataConstants; |
33 | 36 | import org.thingsboard.server.common.data.Event; |
34 | 37 | import org.thingsboard.server.common.data.id.EntityId; |
35 | 38 | import org.thingsboard.server.common.data.id.TenantId; |
36 | 39 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
40 | +import org.thingsboard.server.common.msg.TbMsg; | |
37 | 41 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
38 | 42 | import org.thingsboard.server.common.transport.auth.DeviceAuthService; |
39 | 43 | import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; |
... | ... | @@ -46,116 +50,200 @@ import org.thingsboard.server.dao.device.DeviceService; |
46 | 50 | import org.thingsboard.server.dao.event.EventService; |
47 | 51 | import org.thingsboard.server.dao.plugin.PluginService; |
48 | 52 | import org.thingsboard.server.dao.relation.RelationService; |
53 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
49 | 54 | import org.thingsboard.server.dao.rule.RuleService; |
50 | 55 | import org.thingsboard.server.dao.tenant.TenantService; |
51 | 56 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
57 | +import org.thingsboard.server.dao.user.UserService; | |
52 | 58 | import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
53 | 59 | import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; |
54 | 60 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
55 | 61 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
62 | +import org.thingsboard.server.service.executors.DbCallbackExecutorService; | |
63 | +import org.thingsboard.server.service.mail.MailExecutorService; | |
64 | +import org.thingsboard.server.service.script.JsExecutorService; | |
65 | +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | |
56 | 66 | |
67 | +import java.io.IOException; | |
57 | 68 | import java.io.PrintWriter; |
58 | 69 | import java.io.StringWriter; |
59 | 70 | import java.util.Optional; |
60 | 71 | |
72 | +@Slf4j | |
61 | 73 | @Component |
62 | 74 | public class ActorSystemContext { |
63 | 75 | private static final String AKKA_CONF_FILE_NAME = "actor-system.conf"; |
64 | 76 | |
65 | 77 | protected final ObjectMapper mapper = new ObjectMapper(); |
66 | 78 | |
67 | - @Getter @Setter private ActorService actorService; | |
79 | + @Getter | |
80 | + @Setter | |
81 | + private ActorService actorService; | |
68 | 82 | |
69 | 83 | @Autowired |
70 | - @Getter private DiscoveryService discoveryService; | |
84 | + @Getter | |
85 | + private DiscoveryService discoveryService; | |
71 | 86 | |
72 | 87 | @Autowired |
73 | - @Getter @Setter private ComponentDiscoveryService componentService; | |
88 | + @Getter | |
89 | + @Setter | |
90 | + private ComponentDiscoveryService componentService; | |
74 | 91 | |
75 | 92 | @Autowired |
76 | - @Getter private ClusterRoutingService routingService; | |
93 | + @Getter | |
94 | + private ClusterRoutingService routingService; | |
77 | 95 | |
78 | 96 | @Autowired |
79 | - @Getter private ClusterRpcService rpcService; | |
97 | + @Getter | |
98 | + private ClusterRpcService rpcService; | |
80 | 99 | |
81 | 100 | @Autowired |
82 | - @Getter private DeviceAuthService deviceAuthService; | |
101 | + @Getter | |
102 | + private DeviceAuthService deviceAuthService; | |
83 | 103 | |
84 | 104 | @Autowired |
85 | - @Getter private DeviceService deviceService; | |
105 | + @Getter | |
106 | + private DeviceService deviceService; | |
86 | 107 | |
87 | 108 | @Autowired |
88 | - @Getter private AssetService assetService; | |
109 | + @Getter | |
110 | + private AssetService assetService; | |
89 | 111 | |
90 | 112 | @Autowired |
91 | - @Getter private TenantService tenantService; | |
113 | + @Getter | |
114 | + private TenantService tenantService; | |
92 | 115 | |
93 | 116 | @Autowired |
94 | - @Getter private CustomerService customerService; | |
117 | + @Getter | |
118 | + private CustomerService customerService; | |
95 | 119 | |
96 | 120 | @Autowired |
97 | - @Getter private RuleService ruleService; | |
121 | + @Getter | |
122 | + private UserService userService; | |
98 | 123 | |
99 | 124 | @Autowired |
100 | - @Getter private PluginService pluginService; | |
125 | + @Getter | |
126 | + private RuleService ruleService; | |
101 | 127 | |
102 | 128 | @Autowired |
103 | - @Getter private TimeseriesService tsService; | |
129 | + @Getter | |
130 | + private RuleChainService ruleChainService; | |
104 | 131 | |
105 | 132 | @Autowired |
106 | - @Getter private AttributesService attributesService; | |
133 | + @Getter | |
134 | + private PluginService pluginService; | |
107 | 135 | |
108 | 136 | @Autowired |
109 | - @Getter private EventService eventService; | |
137 | + @Getter | |
138 | + private TimeseriesService tsService; | |
110 | 139 | |
111 | 140 | @Autowired |
112 | - @Getter private AlarmService alarmService; | |
141 | + @Getter | |
142 | + private AttributesService attributesService; | |
113 | 143 | |
114 | 144 | @Autowired |
115 | - @Getter private RelationService relationService; | |
145 | + @Getter | |
146 | + private EventService eventService; | |
116 | 147 | |
117 | 148 | @Autowired |
118 | - @Getter private AuditLogService auditLogService; | |
149 | + @Getter | |
150 | + private AlarmService alarmService; | |
119 | 151 | |
120 | 152 | @Autowired |
121 | - @Getter @Setter private PluginWebSocketMsgEndpoint wsMsgEndpoint; | |
153 | + @Getter | |
154 | + private RelationService relationService; | |
155 | + | |
156 | + @Autowired | |
157 | + @Getter | |
158 | + private AuditLogService auditLogService; | |
159 | + | |
160 | + @Autowired | |
161 | + @Getter | |
162 | + private TelemetrySubscriptionService tsSubService; | |
163 | + | |
164 | + @Autowired | |
165 | + @Getter | |
166 | + @Setter | |
167 | + private PluginWebSocketMsgEndpoint wsMsgEndpoint; | |
168 | + | |
169 | + @Autowired | |
170 | + @Getter | |
171 | + private JsExecutorService jsExecutor; | |
172 | + | |
173 | + @Autowired | |
174 | + @Getter | |
175 | + private MailExecutorService mailExecutor; | |
176 | + | |
177 | + @Autowired | |
178 | + @Getter | |
179 | + private DbCallbackExecutorService dbCallbackExecutor; | |
180 | + | |
181 | + @Autowired | |
182 | + @Getter | |
183 | + private MailService mailService; | |
122 | 184 | |
123 | 185 | @Value("${actors.session.sync.timeout}") |
124 | - @Getter private long syncSessionTimeout; | |
186 | + @Getter | |
187 | + private long syncSessionTimeout; | |
125 | 188 | |
126 | 189 | @Value("${actors.plugin.termination.delay}") |
127 | - @Getter private long pluginActorTerminationDelay; | |
190 | + @Getter | |
191 | + private long pluginActorTerminationDelay; | |
128 | 192 | |
129 | 193 | @Value("${actors.plugin.processing.timeout}") |
130 | - @Getter private long pluginProcessingTimeout; | |
194 | + @Getter | |
195 | + private long pluginProcessingTimeout; | |
131 | 196 | |
132 | 197 | @Value("${actors.plugin.error_persist_frequency}") |
133 | - @Getter private long pluginErrorPersistFrequency; | |
198 | + @Getter | |
199 | + private long pluginErrorPersistFrequency; | |
200 | + | |
201 | + @Value("${actors.rule.chain.error_persist_frequency}") | |
202 | + @Getter | |
203 | + private long ruleChainErrorPersistFrequency; | |
204 | + | |
205 | + @Value("${actors.rule.node.error_persist_frequency}") | |
206 | + @Getter | |
207 | + private long ruleNodeErrorPersistFrequency; | |
134 | 208 | |
135 | 209 | @Value("${actors.rule.termination.delay}") |
136 | - @Getter private long ruleActorTerminationDelay; | |
210 | + @Getter | |
211 | + private long ruleActorTerminationDelay; | |
137 | 212 | |
138 | 213 | @Value("${actors.rule.error_persist_frequency}") |
139 | - @Getter private long ruleErrorPersistFrequency; | |
214 | + @Getter | |
215 | + private long ruleErrorPersistFrequency; | |
140 | 216 | |
141 | 217 | @Value("${actors.statistics.enabled}") |
142 | - @Getter private boolean statisticsEnabled; | |
218 | + @Getter | |
219 | + private boolean statisticsEnabled; | |
143 | 220 | |
144 | 221 | @Value("${actors.statistics.persist_frequency}") |
145 | - @Getter private long statisticsPersistFrequency; | |
222 | + @Getter | |
223 | + private long statisticsPersistFrequency; | |
146 | 224 | |
147 | 225 | @Value("${actors.tenant.create_components_on_init}") |
148 | - @Getter private boolean tenantComponentsInitEnabled; | |
226 | + @Getter | |
227 | + private boolean tenantComponentsInitEnabled; | |
149 | 228 | |
150 | - @Getter @Setter private ActorSystem actorSystem; | |
229 | + @Getter | |
230 | + @Setter | |
231 | + private ActorSystem actorSystem; | |
151 | 232 | |
152 | - @Getter @Setter private ActorRef appActor; | |
233 | + @Getter | |
234 | + @Setter | |
235 | + private ActorRef appActor; | |
153 | 236 | |
154 | - @Getter @Setter private ActorRef sessionManagerActor; | |
237 | + @Getter | |
238 | + @Setter | |
239 | + private ActorRef sessionManagerActor; | |
155 | 240 | |
156 | - @Getter @Setter private ActorRef statsActor; | |
241 | + @Getter | |
242 | + @Setter | |
243 | + private ActorRef statsActor; | |
157 | 244 | |
158 | - @Getter private final Config config; | |
245 | + @Getter | |
246 | + private final Config config; | |
159 | 247 | |
160 | 248 | public ActorSystemContext() { |
161 | 249 | config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); |
... | ... | @@ -187,7 +275,7 @@ public class ActorSystemContext { |
187 | 275 | eventService.save(event); |
188 | 276 | } |
189 | 277 | |
190 | - private String toString(Exception e) { | |
278 | + private String toString(Throwable e) { | |
191 | 279 | StringWriter sw = new StringWriter(); |
192 | 280 | e.printStackTrace(new PrintWriter(sw)); |
193 | 281 | return sw.toString(); |
... | ... | @@ -207,4 +295,60 @@ public class ActorSystemContext { |
207 | 295 | private JsonNode toBodyJson(ServerAddress server, String method, String body) { |
208 | 296 | return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body); |
209 | 297 | } |
298 | + | |
299 | + public String getServerAddress() { | |
300 | + return discoveryService.getCurrentServer().getServerAddress().toString(); | |
301 | + } | |
302 | + | |
303 | + public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg) { | |
304 | + persistDebug(tenantId, entityId, "IN", tbMsg, null); | |
305 | + } | |
306 | + | |
307 | + public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, Throwable error) { | |
308 | + persistDebug(tenantId, entityId, "IN", tbMsg, error); | |
309 | + } | |
310 | + | |
311 | + public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, Throwable error) { | |
312 | + persistDebug(tenantId, entityId, "OUT", tbMsg, error); | |
313 | + } | |
314 | + | |
315 | + public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg) { | |
316 | + persistDebug(tenantId, entityId, "OUT", tbMsg, null); | |
317 | + } | |
318 | + | |
319 | + private void persistDebug(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, Throwable error) { | |
320 | + try { | |
321 | + Event event = new Event(); | |
322 | + event.setTenantId(tenantId); | |
323 | + event.setEntityId(entityId); | |
324 | + event.setType(DataConstants.DEBUG_RULE_NODE); | |
325 | + | |
326 | + String metadata = mapper.writeValueAsString(tbMsg.getMetaData().getData()); | |
327 | + | |
328 | + ObjectNode node = mapper.createObjectNode() | |
329 | + .put("type", type) | |
330 | + .put("server", getServerAddress()) | |
331 | + .put("entityId", tbMsg.getOriginator().getId().toString()) | |
332 | + .put("entityName", tbMsg.getOriginator().getEntityType().name()) | |
333 | + .put("msgId", tbMsg.getId().toString()) | |
334 | + .put("msgType", tbMsg.getType()) | |
335 | + .put("dataType", tbMsg.getDataType().name()) | |
336 | + .put("data", tbMsg.getData()) | |
337 | + .put("metadata", metadata); | |
338 | + | |
339 | + if (error != null) { | |
340 | + node = node.put("error", toString(error)); | |
341 | + } | |
342 | + | |
343 | + event.setBody(node); | |
344 | + eventService.save(event); | |
345 | + } catch (IOException ex) { | |
346 | + log.warn("Failed to persist rule node debug message", ex); | |
347 | + } | |
348 | + } | |
349 | + | |
350 | + public static Exception toException(Throwable error) { | |
351 | + return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); | |
352 | + } | |
353 | + | |
210 | 354 | } | ... | ... |
... | ... | @@ -22,48 +22,41 @@ import akka.event.LoggingAdapter; |
22 | 22 | import akka.japi.Function; |
23 | 23 | import org.thingsboard.server.actors.ActorSystemContext; |
24 | 24 | import org.thingsboard.server.actors.plugin.PluginTerminationMsg; |
25 | -import org.thingsboard.server.actors.service.ContextAwareActor; | |
25 | +import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; | |
26 | 26 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
27 | 27 | import org.thingsboard.server.actors.service.DefaultActorService; |
28 | -import org.thingsboard.server.actors.shared.plugin.PluginManager; | |
29 | 28 | import org.thingsboard.server.actors.shared.plugin.SystemPluginManager; |
30 | -import org.thingsboard.server.actors.shared.rule.RuleManager; | |
31 | -import org.thingsboard.server.actors.shared.rule.SystemRuleManager; | |
32 | -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg; | |
29 | +import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager; | |
33 | 30 | import org.thingsboard.server.actors.tenant.TenantActor; |
34 | 31 | import org.thingsboard.server.common.data.Tenant; |
35 | 32 | import org.thingsboard.server.common.data.id.PluginId; |
36 | -import org.thingsboard.server.common.data.id.RuleId; | |
33 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
37 | 34 | import org.thingsboard.server.common.data.id.TenantId; |
38 | 35 | import org.thingsboard.server.common.data.page.PageDataIterable; |
36 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
39 | 37 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
40 | 38 | import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
41 | 39 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
40 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
42 | 41 | import org.thingsboard.server.dao.model.ModelConstants; |
43 | 42 | import org.thingsboard.server.dao.tenant.TenantService; |
44 | 43 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
45 | 44 | import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg; |
46 | -import org.thingsboard.server.extensions.api.rules.ToRuleActorMsg; | |
47 | 45 | import scala.concurrent.duration.Duration; |
48 | 46 | |
49 | 47 | import java.util.HashMap; |
50 | 48 | import java.util.Map; |
51 | -import java.util.Optional; | |
52 | 49 | |
53 | -public class AppActor extends ContextAwareActor { | |
50 | +public class AppActor extends RuleChainManagerActor { | |
54 | 51 | |
55 | 52 | private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); |
56 | 53 | |
57 | 54 | public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); |
58 | - private final RuleManager ruleManager; | |
59 | - private final PluginManager pluginManager; | |
60 | 55 | private final TenantService tenantService; |
61 | 56 | private final Map<TenantId, ActorRef> tenantActors; |
62 | 57 | |
63 | 58 | private AppActor(ActorSystemContext systemContext) { |
64 | - super(systemContext); | |
65 | - this.ruleManager = new SystemRuleManager(systemContext); | |
66 | - this.pluginManager = new SystemPluginManager(systemContext); | |
59 | + super(systemContext, new SystemRuleChainManager(systemContext), new SystemPluginManager(systemContext)); | |
67 | 60 | this.tenantService = systemContext.getTenantService(); |
68 | 61 | this.tenantActors = new HashMap<>(); |
69 | 62 | } |
... | ... | @@ -77,8 +70,7 @@ public class AppActor extends ContextAwareActor { |
77 | 70 | public void preStart() { |
78 | 71 | logger.info("Starting main system actor."); |
79 | 72 | try { |
80 | - ruleManager.init(this.context()); | |
81 | - pluginManager.init(this.context()); | |
73 | + initRuleChains(); | |
82 | 74 | |
83 | 75 | if (systemContext.isTenantComponentsInitEnabled()) { |
84 | 76 | PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); |
... | ... | @@ -96,29 +88,51 @@ public class AppActor extends ContextAwareActor { |
96 | 88 | } |
97 | 89 | |
98 | 90 | @Override |
99 | - public void onReceive(Object msg) throws Exception { | |
100 | - logger.debug("Received message: {}", msg); | |
101 | - if (msg instanceof ToDeviceActorMsg) { | |
102 | - processDeviceMsg((ToDeviceActorMsg) msg); | |
103 | - } else if (msg instanceof ToPluginActorMsg) { | |
104 | - onToPluginMsg((ToPluginActorMsg) msg); | |
105 | - } else if (msg instanceof ToRuleActorMsg) { | |
106 | - onToRuleMsg((ToRuleActorMsg) msg); | |
107 | - } else if (msg instanceof ToDeviceActorNotificationMsg) { | |
108 | - onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg); | |
109 | - } else if (msg instanceof Terminated) { | |
110 | - processTermination((Terminated) msg); | |
111 | - } else if (msg instanceof ClusterEventMsg) { | |
112 | - broadcast(msg); | |
113 | - } else if (msg instanceof ComponentLifecycleMsg) { | |
114 | - onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
115 | - } else if (msg instanceof PluginTerminationMsg) { | |
116 | - onPluginTerminated((PluginTerminationMsg) msg); | |
91 | + protected boolean process(TbActorMsg msg) { | |
92 | + switch (msg.getMsgType()) { | |
93 | + case COMPONENT_LIFE_CYCLE_MSG: | |
94 | + onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
95 | + break; | |
96 | + case SERVICE_TO_RULE_ENGINE_MSG: | |
97 | + onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | |
98 | + break; | |
99 | + default: | |
100 | + return false; | |
101 | + } | |
102 | + return true; | |
103 | + } | |
104 | + | |
105 | + private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { | |
106 | + if (SYSTEM_TENANT.equals(msg.getTenantId())) { | |
107 | + //TODO: ashvayka handle this. | |
117 | 108 | } else { |
118 | - logger.warning("Unknown message: {}!", msg); | |
109 | + getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); | |
119 | 110 | } |
120 | 111 | } |
121 | 112 | |
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 | + | |
122 | 136 | private void onPluginTerminated(PluginTerminationMsg msg) { |
123 | 137 | pluginManager.remove(msg.getId()); |
124 | 138 | } |
... | ... | @@ -128,20 +142,10 @@ public class AppActor extends ContextAwareActor { |
128 | 142 | tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
129 | 143 | } |
130 | 144 | |
131 | - private void onToRuleMsg(ToRuleActorMsg msg) { | |
132 | - ActorRef target; | |
133 | - if (SYSTEM_TENANT.equals(msg.getTenantId())) { | |
134 | - target = ruleManager.getOrCreateRuleActor(this.context(), msg.getRuleId()); | |
135 | - } else { | |
136 | - target = getOrCreateTenantActor(msg.getTenantId()); | |
137 | - } | |
138 | - target.tell(msg, ActorRef.noSender()); | |
139 | - } | |
140 | - | |
141 | 145 | private void onToPluginMsg(ToPluginActorMsg msg) { |
142 | 146 | ActorRef target; |
143 | 147 | if (SYSTEM_TENANT.equals(msg.getPluginTenantId())) { |
144 | - target = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId()); | |
148 | + target = pluginManager.getOrCreateActor(this.context(), msg.getPluginId()); | |
145 | 149 | } else { |
146 | 150 | target = getOrCreateTenantActor(msg.getPluginTenantId()); |
147 | 151 | } |
... | ... | @@ -149,26 +153,16 @@ public class AppActor extends ContextAwareActor { |
149 | 153 | } |
150 | 154 | |
151 | 155 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
152 | - ActorRef target = null; | |
156 | + ActorRef target; | |
153 | 157 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
154 | - Optional<PluginId> pluginId = msg.getPluginId(); | |
155 | - Optional<RuleId> ruleId = msg.getRuleId(); | |
156 | - if (pluginId.isPresent()) { | |
157 | - target = pluginManager.getOrCreatePluginActor(this.context(), pluginId.get()); | |
158 | - } else if (ruleId.isPresent()) { | |
159 | - Optional<ActorRef> ref = ruleManager.update(this.context(), ruleId.get(), msg.getEvent()); | |
160 | - if (ref.isPresent()) { | |
161 | - target = ref.get(); | |
162 | - } else { | |
163 | - logger.debug("Failed to find actor for rule: [{}]", ruleId); | |
164 | - return; | |
165 | - } | |
166 | - } | |
158 | + target = getEntityActorRef(msg.getEntityId()); | |
167 | 159 | } else { |
168 | 160 | target = getOrCreateTenantActor(msg.getTenantId()); |
169 | 161 | } |
170 | 162 | if (target != null) { |
171 | 163 | target.tell(msg, ActorRef.noSender()); |
164 | + } else { | |
165 | + logger.debug("Invalid component lifecycle msg: {}", msg); | |
172 | 166 | } |
173 | 167 | } |
174 | 168 | |
... | ... | @@ -180,7 +174,7 @@ public class AppActor extends ContextAwareActor { |
180 | 174 | TenantId tenantId = toDeviceActorMsg.getTenantId(); |
181 | 175 | ActorRef tenantActor = getOrCreateTenantActor(tenantId); |
182 | 176 | if (toDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { |
183 | - tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | |
177 | +// tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self()); | |
184 | 178 | } else { |
185 | 179 | tenantActor.tell(toDeviceActorMsg, context().self()); |
186 | 180 | } | ... | ... |
... | ... | @@ -18,19 +18,19 @@ package org.thingsboard.server.actors.device; |
18 | 18 | import akka.event.Logging; |
19 | 19 | import akka.event.LoggingAdapter; |
20 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | -import org.thingsboard.server.actors.rule.RulesProcessedMsg; | |
22 | 21 | import org.thingsboard.server.actors.service.ContextAwareActor; |
23 | 22 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
24 | -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg; | |
25 | 23 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | 24 | import org.thingsboard.server.common.data.id.TenantId; |
25 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
27 | 26 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
28 | 27 | import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
29 | 28 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
30 | 29 | import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg; |
31 | 30 | import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; |
32 | 31 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
33 | -import org.thingsboard.server.extensions.api.plugins.msg.*; | |
32 | +import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | |
33 | +import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | |
34 | 34 | |
35 | 35 | public class DeviceActor extends ContextAwareActor { |
36 | 36 | |
... | ... | @@ -48,12 +48,17 @@ public class DeviceActor extends ContextAwareActor { |
48 | 48 | } |
49 | 49 | |
50 | 50 | @Override |
51 | + protected boolean process(TbActorMsg msg) { | |
52 | + return false; | |
53 | + } | |
54 | + | |
55 | + @Override | |
51 | 56 | public void onReceive(Object msg) throws Exception { |
52 | - if (msg instanceof RuleChainDeviceMsg) { | |
53 | - processor.process(context(), (RuleChainDeviceMsg) msg); | |
54 | - } else if (msg instanceof RulesProcessedMsg) { | |
55 | - processor.onRulesProcessedMsg(context(), (RulesProcessedMsg) msg); | |
56 | - } else if (msg instanceof ToDeviceActorMsg) { | |
57 | +// 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) { | |
57 | 62 | processor.process(context(), (ToDeviceActorMsg) msg); |
58 | 63 | } else if (msg instanceof ToDeviceActorNotificationMsg) { |
59 | 64 | if (msg instanceof DeviceAttributesEventNotificationMsg) { | ... | ... |
... | ... | @@ -19,9 +19,7 @@ import akka.actor.ActorContext; |
19 | 19 | import akka.actor.ActorRef; |
20 | 20 | import akka.event.LoggingAdapter; |
21 | 21 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | -import org.thingsboard.server.actors.rule.*; | |
23 | 22 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
24 | -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg; | |
25 | 23 | import org.thingsboard.server.common.data.DataConstants; |
26 | 24 | import org.thingsboard.server.common.data.Device; |
27 | 25 | import org.thingsboard.server.common.data.id.DeviceId; |
... | ... | @@ -37,15 +35,10 @@ import org.thingsboard.server.common.msg.session.FromDeviceMsg; |
37 | 35 | import org.thingsboard.server.common.msg.session.MsgType; |
38 | 36 | import org.thingsboard.server.common.msg.session.SessionType; |
39 | 37 | import org.thingsboard.server.common.msg.session.ToDeviceMsg; |
40 | -import org.thingsboard.server.extensions.api.device.*; | |
41 | -import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; | |
42 | -import org.thingsboard.server.extensions.api.plugins.msg.RpcError; | |
43 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutIntMsg; | |
44 | -import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; | |
45 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest; | |
46 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestBody; | |
47 | -import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg; | |
48 | -import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg; | |
38 | +import org.thingsboard.server.extensions.api.device.DeviceAttributes; | |
39 | +import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; | |
40 | +import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; | |
41 | +import org.thingsboard.server.extensions.api.plugins.msg.*; | |
49 | 42 | |
50 | 43 | import java.util.*; |
51 | 44 | import java.util.concurrent.ExecutionException; |
... | ... | @@ -230,18 +223,18 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
230 | 223 | } |
231 | 224 | } |
232 | 225 | |
233 | - void process(ActorContext context, RuleChainDeviceMsg srcMsg) { | |
234 | - ChainProcessingMetaData md = new ChainProcessingMetaData(srcMsg.getRuleChain(), | |
235 | - srcMsg.getToDeviceActorMsg(), new DeviceMetaData(deviceId, deviceName, deviceType, deviceAttributes), context.self()); | |
236 | - ChainProcessingContext ctx = new ChainProcessingContext(md); | |
237 | - if (ctx.getChainLength() > 0) { | |
238 | - RuleProcessingMsg msg = new RuleProcessingMsg(ctx); | |
239 | - ActorRef ruleActorRef = ctx.getCurrentActor(); | |
240 | - ruleActorRef.tell(msg, ActorRef.noSender()); | |
241 | - } else { | |
242 | - context.self().tell(new RulesProcessedMsg(ctx), context.self()); | |
243 | - } | |
244 | - } | |
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 | +// } | |
245 | 238 | |
246 | 239 | void processRpcResponses(ActorContext context, ToDeviceActorMsg msg) { |
247 | 240 | SessionId sessionId = msg.getSessionId(); |
... | ... | @@ -302,18 +295,18 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso |
302 | 295 | ); |
303 | 296 | } |
304 | 297 | |
305 | - void onRulesProcessedMsg(ActorContext context, RulesProcessedMsg msg) { | |
306 | - ChainProcessingContext ctx = msg.getCtx(); | |
307 | - ToDeviceActorMsg inMsg = ctx.getInMsg(); | |
308 | - SessionId sid = inMsg.getSessionId(); | |
309 | - ToDeviceSessionActorMsg response; | |
310 | - if (ctx.getResponse() != null) { | |
311 | - response = new BasicToDeviceSessionActorMsg(ctx.getResponse(), sid); | |
312 | - } else { | |
313 | - response = new BasicToDeviceSessionActorMsg(ctx.getError(), sid); | |
314 | - } | |
315 | - sendMsgToSessionActor(response, inMsg.getServerAddress()); | |
316 | - } | |
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 | +// } | |
317 | 310 | |
318 | 311 | private void processSubscriptionCommands(ActorContext context, ToDeviceActorMsg msg) { |
319 | 312 | SessionId sessionId = msg.getSessionId(); | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; |
23 | 23 | import org.thingsboard.server.actors.stats.StatsPersistTick; |
24 | 24 | import org.thingsboard.server.common.data.id.PluginId; |
25 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
26 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
26 | 27 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
27 | 28 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
28 | 29 | import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; |
... | ... | @@ -41,6 +42,12 @@ public class PluginActor extends ComponentActor<PluginId, PluginActorMessageProc |
41 | 42 | } |
42 | 43 | |
43 | 44 | @Override |
45 | + protected boolean process(TbActorMsg msg) { | |
46 | + //TODO Move everything here, to work with TbActorMsg | |
47 | + return false; | |
48 | + } | |
49 | + | |
50 | + @Override | |
44 | 51 | public void onReceive(Object msg) throws Exception { |
45 | 52 | if (msg instanceof PluginWebsocketMsg) { |
46 | 53 | onWebsocketMsg((PluginWebsocketMsg<?>) msg); | ... | ... |
... | ... | @@ -28,9 +28,14 @@ import org.thingsboard.server.common.data.plugin.ComponentType; |
28 | 28 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
29 | 29 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
30 | 30 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
31 | +import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; | |
32 | +import org.thingsboard.server.common.msg.session.FromDeviceRequestMsg; | |
33 | +import org.thingsboard.server.common.msg.session.MsgType; | |
31 | 34 | import org.thingsboard.server.extensions.api.plugins.Plugin; |
32 | 35 | import org.thingsboard.server.extensions.api.plugins.PluginInitializationException; |
33 | 36 | import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse; |
37 | +import org.thingsboard.server.extensions.api.plugins.msg.ResponsePluginToRuleMsg; | |
38 | +import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; | |
34 | 39 | import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; |
35 | 40 | import org.thingsboard.server.extensions.api.plugins.rest.PluginRestMsg; |
36 | 41 | import org.thingsboard.server.extensions.api.plugins.rpc.PluginRpcMsg; |
... | ... | @@ -57,7 +62,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
57 | 62 | } |
58 | 63 | |
59 | 64 | @Override |
60 | - public void start() throws Exception { | |
65 | + public void start(ActorContext context) throws Exception { | |
61 | 66 | logger.info("[{}] Going to start plugin actor.", entityId); |
62 | 67 | pluginMd = systemContext.getPluginService().findPluginById(entityId); |
63 | 68 | if (pluginMd == null) { |
... | ... | @@ -76,7 +81,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
76 | 81 | } |
77 | 82 | |
78 | 83 | @Override |
79 | - public void stop() throws Exception { | |
84 | + public void stop(ActorContext context) throws Exception { | |
80 | 85 | onStop(); |
81 | 86 | } |
82 | 87 | |
... | ... | @@ -98,7 +103,20 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
98 | 103 | |
99 | 104 | public void onRuleToPluginMsg(RuleToPluginMsgWrapper msg) throws RuleException { |
100 | 105 | if (state == ComponentLifecycleState.ACTIVE) { |
101 | - pluginImpl.process(trustedCtx, msg.getRuleTenantId(), msg.getRuleId(), msg.getMsg()); | |
106 | + try { | |
107 | + pluginImpl.process(trustedCtx, msg.getRuleTenantId(), msg.getRuleId(), msg.getMsg()); | |
108 | + } catch (Exception ex) { | |
109 | + logger.debug("[{}] Failed to process RuleToPlugin msg: [{}] [{}]", tenantId, msg.getMsg(), ex); | |
110 | + RuleToPluginMsg ruleMsg = msg.getMsg(); | |
111 | + MsgType responceMsgType = MsgType.RULE_ENGINE_ERROR; | |
112 | + Integer requestId = 0; | |
113 | + if (ruleMsg.getPayload() instanceof FromDeviceRequestMsg) { | |
114 | + requestId = ((FromDeviceRequestMsg) ruleMsg.getPayload()).getRequestId(); | |
115 | + } | |
116 | + trustedCtx.reply( | |
117 | + new ResponsePluginToRuleMsg(ruleMsg.getUid(), tenantId, msg.getRuleId(), | |
118 | + BasicStatusCodeResponse.onError(responceMsgType, requestId, ex))); | |
119 | + } | |
102 | 120 | } else { |
103 | 121 | //TODO: reply with plugin suspended message |
104 | 122 | } |
... | ... | @@ -191,7 +209,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
191 | 209 | if (pluginImpl != null) { |
192 | 210 | pluginImpl.stop(trustedCtx); |
193 | 211 | } |
194 | - start(); | |
212 | + start(context); | |
195 | 213 | } |
196 | 214 | } |
197 | 215 | |
... | ... | @@ -217,7 +235,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
217 | 235 | pluginImpl.resume(trustedCtx); |
218 | 236 | logger.info("[{}] Plugin resumed.", entityId); |
219 | 237 | } else { |
220 | - start(); | |
238 | + start(context); | |
221 | 239 | } |
222 | 240 | } |
223 | 241 | ... | ... |
... | ... | @@ -36,6 +36,7 @@ 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.rule.RuleChain; | |
39 | 40 | import org.thingsboard.server.common.data.rule.RuleMetaData; |
40 | 41 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
41 | 42 | import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; |
... | ... | @@ -330,6 +331,9 @@ public final class PluginProcessingContext implements PluginContext { |
330 | 331 | case RULE: |
331 | 332 | validateRule(ctx, entityId, callback); |
332 | 333 | return; |
334 | + case RULE_CHAIN: | |
335 | + validateRuleChain(ctx, entityId, callback); | |
336 | + return; | |
333 | 337 | case PLUGIN: |
334 | 338 | validatePlugin(ctx, entityId, callback); |
335 | 339 | return; |
... | ... | @@ -411,6 +415,28 @@ public final class PluginProcessingContext implements PluginContext { |
411 | 415 | } |
412 | 416 | } |
413 | 417 | |
418 | + private void validateRuleChain(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { | |
419 | + if (ctx.isCustomerUser()) { | |
420 | + callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | |
421 | + } else { | |
422 | + ListenableFuture<RuleChain> ruleChainFuture = pluginCtx.ruleChainService.findRuleChainByIdAsync(new RuleChainId(entityId.getId())); | |
423 | + Futures.addCallback(ruleChainFuture, getCallback(callback, ruleChain -> { | |
424 | + if (ruleChain == null) { | |
425 | + return ValidationResult.entityNotFound("Rule chain with requested id wasn't found!"); | |
426 | + } else { | |
427 | + if (ctx.isTenantAdmin() && !ruleChain.getTenantId().equals(ctx.getTenantId())) { | |
428 | + return ValidationResult.accessDenied("Rule chain doesn't belong to the current Tenant!"); | |
429 | + } else if (ctx.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) { | |
430 | + return ValidationResult.accessDenied("Rule chain is not in system scope!"); | |
431 | + } else { | |
432 | + return ValidationResult.ok(); | |
433 | + } | |
434 | + } | |
435 | + })); | |
436 | + } | |
437 | + } | |
438 | + | |
439 | + | |
414 | 440 | private void validatePlugin(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) { |
415 | 441 | if (ctx.isCustomerUser()) { |
416 | 442 | callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION)); | ... | ... |
... | ... | @@ -32,6 +32,7 @@ import org.thingsboard.server.dao.customer.CustomerService; |
32 | 32 | import org.thingsboard.server.dao.device.DeviceService; |
33 | 33 | import org.thingsboard.server.dao.plugin.PluginService; |
34 | 34 | import org.thingsboard.server.dao.relation.RelationService; |
35 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
35 | 36 | import org.thingsboard.server.dao.rule.RuleService; |
36 | 37 | import org.thingsboard.server.dao.tenant.TenantService; |
37 | 38 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
... | ... | @@ -56,6 +57,7 @@ public final class SharedPluginProcessingContext { |
56 | 57 | final AssetService assetService; |
57 | 58 | final DeviceService deviceService; |
58 | 59 | final RuleService ruleService; |
60 | + final RuleChainService ruleChainService; | |
59 | 61 | final PluginService pluginService; |
60 | 62 | final CustomerService customerService; |
61 | 63 | final TenantService tenantService; |
... | ... | @@ -84,6 +86,7 @@ public final class SharedPluginProcessingContext { |
84 | 86 | this.rpcService = sysContext.getRpcService(); |
85 | 87 | this.routingService = sysContext.getRoutingService(); |
86 | 88 | this.ruleService = sysContext.getRuleService(); |
89 | + this.ruleChainService = sysContext.getRuleChainService(); | |
87 | 90 | this.pluginService = sysContext.getPluginService(); |
88 | 91 | this.customerService = sysContext.getCustomerService(); |
89 | 92 | this.tenantService = sysContext.getTenantService(); | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.ActorSystemContext; |
23 | 23 | import org.thingsboard.server.actors.service.ContextAwareActor; |
24 | 24 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
25 | 25 | import org.thingsboard.server.actors.service.DefaultActorService; |
26 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
26 | 27 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
27 | 28 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
28 | 29 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
... | ... | @@ -57,6 +58,12 @@ public class RpcManagerActor extends ContextAwareActor { |
57 | 58 | } |
58 | 59 | |
59 | 60 | @Override |
61 | + protected boolean process(TbActorMsg msg) { | |
62 | + //TODO Move everything here, to work with TbActorMsg | |
63 | + return false; | |
64 | + } | |
65 | + | |
66 | + @Override | |
60 | 67 | public void onReceive(Object msg) throws Exception { |
61 | 68 | if (msg instanceof RpcSessionTellMsg) { |
62 | 69 | onMsg((RpcSessionTellMsg) msg); | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import io.grpc.stub.StreamObserver; |
23 | 23 | import org.thingsboard.server.actors.ActorSystemContext; |
24 | 24 | import org.thingsboard.server.actors.service.ContextAwareActor; |
25 | 25 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
26 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
26 | 27 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
27 | 28 | import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
28 | 29 | import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; |
... | ... | @@ -48,6 +49,12 @@ public class RpcSessionActor extends ContextAwareActor { |
48 | 49 | } |
49 | 50 | |
50 | 51 | @Override |
52 | + protected boolean process(TbActorMsg msg) { | |
53 | + //TODO Move everything here, to work with TbActorMsg | |
54 | + return false; | |
55 | + } | |
56 | + | |
57 | + @Override | |
51 | 58 | public void onReceive(Object msg) throws Exception { |
52 | 59 | if (msg instanceof RpcSessionTellMsg) { |
53 | 60 | tell((RpcSessionTellMsg) msg); | ... | ... |
application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingContext.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors.rule; | |
17 | - | |
18 | -import akka.actor.ActorRef; | |
19 | -import org.thingsboard.server.common.msg.core.RuleEngineError; | |
20 | -import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg; | |
21 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
22 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | |
23 | -import org.thingsboard.server.extensions.api.device.DeviceAttributes; | |
24 | -import org.thingsboard.server.extensions.api.device.DeviceMetaData; | |
25 | - | |
26 | -public class ChainProcessingContext { | |
27 | - | |
28 | - private final ChainProcessingMetaData md; | |
29 | - private final int index; | |
30 | - private final RuleEngineError error; | |
31 | - private ToDeviceMsg response; | |
32 | - | |
33 | - | |
34 | - public ChainProcessingContext(ChainProcessingMetaData md) { | |
35 | - super(); | |
36 | - this.md = md; | |
37 | - this.index = 0; | |
38 | - this.error = RuleEngineError.NO_RULES; | |
39 | - } | |
40 | - | |
41 | - private ChainProcessingContext(ChainProcessingContext other, int indexOffset, RuleEngineError error) { | |
42 | - super(); | |
43 | - this.md = other.md; | |
44 | - this.index = other.index + indexOffset; | |
45 | - this.error = error; | |
46 | - this.response = other.response; | |
47 | - | |
48 | - if (this.index < 0 || this.index >= this.md.chain.size()) { | |
49 | - throw new IllegalArgumentException("Can't apply offset " + indexOffset + " to the chain!"); | |
50 | - } | |
51 | - } | |
52 | - | |
53 | - public ActorRef getDeviceActor() { | |
54 | - return md.originator; | |
55 | - } | |
56 | - | |
57 | - public ActorRef getCurrentActor() { | |
58 | - return md.chain.getRuleActorMd(index).getActorRef(); | |
59 | - } | |
60 | - | |
61 | - public boolean hasNext() { | |
62 | - return (getChainLength() - 1) > index; | |
63 | - } | |
64 | - | |
65 | - public boolean isFailure() { | |
66 | - return (error != null && error.isCritical()) || (response != null && !response.isSuccess()); | |
67 | - } | |
68 | - | |
69 | - public ChainProcessingContext getNext() { | |
70 | - return new ChainProcessingContext(this, 1, this.error); | |
71 | - } | |
72 | - | |
73 | - public ChainProcessingContext withError(RuleEngineError error) { | |
74 | - if (error != null && (this.error == null || this.error.getPriority() < error.getPriority())) { | |
75 | - return new ChainProcessingContext(this, 0, error); | |
76 | - } else { | |
77 | - return this; | |
78 | - } | |
79 | - } | |
80 | - | |
81 | - public int getChainLength() { | |
82 | - return md.chain.size(); | |
83 | - } | |
84 | - | |
85 | - public ToDeviceActorMsg getInMsg() { | |
86 | - return md.inMsg; | |
87 | - } | |
88 | - | |
89 | - public DeviceMetaData getDeviceMetaData() { | |
90 | - return md.deviceMetaData; | |
91 | - } | |
92 | - | |
93 | - public String getDeviceName() { | |
94 | - return md.deviceMetaData.getDeviceName(); | |
95 | - } | |
96 | - | |
97 | - public String getDeviceType() { | |
98 | - return md.deviceMetaData.getDeviceType(); | |
99 | - } | |
100 | - | |
101 | - public DeviceAttributes getAttributes() { | |
102 | - return md.deviceMetaData.getDeviceAttributes(); | |
103 | - } | |
104 | - | |
105 | - public ToDeviceMsg getResponse() { | |
106 | - return response; | |
107 | - } | |
108 | - | |
109 | - public void mergeResponse(ToDeviceMsg response) { | |
110 | - // TODO add merge logic | |
111 | - this.response = response; | |
112 | - } | |
113 | - | |
114 | - public RuleEngineErrorMsg getError() { | |
115 | - return new RuleEngineErrorMsg(md.inMsg.getPayload().getMsgType(), error); | |
116 | - } | |
117 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleActor.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors.rule; | |
17 | - | |
18 | -import org.thingsboard.server.actors.ActorSystemContext; | |
19 | -import org.thingsboard.server.actors.service.ComponentActor; | |
20 | -import org.thingsboard.server.actors.service.ContextBasedCreator; | |
21 | -import org.thingsboard.server.actors.stats.StatsPersistTick; | |
22 | -import org.thingsboard.server.common.data.id.RuleId; | |
23 | -import org.thingsboard.server.common.data.id.TenantId; | |
24 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
25 | -import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | |
26 | -import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; | |
27 | - | |
28 | -public class RuleActor extends ComponentActor<RuleId, RuleActorMessageProcessor> { | |
29 | - | |
30 | - private RuleActor(ActorSystemContext systemContext, TenantId tenantId, RuleId ruleId) { | |
31 | - super(systemContext, tenantId, ruleId); | |
32 | - setProcessor(new RuleActorMessageProcessor(tenantId, ruleId, systemContext, logger)); | |
33 | - } | |
34 | - | |
35 | - @Override | |
36 | - public void onReceive(Object msg) throws Exception { | |
37 | - logger.debug("[{}] Received message: {}", id, msg); | |
38 | - if (msg instanceof RuleProcessingMsg) { | |
39 | - try { | |
40 | - processor.onRuleProcessingMsg(context(), (RuleProcessingMsg) msg); | |
41 | - increaseMessagesProcessedCount(); | |
42 | - } catch (Exception e) { | |
43 | - logAndPersist("onDeviceMsg", e); | |
44 | - } | |
45 | - } else if (msg instanceof PluginToRuleMsg<?>) { | |
46 | - try { | |
47 | - processor.onPluginMsg(context(), (PluginToRuleMsg<?>) msg); | |
48 | - } catch (Exception e) { | |
49 | - logAndPersist("onPluginMsg", e); | |
50 | - } | |
51 | - } else if (msg instanceof ComponentLifecycleMsg) { | |
52 | - onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
53 | - } else if (msg instanceof ClusterEventMsg) { | |
54 | - onClusterEventMsg((ClusterEventMsg) msg); | |
55 | - } else if (msg instanceof RuleToPluginTimeoutMsg) { | |
56 | - try { | |
57 | - processor.onTimeoutMsg(context(), (RuleToPluginTimeoutMsg) msg); | |
58 | - } catch (Exception e) { | |
59 | - logAndPersist("onTimeoutMsg", e); | |
60 | - } | |
61 | - } else if (msg instanceof StatsPersistTick) { | |
62 | - onStatsPersistTick(id); | |
63 | - } else { | |
64 | - logger.debug("[{}][{}] Unknown msg type.", tenantId, id, msg.getClass().getName()); | |
65 | - } | |
66 | - } | |
67 | - | |
68 | - public static class ActorCreator extends ContextBasedCreator<RuleActor> { | |
69 | - private static final long serialVersionUID = 1L; | |
70 | - | |
71 | - private final TenantId tenantId; | |
72 | - private final RuleId ruleId; | |
73 | - | |
74 | - public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleId ruleId) { | |
75 | - super(context); | |
76 | - this.tenantId = tenantId; | |
77 | - this.ruleId = ruleId; | |
78 | - } | |
79 | - | |
80 | - @Override | |
81 | - public RuleActor create() throws Exception { | |
82 | - return new RuleActor(context, tenantId, ruleId); | |
83 | - } | |
84 | - } | |
85 | - | |
86 | - @Override | |
87 | - protected long getErrorPersistFrequency() { | |
88 | - return systemContext.getRuleErrorPersistFrequency(); | |
89 | - } | |
90 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMessageProcessor.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors.rule; | |
17 | - | |
18 | -import java.util.*; | |
19 | - | |
20 | -import com.fasterxml.jackson.core.JsonProcessingException; | |
21 | -import org.springframework.util.StringUtils; | |
22 | -import org.thingsboard.server.actors.ActorSystemContext; | |
23 | -import org.thingsboard.server.actors.plugin.RuleToPluginMsgWrapper; | |
24 | -import org.thingsboard.server.actors.shared.ComponentMsgProcessor; | |
25 | -import org.thingsboard.server.common.data.id.PluginId; | |
26 | -import org.thingsboard.server.common.data.id.RuleId; | |
27 | -import org.thingsboard.server.common.data.id.TenantId; | |
28 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
29 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
30 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
31 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
32 | -import org.thingsboard.server.common.msg.core.BasicRequest; | |
33 | -import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse; | |
34 | -import org.thingsboard.server.common.msg.core.RuleEngineError; | |
35 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
36 | -import org.thingsboard.server.common.msg.session.MsgType; | |
37 | -import org.thingsboard.server.common.msg.session.ToDeviceMsg; | |
38 | -import org.thingsboard.server.common.msg.session.ex.ProcessingTimeoutException; | |
39 | -import org.thingsboard.server.extensions.api.rules.*; | |
40 | -import org.thingsboard.server.extensions.api.plugins.PluginAction; | |
41 | -import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; | |
42 | -import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg; | |
43 | - | |
44 | -import com.fasterxml.jackson.databind.JsonNode; | |
45 | - | |
46 | -import akka.actor.ActorContext; | |
47 | -import akka.actor.ActorRef; | |
48 | -import akka.event.LoggingAdapter; | |
49 | - | |
50 | -class RuleActorMessageProcessor extends ComponentMsgProcessor<RuleId> { | |
51 | - | |
52 | - private final RuleProcessingContext ruleCtx; | |
53 | - private final Map<UUID, RuleProcessingMsg> pendingMsgMap; | |
54 | - | |
55 | - private RuleMetaData ruleMd; | |
56 | - private ComponentLifecycleState state; | |
57 | - private List<RuleFilter> filters; | |
58 | - private RuleProcessor processor; | |
59 | - private PluginAction action; | |
60 | - | |
61 | - private TenantId pluginTenantId; | |
62 | - private PluginId pluginId; | |
63 | - | |
64 | - protected RuleActorMessageProcessor(TenantId tenantId, RuleId ruleId, ActorSystemContext systemContext, LoggingAdapter logger) { | |
65 | - super(systemContext, logger, tenantId, ruleId); | |
66 | - this.pendingMsgMap = new HashMap<>(); | |
67 | - this.ruleCtx = new RuleProcessingContext(systemContext, ruleId); | |
68 | - } | |
69 | - | |
70 | - @Override | |
71 | - public void start() throws Exception { | |
72 | - logger.info("[{}][{}] Starting rule actor.", entityId, tenantId); | |
73 | - ruleMd = systemContext.getRuleService().findRuleById(entityId); | |
74 | - if (ruleMd == null) { | |
75 | - throw new RuleInitializationException("Rule not found!"); | |
76 | - } | |
77 | - state = ruleMd.getState(); | |
78 | - if (state == ComponentLifecycleState.ACTIVE) { | |
79 | - logger.info("[{}] Rule is active. Going to initialize rule components.", entityId); | |
80 | - initComponent(); | |
81 | - } else { | |
82 | - logger.info("[{}] Rule is suspended. Skipping rule components initialization.", entityId); | |
83 | - } | |
84 | - | |
85 | - logger.info("[{}][{}] Started rule actor.", entityId, tenantId); | |
86 | - } | |
87 | - | |
88 | - @Override | |
89 | - public void stop() throws Exception { | |
90 | - onStop(); | |
91 | - } | |
92 | - | |
93 | - | |
94 | - private void initComponent() throws RuleException { | |
95 | - try { | |
96 | - if (!ruleMd.getFilters().isArray()) { | |
97 | - throw new RuntimeException("Filters are not array!"); | |
98 | - } | |
99 | - fetchPluginInfo(); | |
100 | - initFilters(); | |
101 | - initProcessor(); | |
102 | - initAction(); | |
103 | - } catch (RuntimeException e) { | |
104 | - throw new RuleInitializationException("Unknown runtime exception!", e); | |
105 | - } catch (InstantiationException e) { | |
106 | - throw new RuleInitializationException("No default constructor for rule implementation!", e); | |
107 | - } catch (IllegalAccessException e) { | |
108 | - throw new RuleInitializationException("Illegal Access Exception during rule initialization!", e); | |
109 | - } catch (ClassNotFoundException e) { | |
110 | - throw new RuleInitializationException("Rule Class not found!", e); | |
111 | - } catch (Exception e) { | |
112 | - throw new RuleException(e.getMessage(), e); | |
113 | - } | |
114 | - } | |
115 | - | |
116 | - private void initAction() throws Exception { | |
117 | - if (ruleMd.getAction() != null && !ruleMd.getAction().isNull()) { | |
118 | - action = initComponent(ruleMd.getAction()); | |
119 | - } | |
120 | - } | |
121 | - | |
122 | - private void initProcessor() throws Exception { | |
123 | - if (ruleMd.getProcessor() != null && !ruleMd.getProcessor().isNull()) { | |
124 | - processor = initComponent(ruleMd.getProcessor()); | |
125 | - } | |
126 | - } | |
127 | - | |
128 | - private void initFilters() throws Exception { | |
129 | - filters = new ArrayList<>(ruleMd.getFilters().size()); | |
130 | - for (int i = 0; i < ruleMd.getFilters().size(); i++) { | |
131 | - filters.add(initComponent(ruleMd.getFilters().get(i))); | |
132 | - } | |
133 | - } | |
134 | - | |
135 | - private void fetchPluginInfo() { | |
136 | - if (!StringUtils.isEmpty(ruleMd.getPluginToken())) { | |
137 | - PluginMetaData pluginMd = systemContext.getPluginService().findPluginByApiToken(ruleMd.getPluginToken()); | |
138 | - pluginTenantId = pluginMd.getTenantId(); | |
139 | - pluginId = pluginMd.getId(); | |
140 | - } | |
141 | - } | |
142 | - | |
143 | - protected void onRuleProcessingMsg(ActorContext context, RuleProcessingMsg msg) throws RuleException { | |
144 | - if (state != ComponentLifecycleState.ACTIVE) { | |
145 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_ACTIVE_RULES); | |
146 | - return; | |
147 | - } | |
148 | - ChainProcessingContext chainCtx = msg.getCtx(); | |
149 | - ToDeviceActorMsg inMsg = chainCtx.getInMsg(); | |
150 | - | |
151 | - ruleCtx.update(inMsg, chainCtx.getDeviceMetaData()); | |
152 | - | |
153 | - logger.debug("[{}] Going to filter in msg: {}", entityId, inMsg); | |
154 | - for (RuleFilter filter : filters) { | |
155 | - if (!filter.filter(ruleCtx, inMsg)) { | |
156 | - logger.debug("[{}] In msg is NOT valid for processing by current rule: {}", entityId, inMsg); | |
157 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_FILTERS_MATCHED); | |
158 | - return; | |
159 | - } | |
160 | - } | |
161 | - RuleProcessingMetaData inMsgMd; | |
162 | - if (processor != null) { | |
163 | - logger.debug("[{}] Going to process in msg: {}", entityId, inMsg); | |
164 | - inMsgMd = processor.process(ruleCtx, inMsg); | |
165 | - } else { | |
166 | - inMsgMd = new RuleProcessingMetaData(); | |
167 | - } | |
168 | - logger.debug("[{}] Going to convert in msg: {}", entityId, inMsg); | |
169 | - if (action != null) { | |
170 | - Optional<RuleToPluginMsg<?>> ruleToPluginMsgOptional = action.convert(ruleCtx, inMsg, inMsgMd); | |
171 | - if (ruleToPluginMsgOptional.isPresent()) { | |
172 | - RuleToPluginMsg<?> ruleToPluginMsg = ruleToPluginMsgOptional.get(); | |
173 | - logger.debug("[{}] Device msg is converted to: {}", entityId, ruleToPluginMsg); | |
174 | - context.parent().tell(new RuleToPluginMsgWrapper(pluginTenantId, pluginId, tenantId, entityId, ruleToPluginMsg), context.self()); | |
175 | - if (action.isOneWayAction()) { | |
176 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_TWO_WAY_ACTIONS); | |
177 | - return; | |
178 | - } else { | |
179 | - pendingMsgMap.put(ruleToPluginMsg.getUid(), msg); | |
180 | - scheduleMsgWithDelay(context, new RuleToPluginTimeoutMsg(ruleToPluginMsg.getUid()), systemContext.getPluginProcessingTimeout()); | |
181 | - return; | |
182 | - } | |
183 | - } | |
184 | - } | |
185 | - logger.debug("[{}] Nothing to send to plugin: {}", entityId, pluginId); | |
186 | - pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_TWO_WAY_ACTIONS); | |
187 | - } | |
188 | - | |
189 | - void onPluginMsg(ActorContext context, PluginToRuleMsg<?> msg) { | |
190 | - RuleProcessingMsg pendingMsg = pendingMsgMap.remove(msg.getUid()); | |
191 | - if (pendingMsg != null) { | |
192 | - ChainProcessingContext ctx = pendingMsg.getCtx(); | |
193 | - Optional<ToDeviceMsg> ruleResponseOptional = action.convert(msg); | |
194 | - if (ruleResponseOptional.isPresent()) { | |
195 | - ctx.mergeResponse(ruleResponseOptional.get()); | |
196 | - pushToNextRule(context, ctx, null); | |
197 | - } else { | |
198 | - pushToNextRule(context, ctx, RuleEngineError.NO_RESPONSE_FROM_ACTIONS); | |
199 | - } | |
200 | - } else { | |
201 | - logger.warning("[{}] Processing timeout detected: [{}]", entityId, msg.getUid()); | |
202 | - } | |
203 | - } | |
204 | - | |
205 | - void onTimeoutMsg(ActorContext context, RuleToPluginTimeoutMsg msg) { | |
206 | - RuleProcessingMsg pendingMsg = pendingMsgMap.remove(msg.getMsgId()); | |
207 | - if (pendingMsg != null) { | |
208 | - logger.debug("[{}] Processing timeout detected [{}]: {}", entityId, msg.getMsgId(), pendingMsg); | |
209 | - ChainProcessingContext ctx = pendingMsg.getCtx(); | |
210 | - pushToNextRule(context, ctx, RuleEngineError.PLUGIN_TIMEOUT); | |
211 | - } | |
212 | - } | |
213 | - | |
214 | - private void pushToNextRule(ActorContext context, ChainProcessingContext ctx, RuleEngineError error) { | |
215 | - if (error != null) { | |
216 | - ctx = ctx.withError(error); | |
217 | - } | |
218 | - if (ctx.isFailure()) { | |
219 | - logger.debug("[{}][{}] Forwarding processing chain to device actor due to failure.", ruleMd.getId(), ctx.getInMsg().getDeviceId()); | |
220 | - ctx.getDeviceActor().tell(new RulesProcessedMsg(ctx), ActorRef.noSender()); | |
221 | - } else if (!ctx.hasNext()) { | |
222 | - logger.debug("[{}][{}] Forwarding processing chain to device actor due to end of chain.", ruleMd.getId(), ctx.getInMsg().getDeviceId()); | |
223 | - ctx.getDeviceActor().tell(new RulesProcessedMsg(ctx), ActorRef.noSender()); | |
224 | - } else { | |
225 | - logger.debug("[{}][{}] Forwarding processing chain to next rule actor.", ruleMd.getId(), ctx.getInMsg().getDeviceId()); | |
226 | - ChainProcessingContext nextTask = ctx.getNext(); | |
227 | - nextTask.getCurrentActor().tell(new RuleProcessingMsg(nextTask), context.self()); | |
228 | - } | |
229 | - } | |
230 | - | |
231 | - @Override | |
232 | - public void onCreated(ActorContext context) { | |
233 | - logger.info("[{}] Going to process onCreated rule.", entityId); | |
234 | - } | |
235 | - | |
236 | - @Override | |
237 | - public void onUpdate(ActorContext context) throws RuleException { | |
238 | - RuleMetaData oldRuleMd = ruleMd; | |
239 | - ruleMd = systemContext.getRuleService().findRuleById(entityId); | |
240 | - logger.info("[{}] Rule configuration was updated from {} to {}.", entityId, oldRuleMd, ruleMd); | |
241 | - try { | |
242 | - fetchPluginInfo(); | |
243 | - if (filters == null || !Objects.equals(oldRuleMd.getFilters(), ruleMd.getFilters())) { | |
244 | - logger.info("[{}] Rule filters require restart due to json change from {} to {}.", | |
245 | - entityId, mapper.writeValueAsString(oldRuleMd.getFilters()), mapper.writeValueAsString(ruleMd.getFilters())); | |
246 | - stopFilters(); | |
247 | - initFilters(); | |
248 | - } | |
249 | - if (processor == null || !Objects.equals(oldRuleMd.getProcessor(), ruleMd.getProcessor())) { | |
250 | - logger.info("[{}] Rule processor require restart due to configuration change.", entityId); | |
251 | - stopProcessor(); | |
252 | - initProcessor(); | |
253 | - } | |
254 | - if (action == null || !Objects.equals(oldRuleMd.getAction(), ruleMd.getAction())) { | |
255 | - logger.info("[{}] Rule action require restart due to configuration change.", entityId); | |
256 | - stopAction(); | |
257 | - initAction(); | |
258 | - } | |
259 | - } catch (RuntimeException e) { | |
260 | - throw new RuleInitializationException("Unknown runtime exception!", e); | |
261 | - } catch (InstantiationException e) { | |
262 | - throw new RuleInitializationException("No default constructor for rule implementation!", e); | |
263 | - } catch (IllegalAccessException e) { | |
264 | - throw new RuleInitializationException("Illegal Access Exception during rule initialization!", e); | |
265 | - } catch (ClassNotFoundException e) { | |
266 | - throw new RuleInitializationException("Rule Class not found!", e); | |
267 | - } catch (JsonProcessingException e) { | |
268 | - throw new RuleInitializationException("Rule configuration is invalid!", e); | |
269 | - } catch (Exception e) { | |
270 | - throw new RuleInitializationException(e.getMessage(), e); | |
271 | - } | |
272 | - } | |
273 | - | |
274 | - @Override | |
275 | - public void onActivate(ActorContext context) throws Exception { | |
276 | - logger.info("[{}] Going to process onActivate rule.", entityId); | |
277 | - this.state = ComponentLifecycleState.ACTIVE; | |
278 | - if (filters != null) { | |
279 | - filters.forEach(RuleLifecycleComponent::resume); | |
280 | - if (processor != null) { | |
281 | - processor.resume(); | |
282 | - } else { | |
283 | - initProcessor(); | |
284 | - } | |
285 | - if (action != null) { | |
286 | - action.resume(); | |
287 | - } | |
288 | - logger.info("[{}] Rule resumed.", entityId); | |
289 | - } else { | |
290 | - start(); | |
291 | - } | |
292 | - } | |
293 | - | |
294 | - @Override | |
295 | - public void onSuspend(ActorContext context) { | |
296 | - logger.info("[{}] Going to process onSuspend rule.", entityId); | |
297 | - this.state = ComponentLifecycleState.SUSPENDED; | |
298 | - if (filters != null) { | |
299 | - filters.forEach(f -> f.suspend()); | |
300 | - } | |
301 | - if (processor != null) { | |
302 | - processor.suspend(); | |
303 | - } | |
304 | - if (action != null) { | |
305 | - action.suspend(); | |
306 | - } | |
307 | - } | |
308 | - | |
309 | - @Override | |
310 | - public void onStop(ActorContext context) { | |
311 | - logger.info("[{}] Going to process onStop rule.", entityId); | |
312 | - onStop(); | |
313 | - scheduleMsgWithDelay(context, new RuleTerminationMsg(entityId), systemContext.getRuleActorTerminationDelay()); | |
314 | - } | |
315 | - | |
316 | - private void onStop() { | |
317 | - this.state = ComponentLifecycleState.SUSPENDED; | |
318 | - stopFilters(); | |
319 | - stopProcessor(); | |
320 | - stopAction(); | |
321 | - } | |
322 | - | |
323 | - @Override | |
324 | - public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | |
325 | - //Do nothing | |
326 | - } | |
327 | - | |
328 | - private void stopAction() { | |
329 | - if (action != null) { | |
330 | - action.stop(); | |
331 | - } | |
332 | - } | |
333 | - | |
334 | - private void stopProcessor() { | |
335 | - if (processor != null) { | |
336 | - processor.stop(); | |
337 | - } | |
338 | - } | |
339 | - | |
340 | - private void stopFilters() { | |
341 | - if (filters != null) { | |
342 | - filters.forEach(f -> f.stop()); | |
343 | - } | |
344 | - } | |
345 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMetaData.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors.rule; | |
17 | - | |
18 | -import java.util.Comparator; | |
19 | - | |
20 | -import org.thingsboard.server.common.data.id.RuleId; | |
21 | - | |
22 | -import akka.actor.ActorRef; | |
23 | - | |
24 | -public class RuleActorMetaData { | |
25 | - | |
26 | - private final RuleId ruleId; | |
27 | - private final boolean systemRule; | |
28 | - private final int weight; | |
29 | - private final ActorRef actorRef; | |
30 | - | |
31 | - public static final Comparator<RuleActorMetaData> RULE_ACTOR_MD_COMPARATOR = new Comparator<RuleActorMetaData>() { | |
32 | - | |
33 | - @Override | |
34 | - public int compare(RuleActorMetaData r1, RuleActorMetaData r2) { | |
35 | - if (r1.isSystemRule() && !r2.isSystemRule()) { | |
36 | - return 1; | |
37 | - } else if (!r1.isSystemRule() && r2.isSystemRule()) { | |
38 | - return -1; | |
39 | - } else { | |
40 | - return Integer.compare(r2.getWeight(), r1.getWeight()); | |
41 | - } | |
42 | - } | |
43 | - }; | |
44 | - | |
45 | - public static RuleActorMetaData systemRule(RuleId ruleId, int weight, ActorRef actorRef) { | |
46 | - return new RuleActorMetaData(ruleId, true, weight, actorRef); | |
47 | - } | |
48 | - | |
49 | - public static RuleActorMetaData tenantRule(RuleId ruleId, int weight, ActorRef actorRef) { | |
50 | - return new RuleActorMetaData(ruleId, false, weight, actorRef); | |
51 | - } | |
52 | - | |
53 | - private RuleActorMetaData(RuleId ruleId, boolean systemRule, int weight, ActorRef actorRef) { | |
54 | - super(); | |
55 | - this.ruleId = ruleId; | |
56 | - this.systemRule = systemRule; | |
57 | - this.weight = weight; | |
58 | - this.actorRef = actorRef; | |
59 | - } | |
60 | - | |
61 | - public RuleId getRuleId() { | |
62 | - return ruleId; | |
63 | - } | |
64 | - | |
65 | - public boolean isSystemRule() { | |
66 | - return systemRule; | |
67 | - } | |
68 | - | |
69 | - public int getWeight() { | |
70 | - return weight; | |
71 | - } | |
72 | - | |
73 | - public ActorRef getActorRef() { | |
74 | - return actorRef; | |
75 | - } | |
76 | - | |
77 | - @Override | |
78 | - public int hashCode() { | |
79 | - final int prime = 31; | |
80 | - int result = 1; | |
81 | - result = prime * result + ((ruleId == null) ? 0 : ruleId.hashCode()); | |
82 | - return result; | |
83 | - } | |
84 | - | |
85 | - @Override | |
86 | - public boolean equals(Object obj) { | |
87 | - if (this == obj) | |
88 | - return true; | |
89 | - if (obj == null) | |
90 | - return false; | |
91 | - if (getClass() != obj.getClass()) | |
92 | - return false; | |
93 | - RuleActorMetaData other = (RuleActorMetaData) obj; | |
94 | - if (ruleId == null) { | |
95 | - if (other.ruleId != null) | |
96 | - return false; | |
97 | - } else if (!ruleId.equals(other.ruleId)) | |
98 | - return false; | |
99 | - return true; | |
100 | - } | |
101 | - | |
102 | - @Override | |
103 | - public String toString() { | |
104 | - return "RuleActorMetaData [ruleId=" + ruleId + ", systemRule=" + systemRule + ", weight=" + weight + ", actorRef=" + actorRef + "]"; | |
105 | - } | |
106 | - | |
107 | -} |
application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingContext.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.server.actors.rule; | |
17 | - | |
18 | -import com.google.common.util.concurrent.ListenableFuture; | |
19 | -import org.thingsboard.server.actors.ActorSystemContext; | |
20 | -import org.thingsboard.server.common.data.Event; | |
21 | -import org.thingsboard.server.common.data.alarm.Alarm; | |
22 | -import org.thingsboard.server.common.data.alarm.AlarmId; | |
23 | -import org.thingsboard.server.common.data.id.*; | |
24 | -import org.thingsboard.server.dao.alarm.AlarmService; | |
25 | -import org.thingsboard.server.dao.event.EventService; | |
26 | -import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
27 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
28 | -import org.thingsboard.server.extensions.api.device.DeviceMetaData; | |
29 | -import org.thingsboard.server.extensions.api.rules.RuleContext; | |
30 | - | |
31 | -import java.util.Optional; | |
32 | -import java.util.concurrent.ExecutionException; | |
33 | - | |
34 | -public class RuleProcessingContext implements RuleContext { | |
35 | - | |
36 | - private final TimeseriesService tsService; | |
37 | - private final EventService eventService; | |
38 | - private final AlarmService alarmService; | |
39 | - private final RuleId ruleId; | |
40 | - private TenantId tenantId; | |
41 | - private CustomerId customerId; | |
42 | - private DeviceId deviceId; | |
43 | - private DeviceMetaData deviceMetaData; | |
44 | - | |
45 | - RuleProcessingContext(ActorSystemContext systemContext, RuleId ruleId) { | |
46 | - this.tsService = systemContext.getTsService(); | |
47 | - this.eventService = systemContext.getEventService(); | |
48 | - this.alarmService = systemContext.getAlarmService(); | |
49 | - this.ruleId = ruleId; | |
50 | - } | |
51 | - | |
52 | - void update(ToDeviceActorMsg toDeviceActorMsg, DeviceMetaData deviceMetaData) { | |
53 | - this.tenantId = toDeviceActorMsg.getTenantId(); | |
54 | - this.customerId = toDeviceActorMsg.getCustomerId(); | |
55 | - this.deviceId = toDeviceActorMsg.getDeviceId(); | |
56 | - this.deviceMetaData = deviceMetaData; | |
57 | - } | |
58 | - | |
59 | - @Override | |
60 | - public RuleId getRuleId() { | |
61 | - return ruleId; | |
62 | - } | |
63 | - | |
64 | - @Override | |
65 | - public DeviceMetaData getDeviceMetaData() { | |
66 | - return deviceMetaData; | |
67 | - } | |
68 | - | |
69 | - @Override | |
70 | - public Event save(Event event) { | |
71 | - checkEvent(event); | |
72 | - return eventService.save(event); | |
73 | - } | |
74 | - | |
75 | - @Override | |
76 | - public Optional<Event> saveIfNotExists(Event event) { | |
77 | - checkEvent(event); | |
78 | - return eventService.saveIfNotExists(event); | |
79 | - } | |
80 | - | |
81 | - @Override | |
82 | - public Optional<Event> findEvent(String eventType, String eventUid) { | |
83 | - return eventService.findEvent(tenantId, deviceId, eventType, eventUid); | |
84 | - } | |
85 | - | |
86 | - @Override | |
87 | - public Alarm createOrUpdateAlarm(Alarm alarm) { | |
88 | - alarm.setTenantId(tenantId); | |
89 | - return alarmService.createOrUpdateAlarm(alarm); | |
90 | - } | |
91 | - | |
92 | - public Optional<Alarm> findLatestAlarm(EntityId originator, String alarmType) { | |
93 | - try { | |
94 | - return Optional.ofNullable(alarmService.findLatestByOriginatorAndType(tenantId, originator, alarmType).get()); | |
95 | - } catch (InterruptedException | ExecutionException e) { | |
96 | - throw new RuntimeException("Failed to lookup alarm!", e); | |
97 | - } | |
98 | - } | |
99 | - | |
100 | - @Override | |
101 | - public ListenableFuture<Boolean> clearAlarm(AlarmId alarmId, long clearTs) { | |
102 | - return alarmService.clearAlarm(alarmId, clearTs); | |
103 | - } | |
104 | - | |
105 | - private void checkEvent(Event event) { | |
106 | - if (event.getTenantId() == null) { | |
107 | - event.setTenantId(tenantId); | |
108 | - } else if (!tenantId.equals(event.getTenantId())) { | |
109 | - throw new IllegalArgumentException("Invalid Tenant id!"); | |
110 | - } | |
111 | - if (event.getEntityId() == null) { | |
112 | - event.setEntityId(deviceId); | |
113 | - } | |
114 | - } | |
115 | -} |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import akka.actor.ActorRef; | |
19 | +import akka.actor.Cancellable; | |
20 | +import com.google.common.base.Function; | |
21 | +import org.thingsboard.rule.engine.api.*; | |
22 | +import org.thingsboard.server.actors.ActorSystemContext; | |
23 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
24 | +import org.thingsboard.server.common.data.id.TenantId; | |
25 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
26 | +import org.thingsboard.server.common.msg.TbMsg; | |
27 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
28 | +import org.thingsboard.server.dao.alarm.AlarmService; | |
29 | +import org.thingsboard.server.dao.asset.AssetService; | |
30 | +import org.thingsboard.server.dao.attributes.AttributesService; | |
31 | +import org.thingsboard.server.dao.customer.CustomerService; | |
32 | +import org.thingsboard.server.dao.device.DeviceService; | |
33 | +import org.thingsboard.server.dao.plugin.PluginService; | |
34 | +import org.thingsboard.server.dao.relation.RelationService; | |
35 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
36 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
37 | +import org.thingsboard.server.dao.user.UserService; | |
38 | +import org.thingsboard.server.service.script.NashornJsEngine; | |
39 | +import scala.concurrent.duration.Duration; | |
40 | + | |
41 | +import java.util.List; | |
42 | +import java.util.Set; | |
43 | +import java.util.concurrent.TimeUnit; | |
44 | + | |
45 | +/** | |
46 | + * Created by ashvayka on 19.03.18. | |
47 | + */ | |
48 | +class DefaultTbContext implements TbContext { | |
49 | + | |
50 | + private static final Function<? super List<Void>, ? extends Void> LIST_VOID_FUNCTION = v -> null; | |
51 | + private final ActorSystemContext mainCtx; | |
52 | + private final RuleNodeCtx nodeCtx; | |
53 | + | |
54 | + public DefaultTbContext(ActorSystemContext mainCtx, RuleNodeCtx nodeCtx) { | |
55 | + this.mainCtx = mainCtx; | |
56 | + this.nodeCtx = nodeCtx; | |
57 | + } | |
58 | + | |
59 | + @Override | |
60 | + public void tellNext(TbMsg msg) { | |
61 | + tellNext(msg, (String) null); | |
62 | + } | |
63 | + | |
64 | + @Override | |
65 | + public void tellNext(TbMsg msg, String relationType) { | |
66 | + if (nodeCtx.getSelf().isDebugMode()) { | |
67 | + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg); | |
68 | + } | |
69 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationType, msg), nodeCtx.getSelfActor()); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public void tellSelf(TbMsg msg, long delayMs) { | |
74 | + //TODO: add persistence layer | |
75 | + scheduleMsgWithDelay(new RuleNodeToSelfMsg(msg), delayMs, nodeCtx.getSelfActor()); | |
76 | + } | |
77 | + | |
78 | + private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) { | |
79 | + mainCtx.getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, mainCtx.getActorSystem().dispatcher(), nodeCtx.getSelfActor()); | |
80 | + } | |
81 | + | |
82 | + @Override | |
83 | + public void tellOthers(TbMsg msg) { | |
84 | + throw new RuntimeException("Not Implemented!"); | |
85 | + } | |
86 | + | |
87 | + @Override | |
88 | + public void tellSibling(TbMsg msg, ServerAddress address) { | |
89 | + throw new RuntimeException("Not Implemented!"); | |
90 | + } | |
91 | + | |
92 | + @Override | |
93 | + public void spawn(TbMsg msg) { | |
94 | + throw new RuntimeException("Not Implemented!"); | |
95 | + } | |
96 | + | |
97 | + @Override | |
98 | + public void ack(TbMsg msg) { | |
99 | + | |
100 | + } | |
101 | + | |
102 | + @Override | |
103 | + public void tellError(TbMsg msg, Throwable th) { | |
104 | + if (nodeCtx.getSelf().isDebugMode()) { | |
105 | + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, th); | |
106 | + } | |
107 | + nodeCtx.getSelfActor().tell(new RuleNodeToSelfErrorMsg(msg, th), nodeCtx.getSelfActor()); | |
108 | + } | |
109 | + | |
110 | + @Override | |
111 | + public void updateSelf(RuleNode self) { | |
112 | + nodeCtx.setSelf(self); | |
113 | + } | |
114 | + | |
115 | + @Override | |
116 | + public RuleNodeId getSelfId() { | |
117 | + return nodeCtx.getSelf().getId(); | |
118 | + } | |
119 | + | |
120 | + @Override | |
121 | + public TenantId getTenantId() { | |
122 | + return nodeCtx.getTenantId(); | |
123 | + } | |
124 | + | |
125 | + @Override | |
126 | + public void tellNext(TbMsg msg, Set<String> relationTypes) { | |
127 | + relationTypes.forEach(type -> tellNext(msg, type)); | |
128 | + } | |
129 | + | |
130 | + @Override | |
131 | + public ListeningExecutor getJsExecutor() { | |
132 | + return mainCtx.getJsExecutor(); | |
133 | + } | |
134 | + | |
135 | + @Override | |
136 | + public ListeningExecutor getMailExecutor() { | |
137 | + return mainCtx.getMailExecutor(); | |
138 | + } | |
139 | + | |
140 | + @Override | |
141 | + public ListeningExecutor getDbCallbackExecutor() { | |
142 | + return mainCtx.getDbCallbackExecutor(); | |
143 | + } | |
144 | + | |
145 | + @Override | |
146 | + public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) { | |
147 | + return new NashornJsEngine(script, functionName, argNames); | |
148 | + } | |
149 | + | |
150 | + @Override | |
151 | + public AttributesService getAttributesService() { | |
152 | + return mainCtx.getAttributesService(); | |
153 | + } | |
154 | + | |
155 | + @Override | |
156 | + public CustomerService getCustomerService() { | |
157 | + return mainCtx.getCustomerService(); | |
158 | + } | |
159 | + | |
160 | + @Override | |
161 | + public UserService getUserService() { | |
162 | + return mainCtx.getUserService(); | |
163 | + } | |
164 | + | |
165 | + @Override | |
166 | + public PluginService getPluginService() { | |
167 | + return mainCtx.getPluginService(); | |
168 | + } | |
169 | + | |
170 | + @Override | |
171 | + public AssetService getAssetService() { | |
172 | + return mainCtx.getAssetService(); | |
173 | + } | |
174 | + | |
175 | + @Override | |
176 | + public DeviceService getDeviceService() { | |
177 | + return mainCtx.getDeviceService(); | |
178 | + } | |
179 | + | |
180 | + @Override | |
181 | + public AlarmService getAlarmService() { | |
182 | + return mainCtx.getAlarmService(); | |
183 | + } | |
184 | + | |
185 | + @Override | |
186 | + public RuleChainService getRuleChainService() { | |
187 | + return mainCtx.getRuleChainService(); | |
188 | + } | |
189 | + | |
190 | + @Override | |
191 | + public TimeseriesService getTimeseriesService() { | |
192 | + return mainCtx.getTsService(); | |
193 | + } | |
194 | + | |
195 | + @Override | |
196 | + public RuleEngineTelemetryService getTelemetryService() { | |
197 | + return mainCtx.getTsSubService(); | |
198 | + } | |
199 | + | |
200 | + @Override | |
201 | + public RelationService getRelationService() { | |
202 | + return mainCtx.getRelationService(); | |
203 | + } | |
204 | + | |
205 | + @Override | |
206 | + public MailService getMailService() { | |
207 | + return mainCtx.getMailService(); | |
208 | + } | |
209 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import akka.actor.OneForOneStrategy; | |
19 | +import akka.actor.SupervisorStrategy; | |
20 | +import org.thingsboard.server.actors.ActorSystemContext; | |
21 | +import org.thingsboard.server.actors.service.ComponentActor; | |
22 | +import org.thingsboard.server.actors.service.ContextBasedCreator; | |
23 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
24 | +import org.thingsboard.server.common.data.id.TenantId; | |
25 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
26 | +import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | |
27 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
28 | +import scala.concurrent.duration.Duration; | |
29 | + | |
30 | +public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> { | |
31 | + | |
32 | + private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) { | |
33 | + super(systemContext, tenantId, ruleChainId); | |
34 | + setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext, | |
35 | + logger, context().parent(), context().self())); | |
36 | + } | |
37 | + | |
38 | + @Override | |
39 | + protected boolean process(TbActorMsg msg) { | |
40 | + switch (msg.getMsgType()) { | |
41 | + case COMPONENT_LIFE_CYCLE_MSG: | |
42 | + onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
43 | + break; | |
44 | + case SERVICE_TO_RULE_ENGINE_MSG: | |
45 | + processor.onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | |
46 | + break; | |
47 | + case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG: | |
48 | + processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg); | |
49 | + break; | |
50 | + default: | |
51 | + return false; | |
52 | + } | |
53 | + return true; | |
54 | + } | |
55 | + | |
56 | + public static class ActorCreator extends ContextBasedCreator<RuleChainActor> { | |
57 | + private static final long serialVersionUID = 1L; | |
58 | + | |
59 | + private final TenantId tenantId; | |
60 | + private final RuleChainId ruleChainId; | |
61 | + | |
62 | + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId pluginId) { | |
63 | + super(context); | |
64 | + this.tenantId = tenantId; | |
65 | + this.ruleChainId = pluginId; | |
66 | + } | |
67 | + | |
68 | + @Override | |
69 | + public RuleChainActor create() throws Exception { | |
70 | + return new RuleChainActor(context, tenantId, ruleChainId); | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + @Override | |
75 | + protected long getErrorPersistFrequency() { | |
76 | + return systemContext.getRuleChainErrorPersistFrequency(); | |
77 | + } | |
78 | + | |
79 | + @Override | |
80 | + public SupervisorStrategy supervisorStrategy() { | |
81 | + return strategy; | |
82 | + } | |
83 | + | |
84 | + private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> { | |
85 | + logAndPersist("Unknown Failure", ActorSystemContext.toException(t)); | |
86 | + return SupervisorStrategy.resume(); | |
87 | + }); | |
88 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import akka.actor.ActorContext; | |
19 | +import akka.actor.ActorRef; | |
20 | +import akka.actor.Props; | |
21 | +import akka.event.LoggingAdapter; | |
22 | +import org.thingsboard.server.actors.ActorSystemContext; | |
23 | +import org.thingsboard.server.actors.service.DefaultActorService; | |
24 | +import org.thingsboard.server.actors.shared.ComponentMsgProcessor; | |
25 | +import org.thingsboard.server.common.data.EntityType; | |
26 | +import org.thingsboard.server.common.data.id.EntityId; | |
27 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
28 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
29 | +import org.thingsboard.server.common.data.id.TenantId; | |
30 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
31 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
32 | +import org.thingsboard.server.common.data.relation.EntityRelation; | |
33 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
34 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
35 | +import org.thingsboard.server.common.msg.TbMsg; | |
36 | +import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
37 | +import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | |
38 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
39 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
40 | + | |
41 | +import java.util.ArrayList; | |
42 | +import java.util.HashMap; | |
43 | +import java.util.List; | |
44 | +import java.util.Map; | |
45 | +import java.util.Set; | |
46 | +import java.util.stream.Collectors; | |
47 | + | |
48 | +/** | |
49 | + * @author Andrew Shvayka | |
50 | + */ | |
51 | +public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { | |
52 | + | |
53 | + private final ActorRef parent; | |
54 | + private final ActorRef self; | |
55 | + private final Map<RuleNodeId, RuleNodeCtx> nodeActors; | |
56 | + private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes; | |
57 | + private final RuleChainService service; | |
58 | + | |
59 | + private RuleNodeId firstId; | |
60 | + private RuleNodeCtx firstNode; | |
61 | + | |
62 | + RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext | |
63 | + , LoggingAdapter logger, ActorRef parent, ActorRef self) { | |
64 | + super(systemContext, logger, tenantId, ruleChainId); | |
65 | + this.parent = parent; | |
66 | + this.self = self; | |
67 | + this.nodeActors = new HashMap<>(); | |
68 | + this.nodeRoutes = new HashMap<>(); | |
69 | + this.service = systemContext.getRuleChainService(); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + 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)); | |
80 | + } | |
81 | + initRoutes(ruleChain, ruleNodeList); | |
82 | + } | |
83 | + | |
84 | + @Override | |
85 | + public void onUpdate(ActorContext context) throws Exception { | |
86 | + RuleChain ruleChain = service.findRuleChainById(entityId); | |
87 | + List<RuleNode> ruleNodeList = service.getRuleChainNodes(entityId); | |
88 | + | |
89 | + for (RuleNode ruleNode : ruleNodeList) { | |
90 | + RuleNodeCtx existing = nodeActors.get(ruleNode.getId()); | |
91 | + if (existing == null) { | |
92 | + ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); | |
93 | + nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); | |
94 | + } else { | |
95 | + existing.setSelf(ruleNode); | |
96 | + existing.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self); | |
97 | + } | |
98 | + } | |
99 | + | |
100 | + Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet()); | |
101 | + List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList()); | |
102 | + removedRules.forEach(ruleNodeId -> { | |
103 | + RuleNodeCtx removed = nodeActors.remove(ruleNodeId); | |
104 | + removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self); | |
105 | + }); | |
106 | + | |
107 | + initRoutes(ruleChain, ruleNodeList); | |
108 | + } | |
109 | + | |
110 | + @Override | |
111 | + public void stop(ActorContext context) throws Exception { | |
112 | + nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(context::stop); | |
113 | + nodeActors.clear(); | |
114 | + nodeRoutes.clear(); | |
115 | + context.stop(self); | |
116 | + } | |
117 | + | |
118 | + @Override | |
119 | + public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | |
120 | + | |
121 | + } | |
122 | + | |
123 | + private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) { | |
124 | + String dispatcherName = tenantId.getId().equals(EntityId.NULL_UUID) ? | |
125 | + DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME : DefaultActorService.TENANT_RULE_DISPATCHER_NAME; | |
126 | + return context.actorOf( | |
127 | + Props.create(new RuleNodeActor.ActorCreator(systemContext, tenantId, entityId, ruleNode.getId())) | |
128 | + .withDispatcher(dispatcherName), ruleNode.getId().toString()); | |
129 | + } | |
130 | + | |
131 | + private void initRoutes(RuleChain ruleChain, List<RuleNode> ruleNodeList) { | |
132 | + nodeRoutes.clear(); | |
133 | + // Populating the routes map; | |
134 | + for (RuleNode ruleNode : ruleNodeList) { | |
135 | + List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId()); | |
136 | + for (EntityRelation relation : relations) { | |
137 | + if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { | |
138 | + RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId())); | |
139 | + if (ruleNodeCtx == null) { | |
140 | + throw new IllegalArgumentException("Rule Node [" + relation.getFrom() + "] has invalid relation to Rule node [" + relation.getTo() + "]"); | |
141 | + } | |
142 | + } | |
143 | + nodeRoutes.computeIfAbsent(ruleNode.getId(), k -> new ArrayList<>()) | |
144 | + .add(new RuleNodeRelation(ruleNode.getId(), relation.getTo(), relation.getType())); | |
145 | + } | |
146 | + } | |
147 | + | |
148 | + firstId = ruleChain.getFirstRuleNodeId(); | |
149 | + firstNode = nodeActors.get(ruleChain.getFirstRuleNodeId()); | |
150 | + state = ComponentLifecycleState.ACTIVE; | |
151 | + } | |
152 | + | |
153 | + void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) { | |
154 | + checkActive(); | |
155 | + TbMsg tbMsg = envelope.getTbMsg(); | |
156 | + //TODO: push to queue and act on ack in async way | |
157 | + pushMsgToNode(firstNode, tbMsg); | |
158 | + } | |
159 | + | |
160 | + void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { | |
161 | + checkActive(); | |
162 | + RuleNodeId originator = envelope.getOriginator(); | |
163 | + String targetRelationType = envelope.getRelationType(); | |
164 | + List<RuleNodeRelation> relations = nodeRoutes.get(originator); | |
165 | + if (relations == null) { | |
166 | + return; | |
167 | + } | |
168 | + boolean copy = relations.size() > 1; | |
169 | + for (RuleNodeRelation relation : relations) { | |
170 | + TbMsg msg = envelope.getMsg(); | |
171 | + if (copy) { | |
172 | + msg = msg.copy(); | |
173 | + } | |
174 | + if (targetRelationType == null || targetRelationType.equalsIgnoreCase(relation.getType())) { | |
175 | + switch (relation.getOut().getEntityType()) { | |
176 | + case RULE_NODE: | |
177 | + RuleNodeId targetRuleNodeId = new RuleNodeId(relation.getOut().getId()); | |
178 | + RuleNodeCtx targetRuleNode = nodeActors.get(targetRuleNodeId); | |
179 | + pushMsgToNode(targetRuleNode, msg); | |
180 | + break; | |
181 | + case RULE_CHAIN: | |
182 | +// TODO: implement | |
183 | + break; | |
184 | + } | |
185 | + } | |
186 | + } | |
187 | + } | |
188 | + | |
189 | + private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg) { | |
190 | + if (nodeCtx != null) { | |
191 | + nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self); | |
192 | + } | |
193 | + } | |
194 | + | |
195 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import akka.actor.ActorRef; | |
19 | +import org.thingsboard.server.actors.ActorSystemContext; | |
20 | +import org.thingsboard.server.actors.service.ContextAwareActor; | |
21 | +import org.thingsboard.server.actors.shared.plugin.PluginManager; | |
22 | +import org.thingsboard.server.actors.shared.rulechain.RuleChainManager; | |
23 | +import org.thingsboard.server.common.data.id.EntityId; | |
24 | +import org.thingsboard.server.common.data.id.PluginId; | |
25 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
26 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
27 | + | |
28 | +/** | |
29 | + * Created by ashvayka on 15.03.18. | |
30 | + */ | |
31 | +public abstract class RuleChainManagerActor extends ContextAwareActor { | |
32 | + | |
33 | + protected final RuleChainManager ruleChainManager; | |
34 | + protected final PluginManager pluginManager; | |
35 | + protected final RuleChainService ruleChainService; | |
36 | + | |
37 | + public RuleChainManagerActor(ActorSystemContext systemContext, RuleChainManager ruleChainManager, PluginManager pluginManager) { | |
38 | + super(systemContext); | |
39 | + this.ruleChainManager = ruleChainManager; | |
40 | + this.pluginManager = pluginManager; | |
41 | + this.ruleChainService = systemContext.getRuleChainService(); | |
42 | + } | |
43 | + | |
44 | + protected void initRuleChains() { | |
45 | + pluginManager.init(this.context()); | |
46 | + ruleChainManager.init(this.context()); | |
47 | + } | |
48 | + | |
49 | + protected ActorRef getEntityActorRef(EntityId entityId) { | |
50 | + ActorRef target = null; | |
51 | + switch (entityId.getEntityType()) { | |
52 | + case PLUGIN: | |
53 | + target = pluginManager.getOrCreateActor(this.context(), (PluginId) entityId); | |
54 | + break; | |
55 | + case RULE_CHAIN: | |
56 | + target = ruleChainManager.getOrCreateActor(this.context(), (RuleChainId) entityId); | |
57 | + break; | |
58 | + } | |
59 | + return target; | |
60 | + } | |
61 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleNodeMsg.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.rule.engine.api.TbContext; | |
20 | +import org.thingsboard.server.common.msg.MsgType; | |
21 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
22 | +import org.thingsboard.server.common.msg.TbMsg; | |
23 | + | |
24 | +/** | |
25 | + * Created by ashvayka on 19.03.18. | |
26 | + */ | |
27 | +@Data | |
28 | +final class RuleChainToRuleNodeMsg implements TbActorMsg { | |
29 | + | |
30 | + private final TbContext ctx; | |
31 | + private final TbMsg msg; | |
32 | + | |
33 | + @Override | |
34 | + public MsgType getMsgType() { | |
35 | + return MsgType.RULE_CHAIN_TO_RULE_MSG; | |
36 | + } | |
37 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import org.thingsboard.server.actors.ActorSystemContext; | |
19 | +import org.thingsboard.server.actors.service.ComponentActor; | |
20 | +import org.thingsboard.server.actors.service.ContextBasedCreator; | |
21 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
22 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
23 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
25 | +import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; | |
26 | + | |
27 | +public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> { | |
28 | + | |
29 | + private final RuleChainId ruleChainId; | |
30 | + | |
31 | + private RuleNodeActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { | |
32 | + super(systemContext, tenantId, ruleNodeId); | |
33 | + this.ruleChainId = ruleChainId; | |
34 | + setProcessor(new RuleNodeActorMessageProcessor(tenantId, ruleChainId, ruleNodeId, systemContext, | |
35 | + logger, context().parent(), context().self())); | |
36 | + } | |
37 | + | |
38 | + @Override | |
39 | + protected boolean process(TbActorMsg msg) { | |
40 | + switch (msg.getMsgType()) { | |
41 | + case COMPONENT_LIFE_CYCLE_MSG: | |
42 | + onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
43 | + break; | |
44 | + case RULE_CHAIN_TO_RULE_MSG: | |
45 | + onRuleChainToRuleNodeMsg((RuleChainToRuleNodeMsg) msg); | |
46 | + break; | |
47 | + case RULE_TO_SELF_ERROR_MSG: | |
48 | + onRuleNodeToSelfErrorMsg((RuleNodeToSelfErrorMsg) msg); | |
49 | + break; | |
50 | + case RULE_TO_SELF_MSG: | |
51 | + onRuleNodeToSelfMsg((RuleNodeToSelfMsg) msg); | |
52 | + break; | |
53 | + default: | |
54 | + return false; | |
55 | + } | |
56 | + return true; | |
57 | + } | |
58 | + | |
59 | + private void onRuleNodeToSelfMsg(RuleNodeToSelfMsg msg) { | |
60 | + logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg()); | |
61 | + try { | |
62 | + processor.onRuleToSelfMsg(msg); | |
63 | + increaseMessagesProcessedCount(); | |
64 | + } catch (Exception e) { | |
65 | + logAndPersist("onRuleMsg", e); | |
66 | + } | |
67 | + } | |
68 | + | |
69 | + private void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) { | |
70 | + logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg()); | |
71 | + try { | |
72 | + processor.onRuleChainToRuleNodeMsg(msg); | |
73 | + increaseMessagesProcessedCount(); | |
74 | + } catch (Exception e) { | |
75 | + logAndPersist("onRuleMsg", e); | |
76 | + } | |
77 | + } | |
78 | + | |
79 | + private void onRuleNodeToSelfErrorMsg(RuleNodeToSelfErrorMsg msg) { | |
80 | + logAndPersist("onRuleMsg", ActorSystemContext.toException(msg.getError())); | |
81 | + } | |
82 | + | |
83 | + public static class ActorCreator extends ContextBasedCreator<RuleNodeActor> { | |
84 | + private static final long serialVersionUID = 1L; | |
85 | + | |
86 | + private final TenantId tenantId; | |
87 | + private final RuleChainId ruleChainId; | |
88 | + private final RuleNodeId ruleNodeId; | |
89 | + | |
90 | + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { | |
91 | + super(context); | |
92 | + this.tenantId = tenantId; | |
93 | + this.ruleChainId = ruleChainId; | |
94 | + this.ruleNodeId = ruleNodeId; | |
95 | + | |
96 | + } | |
97 | + | |
98 | + @Override | |
99 | + public RuleNodeActor create() throws Exception { | |
100 | + return new RuleNodeActor(context, tenantId, ruleChainId, ruleNodeId); | |
101 | + } | |
102 | + } | |
103 | + | |
104 | + @Override | |
105 | + protected long getErrorPersistFrequency() { | |
106 | + return systemContext.getRuleNodeErrorPersistFrequency(); | |
107 | + } | |
108 | + | |
109 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import akka.actor.ActorContext; | |
19 | +import akka.actor.ActorRef; | |
20 | +import akka.event.LoggingAdapter; | |
21 | +import org.thingsboard.rule.engine.api.TbContext; | |
22 | +import org.thingsboard.rule.engine.api.TbNode; | |
23 | +import org.thingsboard.rule.engine.api.TbNodeConfiguration; | |
24 | +import org.thingsboard.rule.engine.api.TbNodeException; | |
25 | +import org.thingsboard.server.actors.ActorSystemContext; | |
26 | +import org.thingsboard.server.actors.shared.ComponentMsgProcessor; | |
27 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
28 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
29 | +import org.thingsboard.server.common.data.id.TenantId; | |
30 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
31 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
32 | +import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
33 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
34 | + | |
35 | +import java.util.concurrent.ExecutionException; | |
36 | + | |
37 | +/** | |
38 | + * @author Andrew Shvayka | |
39 | + */ | |
40 | +public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNodeId> { | |
41 | + | |
42 | + private final ActorRef parent; | |
43 | + private final ActorRef self; | |
44 | + private final RuleChainService service; | |
45 | + private RuleNode ruleNode; | |
46 | + private TbNode tbNode; | |
47 | + private TbContext defaultCtx; | |
48 | + | |
49 | + RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext | |
50 | + , LoggingAdapter logger, ActorRef parent, ActorRef self) { | |
51 | + super(systemContext, logger, tenantId, ruleNodeId); | |
52 | + this.parent = parent; | |
53 | + this.self = self; | |
54 | + this.service = systemContext.getRuleChainService(); | |
55 | + this.ruleNode = systemContext.getRuleChainService().findRuleNodeById(entityId); | |
56 | + this.defaultCtx = new DefaultTbContext(systemContext, new RuleNodeCtx(tenantId, parent, self, ruleNode)); | |
57 | + } | |
58 | + | |
59 | + @Override | |
60 | + public void start(ActorContext context) throws Exception { | |
61 | + tbNode = initComponent(ruleNode); | |
62 | + state = ComponentLifecycleState.ACTIVE; | |
63 | + } | |
64 | + | |
65 | + @Override | |
66 | + public void onUpdate(ActorContext context) throws Exception { | |
67 | + RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(entityId); | |
68 | + boolean restartRequired = !(ruleNode.getType().equals(newRuleNode.getType()) | |
69 | + && ruleNode.getConfiguration().equals(newRuleNode.getConfiguration())); | |
70 | + this.ruleNode = newRuleNode; | |
71 | + this.defaultCtx.updateSelf(newRuleNode); | |
72 | + if (restartRequired) { | |
73 | + if (tbNode != null) { | |
74 | + tbNode.destroy(); | |
75 | + } | |
76 | + start(context); | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + @Override | |
81 | + public void stop(ActorContext context) throws Exception { | |
82 | + if (tbNode != null) { | |
83 | + tbNode.destroy(); | |
84 | + } | |
85 | + context.stop(self); | |
86 | + } | |
87 | + | |
88 | + @Override | |
89 | + public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | |
90 | + | |
91 | + } | |
92 | + | |
93 | + public void onRuleToSelfMsg(RuleNodeToSelfMsg msg) throws Exception { | |
94 | + checkActive(); | |
95 | + if (ruleNode.isDebugMode()) { | |
96 | + systemContext.persistDebugInput(tenantId, entityId, msg.getMsg()); | |
97 | + } | |
98 | + tbNode.onMsg(defaultCtx, msg.getMsg()); | |
99 | + } | |
100 | + | |
101 | + void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) throws Exception { | |
102 | + checkActive(); | |
103 | + if (ruleNode.isDebugMode()) { | |
104 | + systemContext.persistDebugInput(tenantId, entityId, msg.getMsg()); | |
105 | + } | |
106 | + tbNode.onMsg(msg.getCtx(), msg.getMsg()); | |
107 | + } | |
108 | + | |
109 | + private TbNode initComponent(RuleNode ruleNode) throws Exception { | |
110 | + Class<?> componentClazz = Class.forName(ruleNode.getType()); | |
111 | + TbNode tbNode = (TbNode) (componentClazz.newInstance()); | |
112 | + tbNode.init(defaultCtx, new TbNodeConfiguration(ruleNode.getConfiguration())); | |
113 | + return tbNode; | |
114 | + } | |
115 | + | |
116 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import akka.actor.ActorRef; | |
19 | +import lombok.AllArgsConstructor; | |
20 | +import lombok.Data; | |
21 | +import org.thingsboard.server.common.data.id.TenantId; | |
22 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
23 | + | |
24 | +/** | |
25 | + * Created by ashvayka on 19.03.18. | |
26 | + */ | |
27 | +@Data | |
28 | +@AllArgsConstructor | |
29 | +final class RuleNodeCtx { | |
30 | + private final TenantId tenantId; | |
31 | + private final ActorRef chainActor; | |
32 | + private final ActorRef selfActor; | |
33 | + private RuleNode self; | |
34 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.EntityId; | |
20 | + | |
21 | +/** | |
22 | + * Created by ashvayka on 19.03.18. | |
23 | + */ | |
24 | + | |
25 | +@Data | |
26 | +final class RuleNodeRelation { | |
27 | + | |
28 | + private final EntityId in; | |
29 | + private final EntityId out; | |
30 | + private final String type; | |
31 | + | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
20 | +import org.thingsboard.server.common.msg.MsgType; | |
21 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
22 | +import org.thingsboard.server.common.msg.TbMsg; | |
23 | + | |
24 | +/** | |
25 | + * Created by ashvayka on 19.03.18. | |
26 | + */ | |
27 | +@Data | |
28 | +final class RuleNodeToRuleChainTellNextMsg implements TbActorMsg { | |
29 | + | |
30 | + private final RuleNodeId originator; | |
31 | + private final String relationType; | |
32 | + private final TbMsg msg; | |
33 | + | |
34 | + @Override | |
35 | + public MsgType getMsgType() { | |
36 | + return MsgType.RULE_TO_RULE_CHAIN_TELL_NEXT_MSG; | |
37 | + } | |
38 | + | |
39 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.msg.MsgType; | |
20 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
21 | +import org.thingsboard.server.common.msg.TbMsg; | |
22 | + | |
23 | +/** | |
24 | + * Created by ashvayka on 19.03.18. | |
25 | + */ | |
26 | +@Data | |
27 | +final class RuleNodeToSelfErrorMsg implements TbActorMsg { | |
28 | + | |
29 | + private final TbMsg msg; | |
30 | + private final Throwable error; | |
31 | + | |
32 | + @Override | |
33 | + public MsgType getMsgType() { | |
34 | + return MsgType.RULE_TO_SELF_ERROR_MSG; | |
35 | + } | |
36 | + | |
37 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
20 | +import org.thingsboard.server.common.msg.MsgType; | |
21 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
22 | +import org.thingsboard.server.common.msg.TbMsg; | |
23 | + | |
24 | +/** | |
25 | + * Created by ashvayka on 19.03.18. | |
26 | + */ | |
27 | +@Data | |
28 | +final class RuleNodeToSelfMsg implements TbActorMsg { | |
29 | + | |
30 | + private final TbMsg msg; | |
31 | + | |
32 | + @Override | |
33 | + public MsgType getMsgType() { | |
34 | + return MsgType.RULE_TO_SELF_MSG; | |
35 | + } | |
36 | + | |
37 | +} | ... | ... |
... | ... | @@ -15,20 +15,19 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.service; |
17 | 17 | |
18 | -import org.thingsboard.server.common.data.id.DeviceId; | |
19 | -import org.thingsboard.server.common.data.id.PluginId; | |
20 | -import org.thingsboard.server.common.data.id.RuleId; | |
21 | -import org.thingsboard.server.common.data.id.TenantId; | |
18 | +import org.thingsboard.server.common.data.id.*; | |
22 | 19 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
20 | +import org.thingsboard.server.common.msg.TbMsg; | |
21 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
23 | 22 | import org.thingsboard.server.common.transport.SessionMsgProcessor; |
24 | 23 | import org.thingsboard.server.service.cluster.discovery.DiscoveryServiceListener; |
25 | 24 | import org.thingsboard.server.service.cluster.rpc.RpcMsgListener; |
26 | 25 | |
27 | 26 | public interface ActorService extends SessionMsgProcessor, WebSocketMsgProcessor, RestMsgProcessor, RpcMsgListener, DiscoveryServiceListener { |
28 | 27 | |
29 | - void onPluginStateChange(TenantId tenantId, PluginId pluginId, ComponentLifecycleEvent state); | |
28 | + void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state); | |
30 | 29 | |
31 | - void onRuleStateChange(TenantId tenantId, RuleId ruleId, ComponentLifecycleEvent state); | |
30 | + void onMsg(ServiceToRuleEngineMsg msg); | |
32 | 31 | |
33 | 32 | void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId); |
34 | 33 | ... | ... |
... | ... | @@ -54,7 +54,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
54 | 54 | @Override |
55 | 55 | public void preStart() { |
56 | 56 | try { |
57 | - processor.start(); | |
57 | + processor.start(context()); | |
58 | 58 | logLifecycleEvent(ComponentLifecycleEvent.STARTED); |
59 | 59 | if (systemContext.isStatisticsEnabled()) { |
60 | 60 | scheduleStatsPersistTick(); |
... | ... | @@ -78,7 +78,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
78 | 78 | @Override |
79 | 79 | public void postStop() { |
80 | 80 | try { |
81 | - processor.stop(); | |
81 | + processor.stop(context()); | |
82 | 82 | logLifecycleEvent(ComponentLifecycleEvent.STOPPED); |
83 | 83 | } catch (Exception e) { |
84 | 84 | logger.warning("[{}][{}] Failed to stop {} processor: {}", tenantId, id, id.getEntityType(), e.getMessage()); |
... | ... | @@ -141,7 +141,6 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
141 | 141 | messagesProcessed++; |
142 | 142 | } |
143 | 143 | |
144 | - | |
145 | 144 | protected void logAndPersist(String method, Exception e) { |
146 | 145 | logAndPersist(method, e, false); |
147 | 146 | } | ... | ... |
... | ... | @@ -16,9 +16,13 @@ |
16 | 16 | package org.thingsboard.server.actors.service; |
17 | 17 | |
18 | 18 | import akka.actor.UntypedActor; |
19 | +import akka.event.Logging; | |
20 | +import akka.event.LoggingAdapter; | |
19 | 21 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
20 | 23 | |
21 | 24 | public abstract class ContextAwareActor extends UntypedActor { |
25 | + protected final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
22 | 26 | |
23 | 27 | public static final int ENTITY_PACK_LIMIT = 1024; |
24 | 28 | |
... | ... | @@ -28,4 +32,20 @@ public abstract class ContextAwareActor extends UntypedActor { |
28 | 32 | super(); |
29 | 33 | this.systemContext = systemContext; |
30 | 34 | } |
35 | + | |
36 | + @Override | |
37 | + public void onReceive(Object msg) throws Exception { | |
38 | + if (logger.isDebugEnabled()) { | |
39 | + logger.debug("Processing msg: {}", msg); | |
40 | + } | |
41 | + if (msg instanceof TbActorMsg) { | |
42 | + if(!process((TbActorMsg) msg)){ | |
43 | + logger.warning("Unknown message: {}!", msg); | |
44 | + } | |
45 | + } else { | |
46 | + logger.warning("Unknown message: {}!", msg); | |
47 | + } | |
48 | + } | |
49 | + | |
50 | + protected abstract boolean process(TbActorMsg msg); | |
31 | 51 | } | ... | ... |
... | ... | @@ -30,16 +30,14 @@ import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; |
30 | 30 | import org.thingsboard.server.actors.rpc.RpcSessionTellMsg; |
31 | 31 | import org.thingsboard.server.actors.session.SessionManagerActor; |
32 | 32 | import org.thingsboard.server.actors.stats.StatsActor; |
33 | -import org.thingsboard.server.common.data.id.DeviceId; | |
34 | -import org.thingsboard.server.common.data.id.PluginId; | |
35 | -import org.thingsboard.server.common.data.id.RuleId; | |
36 | -import org.thingsboard.server.common.data.id.TenantId; | |
33 | +import org.thingsboard.server.common.data.id.*; | |
37 | 34 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
38 | 35 | import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
39 | 36 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
40 | 37 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
41 | 38 | import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
42 | 39 | import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; |
40 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
43 | 41 | import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; |
44 | 42 | import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
45 | 43 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
... | ... | @@ -129,6 +127,11 @@ public class DefaultActorService implements ActorService { |
129 | 127 | } |
130 | 128 | |
131 | 129 | @Override |
130 | + public void onMsg(ServiceToRuleEngineMsg msg) { | |
131 | + appActor.tell(msg, ActorRef.noSender()); | |
132 | + } | |
133 | + | |
134 | + @Override | |
132 | 135 | public void process(SessionAwareMsg msg) { |
133 | 136 | log.debug("Processing session aware msg: {}", msg); |
134 | 137 | sessionManagerActor.tell(msg, ActorRef.noSender()); |
... | ... | @@ -212,15 +215,9 @@ public class DefaultActorService implements ActorService { |
212 | 215 | } |
213 | 216 | |
214 | 217 | @Override |
215 | - public void onPluginStateChange(TenantId tenantId, PluginId pluginId, ComponentLifecycleEvent state) { | |
216 | - log.trace("[{}] Processing onPluginStateChange event: {}", pluginId, state); | |
217 | - broadcast(ComponentLifecycleMsg.forPlugin(tenantId, pluginId, state)); | |
218 | - } | |
219 | - | |
220 | - @Override | |
221 | - public void onRuleStateChange(TenantId tenantId, RuleId ruleId, ComponentLifecycleEvent state) { | |
222 | - log.trace("[{}] Processing onRuleStateChange event: {}", ruleId, state); | |
223 | - broadcast(ComponentLifecycleMsg.forRule(tenantId, ruleId, state)); | |
218 | + public void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state) { | |
219 | + log.trace("[{}] Processing {} state change event: {}", tenantId, entityId.getEntityType(), state); | |
220 | + broadcast(new ComponentLifecycleMsg(tenantId, entityId, state)); | |
224 | 221 | } |
225 | 222 | |
226 | 223 | @Override | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextAwareActor; |
23 | 23 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
24 | 24 | import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
25 | 25 | import org.thingsboard.server.common.data.id.SessionId; |
26 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
26 | 27 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
27 | 28 | import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; |
28 | 29 | import org.thingsboard.server.common.msg.session.ToDeviceActorSessionMsg; |
... | ... | @@ -61,6 +62,12 @@ public class SessionActor extends ContextAwareActor { |
61 | 62 | } |
62 | 63 | |
63 | 64 | @Override |
65 | + protected boolean process(TbActorMsg msg) { | |
66 | + //TODO Move everything here, to work with TbActorMsg | |
67 | + return false; | |
68 | + } | |
69 | + | |
70 | + @Override | |
64 | 71 | public void onReceive(Object msg) throws Exception { |
65 | 72 | logger.debug("[{}] Processing: {}.", sessionId, msg); |
66 | 73 | if (msg instanceof ToDeviceActorSessionMsg) { | ... | ... |
... | ... | @@ -26,6 +26,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; |
26 | 26 | import org.thingsboard.server.actors.service.DefaultActorService; |
27 | 27 | import org.thingsboard.server.actors.shared.SessionTimeoutMsg; |
28 | 28 | import org.thingsboard.server.common.data.id.SessionId; |
29 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
29 | 30 | import org.thingsboard.server.common.msg.aware.SessionAwareMsg; |
30 | 31 | |
31 | 32 | import akka.event.Logging; |
... | ... | @@ -49,6 +50,12 @@ public class SessionManagerActor extends ContextAwareActor { |
49 | 50 | } |
50 | 51 | |
51 | 52 | @Override |
53 | + protected boolean process(TbActorMsg msg) { | |
54 | + //TODO Move everything here, to work with TbActorMsg | |
55 | + return false; | |
56 | + } | |
57 | + | |
58 | + @Override | |
52 | 59 | public void onReceive(Object msg) throws Exception { |
53 | 60 | if (msg instanceof SessionCtrlMsg) { |
54 | 61 | onSessionCtrlMsg((SessionCtrlMsg) msg); | ... | ... |
application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java
... | ... | @@ -102,9 +102,6 @@ public abstract class AbstractContextAwareMsgProcessor { |
102 | 102 | case FILTER: |
103 | 103 | configurationClazz = ((Filter) componentClazz.getAnnotation(Filter.class)).configuration(); |
104 | 104 | break; |
105 | - case PROCESSOR: | |
106 | - configurationClazz = ((Processor) componentClazz.getAnnotation(Processor.class)).configuration(); | |
107 | - break; | |
108 | 105 | case ACTION: |
109 | 106 | configurationClazz = ((Action) componentClazz.getAnnotation(Action.class)).configuration(); |
110 | 107 | break; | ... | ... |
... | ... | @@ -20,12 +20,14 @@ import akka.event.LoggingAdapter; |
20 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | 21 | import org.thingsboard.server.actors.stats.StatsPersistTick; |
22 | 22 | import org.thingsboard.server.common.data.id.TenantId; |
23 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
23 | 24 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
24 | 25 | |
25 | 26 | public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgProcessor { |
26 | 27 | |
27 | 28 | protected final TenantId tenantId; |
28 | 29 | protected final T entityId; |
30 | + protected ComponentLifecycleState state; | |
29 | 31 | |
30 | 32 | protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) { |
31 | 33 | super(systemContext, logger); |
... | ... | @@ -33,23 +35,44 @@ public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgPr |
33 | 35 | this.entityId = id; |
34 | 36 | } |
35 | 37 | |
36 | - public abstract void start() throws Exception; | |
38 | + public abstract void start(ActorContext context) throws Exception; | |
37 | 39 | |
38 | - public abstract void stop() throws Exception; | |
40 | + public abstract void stop(ActorContext context) throws Exception; | |
39 | 41 | |
40 | - public abstract void onCreated(ActorContext context) throws Exception; | |
42 | + public abstract void onClusterEventMsg(ClusterEventMsg msg) throws Exception; | |
41 | 43 | |
42 | - public abstract void onUpdate(ActorContext context) throws Exception; | |
44 | + public void onCreated(ActorContext context) throws Exception { | |
45 | + start(context); | |
46 | + } | |
43 | 47 | |
44 | - public abstract void onActivate(ActorContext context) throws Exception; | |
48 | + public void onUpdate(ActorContext context) throws Exception { | |
49 | + restart(context); | |
50 | + } | |
45 | 51 | |
46 | - public abstract void onSuspend(ActorContext context) throws Exception; | |
52 | + public void onActivate(ActorContext context) throws Exception { | |
53 | + restart(context); | |
54 | + } | |
47 | 55 | |
48 | - public abstract void onStop(ActorContext context) throws Exception; | |
56 | + public void onSuspend(ActorContext context) throws Exception { | |
57 | + stop(context); | |
58 | + } | |
49 | 59 | |
50 | - public abstract void onClusterEventMsg(ClusterEventMsg msg) throws Exception; | |
60 | + public void onStop(ActorContext context) throws Exception { | |
61 | + stop(context); | |
62 | + } | |
63 | + | |
64 | + private void restart(ActorContext context) throws Exception { | |
65 | + stop(context); | |
66 | + start(context); | |
67 | + } | |
51 | 68 | |
52 | 69 | public void scheduleStatsPersistTick(ActorContext context, long statsPersistFrequency) { |
53 | 70 | schedulePeriodicMsgWithDelay(context, new StatsPersistTick(), statsPersistFrequency, statsPersistFrequency); |
54 | 71 | } |
72 | + | |
73 | + protected void checkActive() { | |
74 | + if (state != ComponentLifecycleState.ACTIVE) { | |
75 | + throw new IllegalStateException("Rule chain is not active!"); | |
76 | + } | |
77 | + } | |
55 | 78 | } | ... | ... |
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.shared; | |
17 | + | |
18 | +import akka.actor.ActorContext; | |
19 | +import akka.actor.ActorRef; | |
20 | +import akka.actor.Props; | |
21 | +import akka.actor.UntypedActor; | |
22 | +import akka.japi.Creator; | |
23 | +import lombok.extern.slf4j.Slf4j; | |
24 | +import org.thingsboard.server.actors.ActorSystemContext; | |
25 | +import org.thingsboard.server.actors.service.ContextAwareActor; | |
26 | +import org.thingsboard.server.common.data.SearchTextBased; | |
27 | +import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | |
28 | +import org.thingsboard.server.common.data.id.EntityId; | |
29 | +import org.thingsboard.server.common.data.id.TenantId; | |
30 | +import org.thingsboard.server.common.data.id.UUIDBased; | |
31 | +import org.thingsboard.server.common.data.page.PageDataIterable; | |
32 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
33 | + | |
34 | +import java.util.HashMap; | |
35 | +import java.util.Map; | |
36 | + | |
37 | +/** | |
38 | + * Created by ashvayka on 15.03.18. | |
39 | + */ | |
40 | +@Slf4j | |
41 | +public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> { | |
42 | + | |
43 | + protected final ActorSystemContext systemContext; | |
44 | + protected final Map<T, ActorRef> actors; | |
45 | + | |
46 | + public EntityActorsManager(ActorSystemContext systemContext) { | |
47 | + this.systemContext = systemContext; | |
48 | + this.actors = new HashMap<>(); | |
49 | + } | |
50 | + | |
51 | + protected abstract TenantId getTenantId(); | |
52 | + | |
53 | + protected abstract String getDispatcherName(); | |
54 | + | |
55 | + protected abstract Creator<A> creator(T entityId); | |
56 | + | |
57 | + protected abstract PageDataIterable.FetchFunction<M> getFetchEntitiesFunction(); | |
58 | + | |
59 | + public void init(ActorContext context) { | |
60 | + for (M entity : new PageDataIterable<>(getFetchEntitiesFunction(), ContextAwareActor.ENTITY_PACK_LIMIT)) { | |
61 | + T entityId = (T) entity.getId(); | |
62 | + log.debug("[{}|{}] Creating entity actor", entityId.getEntityType(), entityId.getId()); | |
63 | + //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa. | |
64 | + ActorRef actorRef = getOrCreateActor(context, entityId); | |
65 | + visit(entity, actorRef); | |
66 | + log.debug("[{}|{}] Entity actor created.", entityId.getEntityType(), entityId.getId()); | |
67 | + } | |
68 | + } | |
69 | + | |
70 | + protected void visit(M entity, ActorRef actorRef) {} | |
71 | + | |
72 | + public ActorRef getOrCreateActor(ActorContext context, T entityId) { | |
73 | + return actors.computeIfAbsent(entityId, eId -> | |
74 | + context.actorOf(Props.create(creator(eId)) | |
75 | + .withDispatcher(getDispatcherName()), eId.toString())); | |
76 | + } | |
77 | + | |
78 | + public void broadcast(Object msg) { | |
79 | + actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | |
80 | + } | |
81 | + | |
82 | + public void remove(T id) { | |
83 | + actors.remove(id); | |
84 | + } | |
85 | + | |
86 | +} | ... | ... |
... | ... | @@ -15,63 +15,28 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.shared.plugin; |
17 | 17 | |
18 | -import akka.actor.ActorContext; | |
19 | -import akka.actor.ActorRef; | |
20 | -import akka.actor.Props; | |
18 | +import akka.japi.Creator; | |
21 | 19 | import lombok.extern.slf4j.Slf4j; |
22 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 21 | import org.thingsboard.server.actors.plugin.PluginActor; |
24 | -import org.thingsboard.server.actors.service.ContextAwareActor; | |
22 | +import org.thingsboard.server.actors.shared.EntityActorsManager; | |
25 | 23 | import org.thingsboard.server.common.data.id.PluginId; |
26 | -import org.thingsboard.server.common.data.id.TenantId; | |
27 | -import org.thingsboard.server.common.data.page.PageDataIterable; | |
28 | -import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; | |
29 | 24 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
30 | 25 | import org.thingsboard.server.dao.plugin.PluginService; |
31 | 26 | |
32 | -import java.util.HashMap; | |
33 | -import java.util.Map; | |
34 | - | |
35 | 27 | @Slf4j |
36 | -public abstract class PluginManager { | |
28 | +public abstract class PluginManager extends EntityActorsManager<PluginId, PluginActor, PluginMetaData> { | |
37 | 29 | |
38 | - protected final ActorSystemContext systemContext; | |
39 | 30 | protected final PluginService pluginService; |
40 | - protected final Map<PluginId, ActorRef> pluginActors; | |
41 | 31 | |
42 | 32 | public PluginManager(ActorSystemContext systemContext) { |
43 | - this.systemContext = systemContext; | |
33 | + super(systemContext); | |
44 | 34 | this.pluginService = systemContext.getPluginService(); |
45 | - this.pluginActors = new HashMap<>(); | |
46 | 35 | } |
47 | 36 | |
48 | - public void init(ActorContext context) { | |
49 | - PageDataIterable<PluginMetaData> pluginIterator = new PageDataIterable<>(getFetchPluginsFunction(), | |
50 | - ContextAwareActor.ENTITY_PACK_LIMIT); | |
51 | - for (PluginMetaData plugin : pluginIterator) { | |
52 | - log.debug("[{}] Creating plugin actor", plugin.getId()); | |
53 | - getOrCreatePluginActor(context, plugin.getId()); | |
54 | - log.debug("Plugin actor created."); | |
55 | - } | |
37 | + @Override | |
38 | + public Creator<PluginActor> creator(PluginId entityId){ | |
39 | + return new PluginActor.ActorCreator(systemContext, getTenantId(), entityId); | |
56 | 40 | } |
57 | 41 | |
58 | - abstract FetchFunction<PluginMetaData> getFetchPluginsFunction(); | |
59 | - | |
60 | - abstract TenantId getTenantId(); | |
61 | - | |
62 | - abstract String getDispatcherName(); | |
63 | - | |
64 | - public ActorRef getOrCreatePluginActor(ActorContext context, PluginId pluginId) { | |
65 | - return pluginActors.computeIfAbsent(pluginId, pId -> | |
66 | - context.actorOf(Props.create(new PluginActor.ActorCreator(systemContext, getTenantId(), pId)) | |
67 | - .withDispatcher(getDispatcherName()), pId.toString())); | |
68 | - } | |
69 | - | |
70 | - public void broadcast(Object msg) { | |
71 | - pluginActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); | |
72 | - } | |
73 | - | |
74 | - public void remove(PluginId id) { | |
75 | - pluginActors.remove(id); | |
76 | - } | |
77 | 42 | } | ... | ... |
... | ... | @@ -29,12 +29,12 @@ public class SystemPluginManager extends PluginManager { |
29 | 29 | } |
30 | 30 | |
31 | 31 | @Override |
32 | - FetchFunction<PluginMetaData> getFetchPluginsFunction() { | |
32 | + protected FetchFunction<PluginMetaData> getFetchEntitiesFunction() { | |
33 | 33 | return pluginService::findSystemPlugins; |
34 | 34 | } |
35 | 35 | |
36 | 36 | @Override |
37 | - TenantId getTenantId() { | |
37 | + protected TenantId getTenantId() { | |
38 | 38 | return BasePluginService.SYSTEM_TENANT; |
39 | 39 | } |
40 | 40 | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import akka.actor.ActorContext; |
19 | 19 | import org.thingsboard.server.actors.ActorSystemContext; |
20 | 20 | import org.thingsboard.server.actors.service.DefaultActorService; |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | +import org.thingsboard.server.common.data.page.PageDataIterable; | |
22 | 23 | import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; |
23 | 24 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
24 | 25 | |
... | ... | @@ -39,12 +40,12 @@ public class TenantPluginManager extends PluginManager { |
39 | 40 | } |
40 | 41 | |
41 | 42 | @Override |
42 | - FetchFunction<PluginMetaData> getFetchPluginsFunction() { | |
43 | + protected FetchFunction<PluginMetaData> getFetchEntitiesFunction() { | |
43 | 44 | return link -> pluginService.findTenantPlugins(tenantId, link); |
44 | 45 | } |
45 | 46 | |
46 | 47 | @Override |
47 | - TenantId getTenantId() { | |
48 | + protected TenantId getTenantId() { | |
48 | 49 | return tenantId; |
49 | 50 | } |
50 | 51 | ... | ... |
application/src/main/java/org/thingsboard/server/actors/shared/rule/RuleManager.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.shared.rule; | |
17 | - | |
18 | -import akka.actor.ActorContext; | |
19 | -import akka.actor.ActorRef; | |
20 | -import akka.actor.Props; | |
21 | -import lombok.extern.slf4j.Slf4j; | |
22 | -import org.thingsboard.server.actors.ActorSystemContext; | |
23 | -import org.thingsboard.server.actors.rule.RuleActor; | |
24 | -import org.thingsboard.server.actors.rule.RuleActorChain; | |
25 | -import org.thingsboard.server.actors.rule.RuleActorMetaData; | |
26 | -import org.thingsboard.server.actors.rule.SimpleRuleActorChain; | |
27 | -import org.thingsboard.server.actors.service.ContextAwareActor; | |
28 | -import org.thingsboard.server.common.data.id.RuleId; | |
29 | -import org.thingsboard.server.common.data.id.TenantId; | |
30 | -import org.thingsboard.server.common.data.page.PageDataIterable; | |
31 | -import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; | |
32 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; | |
33 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
34 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
35 | -import org.thingsboard.server.dao.rule.RuleService; | |
36 | - | |
37 | -import java.util.*; | |
38 | - | |
39 | -@Slf4j | |
40 | -public abstract class RuleManager { | |
41 | - | |
42 | - protected final ActorSystemContext systemContext; | |
43 | - protected final RuleService ruleService; | |
44 | - protected final Map<RuleId, ActorRef> ruleActors; | |
45 | - protected final TenantId tenantId; | |
46 | - | |
47 | - private Map<RuleMetaData, RuleActorMetaData> ruleMap; | |
48 | - private RuleActorChain ruleChain; | |
49 | - | |
50 | - public RuleManager(ActorSystemContext systemContext, TenantId tenantId) { | |
51 | - this.systemContext = systemContext; | |
52 | - this.ruleService = systemContext.getRuleService(); | |
53 | - this.ruleActors = new HashMap<>(); | |
54 | - this.tenantId = tenantId; | |
55 | - } | |
56 | - | |
57 | - public void init(ActorContext context) { | |
58 | - doInit(context); | |
59 | - } | |
60 | - | |
61 | - private void doInit(ActorContext context) { | |
62 | - PageDataIterable<RuleMetaData> ruleIterator = new PageDataIterable<>(getFetchRulesFunction(), | |
63 | - ContextAwareActor.ENTITY_PACK_LIMIT); | |
64 | - ruleMap = new HashMap<>(); | |
65 | - | |
66 | - for (RuleMetaData rule : ruleIterator) { | |
67 | - log.debug("[{}] Creating rule actor {}", rule.getId(), rule); | |
68 | - ActorRef ref = getOrCreateRuleActor(context, rule.getId()); | |
69 | - ruleMap.put(rule, RuleActorMetaData.systemRule(rule.getId(), rule.getWeight(), ref)); | |
70 | - log.debug("[{}] Rule actor created.", rule.getId()); | |
71 | - } | |
72 | - | |
73 | - refreshRuleChain(); | |
74 | - } | |
75 | - | |
76 | - public Optional<ActorRef> update(ActorContext context, RuleId ruleId, ComponentLifecycleEvent event) { | |
77 | - if (ruleMap == null) { | |
78 | - doInit(context); | |
79 | - } | |
80 | - RuleMetaData rule; | |
81 | - if (event != ComponentLifecycleEvent.DELETED) { | |
82 | - rule = systemContext.getRuleService().findRuleById(ruleId); | |
83 | - } else { | |
84 | - rule = ruleMap.keySet().stream() | |
85 | - .filter(r -> r.getId().equals(ruleId)) | |
86 | - .peek(r -> r.setState(ComponentLifecycleState.SUSPENDED)) | |
87 | - .findFirst() | |
88 | - .orElse(null); | |
89 | - if (rule != null) { | |
90 | - ruleMap.remove(rule); | |
91 | - ruleActors.remove(ruleId); | |
92 | - } | |
93 | - } | |
94 | - if (rule != null) { | |
95 | - RuleActorMetaData actorMd = ruleMap.get(rule); | |
96 | - if (actorMd == null) { | |
97 | - ActorRef ref = getOrCreateRuleActor(context, rule.getId()); | |
98 | - actorMd = RuleActorMetaData.systemRule(rule.getId(), rule.getWeight(), ref); | |
99 | - ruleMap.put(rule, actorMd); | |
100 | - } | |
101 | - refreshRuleChain(); | |
102 | - return Optional.of(actorMd.getActorRef()); | |
103 | - } else { | |
104 | - log.warn("[{}] Can't process unknown rule!", ruleId); | |
105 | - return Optional.empty(); | |
106 | - } | |
107 | - } | |
108 | - | |
109 | - abstract FetchFunction<RuleMetaData> getFetchRulesFunction(); | |
110 | - | |
111 | - abstract String getDispatcherName(); | |
112 | - | |
113 | - public ActorRef getOrCreateRuleActor(ActorContext context, RuleId ruleId) { | |
114 | - return ruleActors.computeIfAbsent(ruleId, rId -> | |
115 | - context.actorOf(Props.create(new RuleActor.ActorCreator(systemContext, tenantId, rId)) | |
116 | - .withDispatcher(getDispatcherName()), rId.toString())); | |
117 | - } | |
118 | - | |
119 | - public RuleActorChain getRuleChain(ActorContext context) { | |
120 | - if (ruleChain == null) { | |
121 | - doInit(context); | |
122 | - } | |
123 | - return ruleChain; | |
124 | - } | |
125 | - | |
126 | - private void refreshRuleChain() { | |
127 | - Set<RuleActorMetaData> activeRuleSet = new HashSet<>(); | |
128 | - for (Map.Entry<RuleMetaData, RuleActorMetaData> rule : ruleMap.entrySet()) { | |
129 | - if (rule.getKey().getState() == ComponentLifecycleState.ACTIVE) { | |
130 | - activeRuleSet.add(rule.getValue()); | |
131 | - } | |
132 | - } | |
133 | - ruleChain = new SimpleRuleActorChain(activeRuleSet); | |
134 | - } | |
135 | -} |
application/src/main/java/org/thingsboard/server/actors/shared/rulechain/RuleChainManager.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2018 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.actors.shared.rulechain; | |
17 | + | |
18 | +import akka.actor.ActorRef; | |
19 | +import akka.japi.Creator; | |
20 | +import lombok.Getter; | |
21 | +import lombok.extern.slf4j.Slf4j; | |
22 | +import org.thingsboard.server.actors.ActorSystemContext; | |
23 | +import org.thingsboard.server.actors.ruleChain.RuleChainActor; | |
24 | +import org.thingsboard.server.actors.shared.EntityActorsManager; | |
25 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
26 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
27 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
28 | + | |
29 | +/** | |
30 | + * Created by ashvayka on 15.03.18. | |
31 | + */ | |
32 | +@Slf4j | |
33 | +public abstract class RuleChainManager extends EntityActorsManager<RuleChainId, RuleChainActor, RuleChain> { | |
34 | + | |
35 | + protected final RuleChainService service; | |
36 | + @Getter | |
37 | + protected RuleChain rootChain; | |
38 | + @Getter | |
39 | + protected ActorRef rootChainActor; | |
40 | + | |
41 | + public RuleChainManager(ActorSystemContext systemContext) { | |
42 | + super(systemContext); | |
43 | + this.service = systemContext.getRuleChainService(); | |
44 | + } | |
45 | + | |
46 | + @Override | |
47 | + public Creator<RuleChainActor> creator(RuleChainId entityId) { | |
48 | + return new RuleChainActor.ActorCreator(systemContext, getTenantId(), entityId); | |
49 | + } | |
50 | + | |
51 | + @Override | |
52 | + protected void visit(RuleChain entity, ActorRef actorRef) { | |
53 | + if (entity.isRoot()) { | |
54 | + rootChain = entity; | |
55 | + rootChainActor = actorRef; | |
56 | + } | |
57 | + } | |
58 | + | |
59 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java
renamed from
application/src/main/java/org/thingsboard/server/actors/shared/rule/SystemRuleManager.java
... | ... | @@ -13,28 +13,35 @@ |
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.actors.shared.rule; | |
16 | +package org.thingsboard.server.actors.shared.rulechain; | |
17 | 17 | |
18 | 18 | import org.thingsboard.server.actors.ActorSystemContext; |
19 | 19 | import org.thingsboard.server.actors.service.DefaultActorService; |
20 | +import org.thingsboard.server.actors.shared.plugin.PluginManager; | |
20 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
21 | 22 | import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; |
22 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
23 | -import org.thingsboard.server.dao.model.ModelConstants; | |
23 | +import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
24 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
25 | +import org.thingsboard.server.dao.plugin.BasePluginService; | |
24 | 26 | |
25 | -public class SystemRuleManager extends RuleManager { | |
27 | +public class SystemRuleChainManager extends RuleChainManager { | |
26 | 28 | |
27 | - public SystemRuleManager(ActorSystemContext systemContext) { | |
28 | - super(systemContext, new TenantId(ModelConstants.NULL_UUID)); | |
29 | + public SystemRuleChainManager(ActorSystemContext systemContext) { | |
30 | + super(systemContext); | |
29 | 31 | } |
30 | 32 | |
31 | 33 | @Override |
32 | - FetchFunction<RuleMetaData> getFetchRulesFunction() { | |
33 | - return ruleService::findSystemRules; | |
34 | + protected FetchFunction<RuleChain> getFetchEntitiesFunction() { | |
35 | + return service::findSystemRuleChains; | |
34 | 36 | } |
35 | 37 | |
36 | 38 | @Override |
37 | - String getDispatcherName() { | |
39 | + protected TenantId getTenantId() { | |
40 | + return BasePluginService.SYSTEM_TENANT; | |
41 | + } | |
42 | + | |
43 | + @Override | |
44 | + protected String getDispatcherName() { | |
38 | 45 | return DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME; |
39 | 46 | } |
40 | 47 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java
renamed from
application/src/main/java/org/thingsboard/server/actors/shared/rule/TenantRuleManager.java
... | ... | @@ -13,19 +13,22 @@ |
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.actors.shared.rule; | |
16 | +package org.thingsboard.server.actors.shared.rulechain; | |
17 | 17 | |
18 | 18 | import akka.actor.ActorContext; |
19 | 19 | import org.thingsboard.server.actors.ActorSystemContext; |
20 | 20 | import org.thingsboard.server.actors.service.DefaultActorService; |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | 22 | import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; |
23 | -import org.thingsboard.server.common.data.rule.RuleMetaData; | |
23 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
24 | 24 | |
25 | -public class TenantRuleManager extends RuleManager { | |
26 | - | |
27 | - public TenantRuleManager(ActorSystemContext systemContext, TenantId tenantId) { | |
28 | - super(systemContext, tenantId); | |
25 | +public class TenantRuleChainManager extends RuleChainManager { | |
26 | + | |
27 | + private final TenantId tenantId; | |
28 | + | |
29 | + public TenantRuleChainManager(ActorSystemContext systemContext, TenantId tenantId) { | |
30 | + super(systemContext); | |
31 | + this.tenantId = tenantId; | |
29 | 32 | } |
30 | 33 | |
31 | 34 | @Override |
... | ... | @@ -36,13 +39,17 @@ public class TenantRuleManager extends RuleManager { |
36 | 39 | } |
37 | 40 | |
38 | 41 | @Override |
39 | - FetchFunction<RuleMetaData> getFetchRulesFunction() { | |
40 | - return link -> ruleService.findTenantRules(tenantId, link); | |
42 | + protected TenantId getTenantId() { | |
43 | + return tenantId; | |
41 | 44 | } |
42 | 45 | |
43 | 46 | @Override |
44 | - String getDispatcherName() { | |
47 | + protected String getDispatcherName() { | |
45 | 48 | return DefaultActorService.TENANT_RULE_DISPATCHER_NAME; |
46 | 49 | } |
47 | 50 | |
51 | + @Override | |
52 | + protected FetchFunction<RuleChain> getFetchEntitiesFunction() { | |
53 | + return link -> service.findTenantRuleChains(tenantId, link); | |
54 | + } | |
48 | 55 | } | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.thingsboard.server.actors.service.ContextAwareActor; |
24 | 24 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
25 | 25 | import org.thingsboard.server.common.data.DataConstants; |
26 | 26 | import org.thingsboard.server.common.data.Event; |
27 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
27 | 28 | import org.thingsboard.server.common.msg.cluster.ServerAddress; |
28 | 29 | |
29 | 30 | public class StatsActor extends ContextAwareActor { |
... | ... | @@ -36,6 +37,12 @@ public class StatsActor extends ContextAwareActor { |
36 | 37 | } |
37 | 38 | |
38 | 39 | @Override |
40 | + protected boolean process(TbActorMsg msg) { | |
41 | + //TODO Move everything here, to work with TbActorMsg\ | |
42 | + return false; | |
43 | + } | |
44 | + | |
45 | + @Override | |
39 | 46 | public void onReceive(Object msg) throws Exception { |
40 | 47 | logger.debug("Received message: {}", msg); |
41 | 48 | if (msg instanceof StatsPersistMsg) { | ... | ... |
... | ... | @@ -15,52 +15,38 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.tenant; |
17 | 17 | |
18 | -import java.util.HashMap; | |
19 | -import java.util.Map; | |
20 | -import java.util.Optional; | |
21 | - | |
18 | +import akka.actor.ActorRef; | |
19 | +import akka.actor.Props; | |
20 | +import akka.event.Logging; | |
21 | +import akka.event.LoggingAdapter; | |
22 | 22 | import org.thingsboard.server.actors.ActorSystemContext; |
23 | 23 | import org.thingsboard.server.actors.device.DeviceActor; |
24 | 24 | import org.thingsboard.server.actors.plugin.PluginTerminationMsg; |
25 | -import org.thingsboard.server.actors.rule.ComplexRuleActorChain; | |
26 | -import org.thingsboard.server.actors.rule.RuleActorChain; | |
27 | -import org.thingsboard.server.actors.service.ContextAwareActor; | |
25 | +import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; | |
28 | 26 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
29 | 27 | import org.thingsboard.server.actors.service.DefaultActorService; |
30 | -import org.thingsboard.server.actors.shared.plugin.PluginManager; | |
31 | 28 | import org.thingsboard.server.actors.shared.plugin.TenantPluginManager; |
32 | -import org.thingsboard.server.actors.shared.rule.RuleManager; | |
33 | -import org.thingsboard.server.actors.shared.rule.TenantRuleManager; | |
29 | +import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager; | |
34 | 30 | import org.thingsboard.server.common.data.id.DeviceId; |
35 | -import org.thingsboard.server.common.data.id.PluginId; | |
36 | -import org.thingsboard.server.common.data.id.RuleId; | |
37 | 31 | import org.thingsboard.server.common.data.id.TenantId; |
38 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
32 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
39 | 33 | import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
40 | - | |
41 | -import akka.actor.ActorRef; | |
42 | -import akka.actor.Props; | |
43 | -import akka.event.Logging; | |
44 | -import akka.event.LoggingAdapter; | |
45 | 34 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
35 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
46 | 36 | import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; |
47 | 37 | import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg; |
48 | -import org.thingsboard.server.extensions.api.rules.ToRuleActorMsg; | |
49 | 38 | |
50 | -public class TenantActor extends ContextAwareActor { | |
39 | +import java.util.HashMap; | |
40 | +import java.util.Map; | |
51 | 41 | |
52 | - private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); | |
42 | +public class TenantActor extends RuleChainManagerActor { | |
53 | 43 | |
54 | 44 | private final TenantId tenantId; |
55 | - private final RuleManager ruleManager; | |
56 | - private final PluginManager pluginManager; | |
57 | 45 | private final Map<DeviceId, ActorRef> deviceActors; |
58 | 46 | |
59 | 47 | private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { |
60 | - super(systemContext); | |
48 | + super(systemContext, new TenantRuleChainManager(systemContext, tenantId), new TenantPluginManager(systemContext, tenantId)); | |
61 | 49 | this.tenantId = tenantId; |
62 | - this.ruleManager = new TenantRuleManager(systemContext, tenantId); | |
63 | - this.pluginManager = new TenantPluginManager(systemContext, tenantId); | |
64 | 50 | this.deviceActors = new HashMap<>(); |
65 | 51 | } |
66 | 52 | |
... | ... | @@ -68,8 +54,7 @@ public class TenantActor extends ContextAwareActor { |
68 | 54 | public void preStart() { |
69 | 55 | logger.info("[{}] Starting tenant actor.", tenantId); |
70 | 56 | try { |
71 | - ruleManager.init(this.context()); | |
72 | - pluginManager.init(this.context()); | |
57 | + initRuleChains(); | |
73 | 58 | logger.info("[{}] Tenant actor started.", tenantId); |
74 | 59 | } catch (Exception e) { |
75 | 60 | logger.error(e, "[{}] Unknown failure", tenantId); |
... | ... | @@ -77,29 +62,45 @@ public class TenantActor extends ContextAwareActor { |
77 | 62 | } |
78 | 63 | |
79 | 64 | @Override |
80 | - public void onReceive(Object msg) throws Exception { | |
81 | - logger.debug("[{}] Received message: {}", tenantId, msg); | |
82 | - if (msg instanceof RuleChainDeviceMsg) { | |
83 | - process((RuleChainDeviceMsg) msg); | |
84 | - } else if (msg instanceof ToDeviceActorMsg) { | |
85 | - onToDeviceActorMsg((ToDeviceActorMsg) msg); | |
86 | - } else if (msg instanceof ToPluginActorMsg) { | |
87 | - onToPluginMsg((ToPluginActorMsg) msg); | |
88 | - } else if (msg instanceof ToRuleActorMsg) { | |
89 | - onToRuleMsg((ToRuleActorMsg) msg); | |
90 | - } else if (msg instanceof ToDeviceActorNotificationMsg) { | |
91 | - onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg); | |
92 | - } else if (msg instanceof ClusterEventMsg) { | |
93 | - broadcast(msg); | |
94 | - } else if (msg instanceof ComponentLifecycleMsg) { | |
95 | - onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
96 | - } else if (msg instanceof PluginTerminationMsg) { | |
97 | - onPluginTerminated((PluginTerminationMsg) msg); | |
98 | - } else { | |
99 | - logger.warning("[{}] Unknown message: {}!", tenantId, msg); | |
65 | + protected boolean process(TbActorMsg msg) { | |
66 | + switch (msg.getMsgType()) { | |
67 | + case COMPONENT_LIFE_CYCLE_MSG: | |
68 | + onComponentLifecycleMsg((ComponentLifecycleMsg) msg); | |
69 | + break; | |
70 | + case SERVICE_TO_RULE_ENGINE_MSG: | |
71 | + onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); | |
72 | + break; | |
73 | + default: | |
74 | + return false; | |
100 | 75 | } |
76 | + return true; | |
101 | 77 | } |
102 | 78 | |
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 | + | |
103 | 104 | private void broadcast(Object msg) { |
104 | 105 | pluginManager.broadcast(msg); |
105 | 106 | deviceActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
... | ... | @@ -113,14 +114,9 @@ public class TenantActor extends ContextAwareActor { |
113 | 114 | getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); |
114 | 115 | } |
115 | 116 | |
116 | - private void onToRuleMsg(ToRuleActorMsg msg) { | |
117 | - ActorRef target = ruleManager.getOrCreateRuleActor(this.context(), msg.getRuleId()); | |
118 | - target.tell(msg, ActorRef.noSender()); | |
119 | - } | |
120 | - | |
121 | 117 | private void onToPluginMsg(ToPluginActorMsg msg) { |
122 | 118 | if (msg.getPluginTenantId().equals(tenantId)) { |
123 | - ActorRef pluginActor = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId()); | |
119 | + ActorRef pluginActor = pluginManager.getOrCreateActor(this.context(), msg.getPluginId()); | |
124 | 120 | pluginActor.tell(msg, ActorRef.noSender()); |
125 | 121 | } else { |
126 | 122 | context().parent().tell(msg, ActorRef.noSender()); |
... | ... | @@ -128,23 +124,11 @@ public class TenantActor extends ContextAwareActor { |
128 | 124 | } |
129 | 125 | |
130 | 126 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
131 | - Optional<PluginId> pluginId = msg.getPluginId(); | |
132 | - Optional<RuleId> ruleId = msg.getRuleId(); | |
133 | - if (pluginId.isPresent()) { | |
134 | - ActorRef pluginActor = pluginManager.getOrCreatePluginActor(this.context(), pluginId.get()); | |
135 | - pluginActor.tell(msg, ActorRef.noSender()); | |
136 | - } else if (ruleId.isPresent()) { | |
137 | - ActorRef target; | |
138 | - Optional<ActorRef> ref = ruleManager.update(this.context(), ruleId.get(), msg.getEvent()); | |
139 | - if (ref.isPresent()) { | |
140 | - target = ref.get(); | |
141 | - } else { | |
142 | - logger.debug("Failed to find actor for rule: [{}]", ruleId); | |
143 | - return; | |
144 | - } | |
127 | + ActorRef target = getEntityActorRef(msg.getEntityId()); | |
128 | + if (target != null) { | |
145 | 129 | target.tell(msg, ActorRef.noSender()); |
146 | 130 | } else { |
147 | - logger.debug("[{}] Invalid component lifecycle msg.", tenantId); | |
131 | + logger.debug("Invalid component lifecycle msg: {}", msg); | |
148 | 132 | } |
149 | 133 | } |
150 | 134 | |
... | ... | @@ -152,13 +136,6 @@ public class TenantActor extends ContextAwareActor { |
152 | 136 | pluginManager.remove(msg.getId()); |
153 | 137 | } |
154 | 138 | |
155 | - private void process(RuleChainDeviceMsg msg) { | |
156 | - ToDeviceActorMsg toDeviceActorMsg = msg.getToDeviceActorMsg(); | |
157 | - ActorRef deviceActor = getOrCreateDeviceActor(toDeviceActorMsg.getDeviceId()); | |
158 | - RuleActorChain tenantChain = ruleManager.getRuleChain(this.context()); | |
159 | - RuleActorChain chain = new ComplexRuleActorChain(msg.getRuleChain(), tenantChain); | |
160 | - deviceActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, chain), context().self()); | |
161 | - } | |
162 | 139 | |
163 | 140 | private ActorRef getOrCreateDeviceActor(DeviceId deviceId) { |
164 | 141 | return deviceActors.computeIfAbsent(deviceId, k -> context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId)) | ... | ... |
... | ... | @@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired; |
20 | 20 | import org.springframework.beans.factory.annotation.Qualifier; |
21 | 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
22 | 22 | import org.springframework.boot.autoconfigure.security.SecurityProperties; |
23 | -import org.springframework.boot.context.properties.EnableConfigurationProperties; | |
24 | 23 | import org.springframework.context.annotation.Bean; |
25 | 24 | import org.springframework.context.annotation.Configuration; |
26 | 25 | import org.springframework.core.annotation.Order; |
... | ... | @@ -37,7 +36,6 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand |
37 | 36 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler; |
38 | 37 | import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
39 | 38 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; |
40 | -import org.springframework.web.cors.CorsUtils; | |
41 | 39 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
42 | 40 | import org.springframework.web.filter.CorsFilter; |
43 | 41 | import org.thingsboard.server.dao.audit.AuditLogLevelFilter; | ... | ... |
... | ... | @@ -17,9 +17,9 @@ package org.thingsboard.server.config; |
17 | 17 | |
18 | 18 | import java.util.Map; |
19 | 19 | |
20 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
21 | -import org.thingsboard.server.exception.ThingsboardException; | |
22 | -import org.thingsboard.server.controller.plugin.PluginWebSocketHandler; | |
20 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
21 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
22 | +import org.thingsboard.server.controller.plugin.TbWebSocketHandler; | |
23 | 23 | import org.thingsboard.server.service.security.model.SecurityUser; |
24 | 24 | import org.springframework.context.annotation.Bean; |
25 | 25 | import org.springframework.context.annotation.Configuration; |
... | ... | @@ -54,7 +54,7 @@ public class WebSocketConfiguration implements WebSocketConfigurer { |
54 | 54 | |
55 | 55 | @Override |
56 | 56 | public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { |
57 | - registry.addHandler(pluginWsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*") | |
57 | + registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*") | |
58 | 58 | .addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() { |
59 | 59 | |
60 | 60 | @Override |
... | ... | @@ -82,8 +82,8 @@ public class WebSocketConfiguration implements WebSocketConfigurer { |
82 | 82 | } |
83 | 83 | |
84 | 84 | @Bean |
85 | - public WebSocketHandler pluginWsHandler() { | |
86 | - return new PluginWebSocketHandler(); | |
85 | + public WebSocketHandler wsHandler() { | |
86 | + return new TbWebSocketHandler(); | |
87 | 87 | } |
88 | 88 | |
89 | 89 | protected SecurityUser getCurrentUser() throws ThingsboardException { | ... | ... |
... | ... | @@ -20,8 +20,8 @@ import org.springframework.security.access.prepost.PreAuthorize; |
20 | 20 | import org.springframework.web.bind.annotation.*; |
21 | 21 | import org.thingsboard.server.common.data.AdminSettings; |
22 | 22 | import org.thingsboard.server.dao.settings.AdminSettingsService; |
23 | -import org.thingsboard.server.exception.ThingsboardException; | |
24 | -import org.thingsboard.server.service.mail.MailService; | |
23 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
24 | +import org.thingsboard.rule.engine.api.MailService; | |
25 | 25 | import org.thingsboard.server.service.update.UpdateService; |
26 | 26 | import org.thingsboard.server.service.update.model.UpdateMessage; |
27 | 27 | ... | ... |
... | ... | @@ -23,8 +23,8 @@ import org.thingsboard.server.common.data.alarm.*; |
23 | 23 | import org.thingsboard.server.common.data.id.*; |
24 | 24 | import org.thingsboard.server.common.data.page.TimePageData; |
25 | 25 | import org.thingsboard.server.common.data.page.TimePageLink; |
26 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
27 | -import org.thingsboard.server.exception.ThingsboardException; | |
26 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
27 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
28 | 28 | |
29 | 29 | @RestController |
30 | 30 | @RequestMapping("/api") | ... | ... |
... | ... | @@ -33,8 +33,8 @@ import org.thingsboard.server.common.data.asset.AssetSearchQuery; |
33 | 33 | import org.thingsboard.server.common.data.security.Authority; |
34 | 34 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
35 | 35 | import org.thingsboard.server.dao.model.ModelConstants; |
36 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
37 | -import org.thingsboard.server.exception.ThingsboardException; | |
36 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
37 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
38 | 38 | import org.thingsboard.server.service.security.model.SecurityUser; |
39 | 39 | |
40 | 40 | import java.util.ArrayList; | ... | ... |
... | ... | @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
24 | 24 | import org.thingsboard.server.common.data.id.UserId; |
25 | 25 | import org.thingsboard.server.common.data.page.TimePageData; |
26 | 26 | import org.thingsboard.server.common.data.page.TimePageLink; |
27 | -import org.thingsboard.server.exception.ThingsboardException; | |
27 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
28 | 28 | |
29 | 29 | import java.util.UUID; |
30 | 30 | ... | ... |
... | ... | @@ -28,9 +28,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
28 | 28 | import org.springframework.web.bind.annotation.*; |
29 | 29 | import org.thingsboard.server.common.data.User; |
30 | 30 | import org.thingsboard.server.common.data.security.UserCredentials; |
31 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
32 | -import org.thingsboard.server.exception.ThingsboardException; | |
33 | -import org.thingsboard.server.service.mail.MailService; | |
31 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
32 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
33 | +import org.thingsboard.rule.engine.api.MailService; | |
34 | 34 | import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; |
35 | 35 | import org.thingsboard.server.service.security.model.SecurityUser; |
36 | 36 | import org.thingsboard.server.service.security.model.UserPrincipal; | ... | ... |
... | ... | @@ -15,12 +15,9 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | -import com.fasterxml.jackson.databind.JsonNode; | |
19 | -import com.fasterxml.jackson.databind.ObjectMapper; | |
20 | 18 | import lombok.extern.slf4j.Slf4j; |
21 | 19 | import org.apache.commons.lang3.StringUtils; |
22 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
23 | -import org.springframework.beans.factory.annotation.Value; | |
24 | 21 | import org.springframework.security.core.Authentication; |
25 | 22 | import org.springframework.security.core.context.SecurityContextHolder; |
26 | 23 | import org.springframework.web.bind.annotation.ExceptionHandler; |
... | ... | @@ -30,7 +27,6 @@ import org.thingsboard.server.common.data.alarm.Alarm; |
30 | 27 | import org.thingsboard.server.common.data.alarm.AlarmId; |
31 | 28 | import org.thingsboard.server.common.data.alarm.AlarmInfo; |
32 | 29 | import org.thingsboard.server.common.data.asset.Asset; |
33 | -import org.thingsboard.server.common.data.audit.ActionStatus; | |
34 | 30 | import org.thingsboard.server.common.data.audit.ActionType; |
35 | 31 | import org.thingsboard.server.common.data.id.*; |
36 | 32 | import org.thingsboard.server.common.data.page.TextPageLink; |
... | ... | @@ -49,6 +45,7 @@ import org.thingsboard.server.dao.audit.AuditLogService; |
49 | 45 | import org.thingsboard.server.dao.customer.CustomerService; |
50 | 46 | import org.thingsboard.server.dao.dashboard.DashboardService; |
51 | 47 | import org.thingsboard.server.dao.device.DeviceCredentialsService; |
48 | +import org.thingsboard.server.dao.device.DeviceOfflineService; | |
52 | 49 | import org.thingsboard.server.dao.device.DeviceService; |
53 | 50 | import org.thingsboard.server.dao.exception.DataValidationException; |
54 | 51 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
... | ... | @@ -57,12 +54,13 @@ import org.thingsboard.server.dao.plugin.PluginService; |
57 | 54 | import org.thingsboard.server.dao.relation.RelationService; |
58 | 55 | import org.thingsboard.server.dao.rule.RuleChainService; |
59 | 56 | import org.thingsboard.server.dao.rule.RuleService; |
57 | +import org.thingsboard.server.dao.tenant.TenantService; | |
60 | 58 | import org.thingsboard.server.dao.user.UserService; |
61 | 59 | import org.thingsboard.server.dao.widget.WidgetTypeService; |
62 | 60 | import org.thingsboard.server.dao.widget.WidgetsBundleService; |
63 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
61 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
64 | 62 | import org.thingsboard.server.exception.ThingsboardErrorResponseHandler; |
65 | -import org.thingsboard.server.exception.ThingsboardException; | |
63 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
66 | 64 | import org.thingsboard.server.service.component.ComponentDiscoveryService; |
67 | 65 | import org.thingsboard.server.service.security.model.SecurityUser; |
68 | 66 | |
... | ... | @@ -71,6 +69,7 @@ import javax.servlet.http.HttpServletRequest; |
71 | 69 | import javax.servlet.http.HttpServletResponse; |
72 | 70 | import java.util.List; |
73 | 71 | import java.util.Optional; |
72 | +import java.util.Set; | |
74 | 73 | import java.util.UUID; |
75 | 74 | |
76 | 75 | import static org.thingsboard.server.dao.service.Validator.validateId; |
... | ... | @@ -85,6 +84,9 @@ public abstract class BaseController { |
85 | 84 | private ThingsboardErrorResponseHandler errorResponseHandler; |
86 | 85 | |
87 | 86 | @Autowired |
87 | + protected TenantService tenantService; | |
88 | + | |
89 | + @Autowired | |
88 | 90 | protected CustomerService customerService; |
89 | 91 | |
90 | 92 | @Autowired |
... | ... | @@ -132,6 +134,9 @@ public abstract class BaseController { |
132 | 134 | @Autowired |
133 | 135 | protected AuditLogService auditLogService; |
134 | 136 | |
137 | + @Autowired | |
138 | + protected DeviceOfflineService offlineService; | |
139 | + | |
135 | 140 | @ExceptionHandler(ThingsboardException.class) |
136 | 141 | public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) { |
137 | 142 | errorResponseHandler.handle(ex, response); |
... | ... | @@ -480,6 +485,15 @@ public abstract class BaseController { |
480 | 485 | } |
481 | 486 | } |
482 | 487 | |
488 | + List<ComponentDescriptor> checkComponentDescriptorsByTypes(Set<ComponentType> types) throws ThingsboardException { | |
489 | + try { | |
490 | + log.debug("[{}] Lookup component descriptors", types); | |
491 | + return componentDescriptorService.getComponents(types); | |
492 | + } catch (Exception e) { | |
493 | + throw handleException(e, false); | |
494 | + } | |
495 | + } | |
496 | + | |
483 | 497 | List<ComponentDescriptor> checkPluginActionsByPluginClazz(String pluginClazz) throws ThingsboardException { |
484 | 498 | try { |
485 | 499 | checkComponentDescriptorByClazz(pluginClazz); |
... | ... | @@ -550,6 +564,8 @@ public abstract class BaseController { |
550 | 564 | throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION, |
551 | 565 | ThingsboardErrorCode.PERMISSION_DENIED); |
552 | 566 | |
567 | + } else if (tenantId.getId().equals(ModelConstants.NULL_UUID)) { | |
568 | + ruleChain.setConfiguration(null); | |
553 | 569 | } |
554 | 570 | } |
555 | 571 | return ruleChain; |
... | ... | @@ -590,5 +606,8 @@ public abstract class BaseController { |
590 | 606 | auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo); |
591 | 607 | } |
592 | 608 | |
609 | + protected static Exception toException(Throwable error) { | |
610 | + return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); | |
611 | + } | |
593 | 612 | |
594 | 613 | } | ... | ... |
... | ... | @@ -19,9 +19,11 @@ import org.springframework.security.access.prepost.PreAuthorize; |
19 | 19 | import org.springframework.web.bind.annotation.*; |
20 | 20 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
21 | 21 | import org.thingsboard.server.common.data.plugin.ComponentType; |
22 | -import org.thingsboard.server.exception.ThingsboardException; | |
22 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
23 | 23 | |
24 | +import java.util.HashSet; | |
24 | 25 | import java.util.List; |
26 | +import java.util.Set; | |
25 | 27 | |
26 | 28 | @RestController |
27 | 29 | @RequestMapping("/api") |
... | ... | @@ -52,6 +54,22 @@ public class ComponentDescriptorController extends BaseController { |
52 | 54 | } |
53 | 55 | |
54 | 56 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") |
57 | + @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET) | |
58 | + @ResponseBody | |
59 | + public List<ComponentDescriptor> getComponentDescriptorsByTypes(@RequestParam("componentTypes") String[] strComponentTypes) throws ThingsboardException { | |
60 | + checkArrayParameter("componentTypes", strComponentTypes); | |
61 | + try { | |
62 | + Set<ComponentType> componentTypes = new HashSet<>(); | |
63 | + for (String strComponentType : strComponentTypes) { | |
64 | + componentTypes.add(ComponentType.valueOf(strComponentType)); | |
65 | + } | |
66 | + return checkComponentDescriptorsByTypes(componentTypes); | |
67 | + } catch (Exception e) { | |
68 | + throw handleException(e); | |
69 | + } | |
70 | + } | |
71 | + | |
72 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')") | |
55 | 73 | @RequestMapping(value = "/components/actions/{pluginClazz:.+}", method = RequestMethod.GET) |
56 | 74 | @ResponseBody |
57 | 75 | public List<ComponentDescriptor> getPluginActionsByPluginClazz(@PathVariable("pluginClazz") String pluginClazz) throws ThingsboardException { | ... | ... |
... | ... | @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.id.CustomerId; |
28 | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | 29 | import org.thingsboard.server.common.data.page.TextPageData; |
30 | 30 | import org.thingsboard.server.common.data.page.TextPageLink; |
31 | -import org.thingsboard.server.exception.ThingsboardException; | |
31 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
32 | 32 | |
33 | 33 | @RestController |
34 | 34 | @RequestMapping("/api") | ... | ... |
... | ... | @@ -27,9 +27,7 @@ import org.thingsboard.server.common.data.page.TextPageData; |
27 | 27 | import org.thingsboard.server.common.data.page.TextPageLink; |
28 | 28 | import org.thingsboard.server.common.data.page.TimePageData; |
29 | 29 | import org.thingsboard.server.common.data.page.TimePageLink; |
30 | -import org.thingsboard.server.dao.exception.IncorrectParameterException; | |
31 | -import org.thingsboard.server.dao.model.ModelConstants; | |
32 | -import org.thingsboard.server.exception.ThingsboardException; | |
30 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
33 | 31 | |
34 | 32 | import java.util.HashSet; |
35 | 33 | import java.util.Set; | ... | ... |
... | ... | @@ -23,9 +23,11 @@ import org.thingsboard.server.common.data.Customer; |
23 | 23 | import org.thingsboard.server.common.data.Device; |
24 | 24 | import org.thingsboard.server.common.data.EntitySubtype; |
25 | 25 | import org.thingsboard.server.common.data.EntityType; |
26 | -import org.thingsboard.server.common.data.audit.ActionStatus; | |
27 | 26 | import org.thingsboard.server.common.data.audit.ActionType; |
28 | 27 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
28 | +import org.thingsboard.server.common.data.device.DeviceStatusQuery; | |
29 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
30 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
29 | 31 | import org.thingsboard.server.common.data.id.CustomerId; |
30 | 32 | import org.thingsboard.server.common.data.id.DeviceId; |
31 | 33 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -35,8 +37,6 @@ import org.thingsboard.server.common.data.security.Authority; |
35 | 37 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
36 | 38 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
37 | 39 | import org.thingsboard.server.dao.model.ModelConstants; |
38 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
39 | -import org.thingsboard.server.exception.ThingsboardException; | |
40 | 40 | import org.thingsboard.server.service.security.model.SecurityUser; |
41 | 41 | |
42 | 42 | import java.util.ArrayList; |
... | ... | @@ -70,7 +70,7 @@ public class DeviceController extends BaseController { |
70 | 70 | device.setTenantId(getCurrentUser().getTenantId()); |
71 | 71 | if (getCurrentUser().getAuthority() == Authority.CUSTOMER_USER) { |
72 | 72 | if (device.getId() == null || device.getId().isNullUid() || |
73 | - device.getCustomerId() == null || device.getCustomerId().isNullUid()) { | |
73 | + device.getCustomerId() == null || device.getCustomerId().isNullUid()) { | |
74 | 74 | throw new ThingsboardException("You don't have permission to perform this operation!", |
75 | 75 | ThingsboardErrorCode.PERMISSION_DENIED); |
76 | 76 | } else { |
... | ... | @@ -368,4 +368,32 @@ public class DeviceController extends BaseController { |
368 | 368 | throw handleException(e); |
369 | 369 | } |
370 | 370 | } |
371 | + | |
372 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | |
373 | + @RequestMapping(value = "/device/offline", method = RequestMethod.GET) | |
374 | + @ResponseBody | |
375 | + public List<Device> getOfflineDevices(@RequestParam("contactType") DeviceStatusQuery.ContactType contactType, | |
376 | + @RequestParam("threshold") long threshold) throws ThingsboardException { | |
377 | + try { | |
378 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
379 | + ListenableFuture<List<Device>> offlineDevices = offlineService.findOfflineDevices(tenantId.getId(), contactType, threshold); | |
380 | + return checkNotNull(offlineDevices.get()); | |
381 | + } catch (Exception e) { | |
382 | + throw handleException(e); | |
383 | + } | |
384 | + } | |
385 | + | |
386 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | |
387 | + @RequestMapping(value = "/device/online", method = RequestMethod.GET) | |
388 | + @ResponseBody | |
389 | + public List<Device> getOnlineDevices(@RequestParam("contactType") DeviceStatusQuery.ContactType contactType, | |
390 | + @RequestParam("threshold") long threshold) throws ThingsboardException { | |
391 | + try { | |
392 | + TenantId tenantId = getCurrentUser().getTenantId(); | |
393 | + ListenableFuture<List<Device>> offlineDevices = offlineService.findOnlineDevices(tenantId.getId(), contactType, threshold); | |
394 | + return checkNotNull(offlineDevices.get()); | |
395 | + } catch (Exception e) { | |
396 | + throw handleException(e); | |
397 | + } | |
398 | + } | |
371 | 399 | } | ... | ... |
... | ... | @@ -24,8 +24,8 @@ import org.thingsboard.server.common.data.relation.EntityRelation; |
24 | 24 | import org.thingsboard.server.common.data.relation.EntityRelationInfo; |
25 | 25 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
26 | 26 | import org.thingsboard.server.common.data.relation.EntityRelationsQuery; |
27 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
28 | -import org.thingsboard.server.exception.ThingsboardException; | |
27 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
28 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
29 | 29 | |
30 | 30 | import java.util.List; |
31 | 31 | ... | ... |
... | ... | @@ -24,8 +24,8 @@ import org.thingsboard.server.common.data.page.TimePageData; |
24 | 24 | import org.thingsboard.server.common.data.page.TimePageLink; |
25 | 25 | import org.thingsboard.server.dao.event.EventService; |
26 | 26 | import org.thingsboard.server.dao.model.ModelConstants; |
27 | -import org.thingsboard.server.exception.ThingsboardErrorCode; | |
28 | -import org.thingsboard.server.exception.ThingsboardException; | |
27 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; | |
28 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
29 | 29 | |
30 | 30 | @RestController |
31 | 31 | @RequestMapping("/api") | ... | ... |
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.google.common.util.concurrent.FutureCallback; | |
19 | +import org.springframework.http.ResponseEntity; | |
20 | +import org.springframework.web.context.request.async.DeferredResult; | |
21 | +import org.thingsboard.server.service.security.ValidationCallback; | |
22 | + | |
23 | +/** | |
24 | + * Created by ashvayka on 21.02.17. | |
25 | + */ | |
26 | +public class HttpValidationCallback extends ValidationCallback<DeferredResult<ResponseEntity>> { | |
27 | + | |
28 | + public HttpValidationCallback(DeferredResult<ResponseEntity> response, FutureCallback<DeferredResult<ResponseEntity>> action) { | |
29 | + super(response, action); | |
30 | + } | |
31 | + | |
32 | +} | ... | ... |
... | ... | @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
28 | 28 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
29 | 29 | import org.thingsboard.server.common.data.security.Authority; |
30 | 30 | import org.thingsboard.server.dao.model.ModelConstants; |
31 | -import org.thingsboard.server.exception.ThingsboardException; | |
31 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
32 | 32 | |
33 | 33 | import java.util.List; |
34 | 34 | |
... | ... | @@ -71,7 +71,7 @@ public class PluginController extends BaseController { |
71 | 71 | boolean created = source.getId() == null; |
72 | 72 | source.setTenantId(getCurrentUser().getTenantId()); |
73 | 73 | PluginMetaData plugin = checkNotNull(pluginService.savePlugin(source)); |
74 | - actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), | |
74 | + actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(), | |
75 | 75 | created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
76 | 76 | |
77 | 77 | logEntityAction(plugin.getId(), plugin, |
... | ... | @@ -97,7 +97,7 @@ public class PluginController extends BaseController { |
97 | 97 | PluginId pluginId = new PluginId(toUUID(strPluginId)); |
98 | 98 | PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); |
99 | 99 | pluginService.activatePluginById(pluginId); |
100 | - actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.ACTIVATED); | |
100 | + actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.ACTIVATED); | |
101 | 101 | |
102 | 102 | logEntityAction(plugin.getId(), plugin, |
103 | 103 | null, |
... | ... | @@ -123,7 +123,7 @@ public class PluginController extends BaseController { |
123 | 123 | PluginId pluginId = new PluginId(toUUID(strPluginId)); |
124 | 124 | PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); |
125 | 125 | pluginService.suspendPluginById(pluginId); |
126 | - actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.SUSPENDED); | |
126 | + actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.SUSPENDED); | |
127 | 127 | |
128 | 128 | logEntityAction(plugin.getId(), plugin, |
129 | 129 | null, |
... | ... | @@ -221,7 +221,7 @@ public class PluginController extends BaseController { |
221 | 221 | PluginId pluginId = new PluginId(toUUID(strPluginId)); |
222 | 222 | PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); |
223 | 223 | pluginService.deletePluginById(pluginId); |
224 | - actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.DELETED); | |
224 | + actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.DELETED); | |
225 | 225 | |
226 | 226 | logEntityAction(pluginId, plugin, |
227 | 227 | null, | ... | ... |
... | ... | @@ -15,31 +15,46 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | +import com.datastax.driver.core.utils.UUIDs; | |
19 | +import com.fasterxml.jackson.core.type.TypeReference; | |
20 | +import com.fasterxml.jackson.databind.JsonNode; | |
21 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
22 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
23 | +import lombok.extern.slf4j.Slf4j; | |
18 | 24 | import org.springframework.http.HttpStatus; |
19 | 25 | import org.springframework.security.access.prepost.PreAuthorize; |
26 | +import org.springframework.util.StringUtils; | |
20 | 27 | import org.springframework.web.bind.annotation.*; |
28 | +import org.thingsboard.rule.engine.api.ScriptEngine; | |
21 | 29 | import org.thingsboard.server.common.data.EntityType; |
22 | 30 | import org.thingsboard.server.common.data.audit.ActionType; |
23 | -import org.thingsboard.server.common.data.id.PluginId; | |
24 | 31 | import org.thingsboard.server.common.data.id.RuleChainId; |
25 | 32 | import org.thingsboard.server.common.data.id.TenantId; |
26 | 33 | import org.thingsboard.server.common.data.page.TextPageData; |
27 | 34 | import org.thingsboard.server.common.data.page.TextPageLink; |
28 | 35 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
29 | -import org.thingsboard.server.common.data.plugin.PluginMetaData; | |
30 | 36 | import org.thingsboard.server.common.data.rule.RuleChain; |
37 | +import org.thingsboard.server.common.data.rule.RuleChainMetaData; | |
31 | 38 | import org.thingsboard.server.common.data.security.Authority; |
39 | +import org.thingsboard.server.common.msg.TbMsg; | |
40 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | |
32 | 41 | import org.thingsboard.server.dao.model.ModelConstants; |
33 | -import org.thingsboard.server.exception.ThingsboardException; | |
42 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
43 | +import org.thingsboard.server.service.script.NashornJsEngine; | |
34 | 44 | |
35 | 45 | import java.util.List; |
46 | +import java.util.Map; | |
47 | +import java.util.Set; | |
36 | 48 | |
49 | +@Slf4j | |
37 | 50 | @RestController |
38 | 51 | @RequestMapping("/api") |
39 | 52 | public class RuleChainController extends BaseController { |
40 | 53 | |
41 | 54 | public static final String RULE_CHAIN_ID = "ruleChainId"; |
42 | 55 | |
56 | + private static final ObjectMapper objectMapper = new ObjectMapper(); | |
57 | + | |
43 | 58 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
44 | 59 | @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET) |
45 | 60 | @ResponseBody |
... | ... | @@ -54,6 +69,21 @@ public class RuleChainController extends BaseController { |
54 | 69 | } |
55 | 70 | |
56 | 71 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
72 | + @RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET) | |
73 | + @ResponseBody | |
74 | + public RuleChainMetaData getRuleChainMetaData(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { | |
75 | + checkParameter(RULE_CHAIN_ID, strRuleChainId); | |
76 | + try { | |
77 | + RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); | |
78 | + checkRuleChain(ruleChainId); | |
79 | + return ruleChainService.loadRuleChainMetaData(ruleChainId); | |
80 | + } catch (Exception e) { | |
81 | + throw handleException(e); | |
82 | + } | |
83 | + } | |
84 | + | |
85 | + | |
86 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
57 | 87 | @RequestMapping(value = "/ruleChain", method = RequestMethod.POST) |
58 | 88 | @ResponseBody |
59 | 89 | public RuleChain saveRuleChain(@RequestBody RuleChain ruleChain) throws ThingsboardException { |
... | ... | @@ -62,6 +92,9 @@ public class RuleChainController extends BaseController { |
62 | 92 | ruleChain.setTenantId(getCurrentUser().getTenantId()); |
63 | 93 | RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); |
64 | 94 | |
95 | + actorService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(), | |
96 | + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | |
97 | + | |
65 | 98 | logEntityAction(savedRuleChain.getId(), savedRuleChain, |
66 | 99 | null, |
67 | 100 | created ? ActionType.ADDED : ActionType.UPDATED, null); |
... | ... | @@ -77,6 +110,30 @@ public class RuleChainController extends BaseController { |
77 | 110 | } |
78 | 111 | |
79 | 112 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
113 | + @RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST) | |
114 | + @ResponseBody | |
115 | + public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException { | |
116 | + try { | |
117 | + RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId()); | |
118 | + RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(ruleChainMetaData)); | |
119 | + | |
120 | + actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); | |
121 | + | |
122 | + logEntityAction(ruleChain.getId(), ruleChain, | |
123 | + null, | |
124 | + ActionType.UPDATED, null, ruleChainMetaData); | |
125 | + | |
126 | + return savedRuleChainMetaData; | |
127 | + } catch (Exception e) { | |
128 | + | |
129 | + logEntityAction(emptyId(EntityType.RULE_CHAIN), null, | |
130 | + null, ActionType.UPDATED, e, ruleChainMetaData); | |
131 | + | |
132 | + throw handleException(e); | |
133 | + } | |
134 | + } | |
135 | + | |
136 | + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | |
80 | 137 | @RequestMapping(value = "/ruleChains", params = {"limit"}, method = RequestMethod.GET) |
81 | 138 | @ResponseBody |
82 | 139 | public TextPageData<RuleChain> getRuleChains( |
... | ... | @@ -145,6 +202,8 @@ public class RuleChainController extends BaseController { |
145 | 202 | RuleChain ruleChain = checkRuleChain(ruleChainId); |
146 | 203 | ruleChainService.deleteRuleChainById(ruleChainId); |
147 | 204 | |
205 | + actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED); | |
206 | + | |
148 | 207 | logEntityAction(ruleChainId, ruleChain, |
149 | 208 | null, |
150 | 209 | ActionType.DELETED, null, strRuleChainId); |
... | ... | @@ -158,4 +217,78 @@ public class RuleChainController extends BaseController { |
158 | 217 | } |
159 | 218 | } |
160 | 219 | |
220 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | |
221 | + @RequestMapping(value = "/ruleChain/testScript", method = RequestMethod.POST) | |
222 | + @ResponseBody | |
223 | + public JsonNode testScript(@RequestBody JsonNode inputParams) throws ThingsboardException { | |
224 | + try { | |
225 | + String script = inputParams.get("script").asText(); | |
226 | + String scriptType = inputParams.get("scriptType").asText(); | |
227 | + String functionName = inputParams.get("functionName").asText(); | |
228 | + JsonNode argNamesJson = inputParams.get("argNames"); | |
229 | + String[] argNames = objectMapper.treeToValue(argNamesJson, String[].class); | |
230 | + | |
231 | + String data = inputParams.get("msg").asText(); | |
232 | + JsonNode metadataJson = inputParams.get("metadata"); | |
233 | + Map<String, String> metadata = objectMapper.convertValue(metadataJson, new TypeReference<Map<String, String>>() {}); | |
234 | + String msgType = inputParams.get("msgType").asText(); | |
235 | + String output = ""; | |
236 | + String errorText = ""; | |
237 | + ScriptEngine engine = null; | |
238 | + try { | |
239 | + engine = new NashornJsEngine(script, functionName, argNames); | |
240 | + TbMsg inMsg = new TbMsg(UUIDs.timeBased(), msgType, null, new TbMsgMetaData(metadata), data); | |
241 | + switch (scriptType) { | |
242 | + case "update": | |
243 | + output = msgToOutput(engine.executeUpdate(inMsg)); | |
244 | + break; | |
245 | + case "generate": | |
246 | + output = msgToOutput(engine.executeGenerate(inMsg)); | |
247 | + break; | |
248 | + case "filter": | |
249 | + boolean result = engine.executeFilter(inMsg); | |
250 | + output = Boolean.toString(result); | |
251 | + break; | |
252 | + case "switch": | |
253 | + Set<String> states = engine.executeSwitch(inMsg); | |
254 | + output = objectMapper.writeValueAsString(states); | |
255 | + break; | |
256 | + case "json": | |
257 | + JsonNode json = engine.executeJson(inMsg); | |
258 | + output = objectMapper.writeValueAsString(json); | |
259 | + break; | |
260 | + case "string": | |
261 | + output = engine.executeToString(inMsg); | |
262 | + break; | |
263 | + default: | |
264 | + throw new IllegalArgumentException("Unsupported script type: " + scriptType); | |
265 | + } | |
266 | + } catch (Exception e) { | |
267 | + log.error("Error evaluating JS function", e); | |
268 | + errorText = e.getMessage(); | |
269 | + } finally { | |
270 | + if (engine != null) { | |
271 | + engine.destroy(); | |
272 | + } | |
273 | + } | |
274 | + ObjectNode result = objectMapper.createObjectNode(); | |
275 | + result.put("output", output); | |
276 | + result.put("error", errorText); | |
277 | + return result; | |
278 | + } catch (Exception e) { | |
279 | + throw handleException(e); | |
280 | + } | |
281 | + } | |
282 | + | |
283 | + private String msgToOutput(TbMsg msg) throws Exception { | |
284 | + ObjectNode msgData = objectMapper.createObjectNode(); | |
285 | + if (!StringUtils.isEmpty(msg.getData())) { | |
286 | + msgData.set("msg", objectMapper.readTree(msg.getData())); | |
287 | + } | |
288 | + Map<String, String> metadata = msg.getMetaData().getData(); | |
289 | + msgData.set("metadata", objectMapper.valueToTree(metadata)); | |
290 | + msgData.put("msgType", msg.getType()); | |
291 | + return objectMapper.writeValueAsString(msgData); | |
292 | + } | |
293 | + | |
161 | 294 | } | ... | ... |
... | ... | @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
28 | 28 | import org.thingsboard.server.common.data.plugin.PluginMetaData; |
29 | 29 | import org.thingsboard.server.common.data.rule.RuleMetaData; |
30 | 30 | import org.thingsboard.server.common.data.security.Authority; |
31 | -import org.thingsboard.server.exception.ThingsboardException; | |
31 | +import org.thingsboard.server.common.data.exception.ThingsboardException; | |
32 | 32 | |
33 | 33 | import java.util.List; |
34 | 34 | |
... | ... | @@ -73,7 +73,7 @@ public class RuleController extends BaseController { |
73 | 73 | boolean created = source.getId() == null; |
74 | 74 | source.setTenantId(getCurrentUser().getTenantId()); |
75 | 75 | RuleMetaData rule = checkNotNull(ruleService.saveRule(source)); |
76 | - actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), | |
76 | + actorService.onEntityStateChange(rule.getTenantId(), rule.getId(), | |
77 | 77 | created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
78 | 78 | |
79 | 79 | logEntityAction(rule.getId(), rule, |
... | ... | @@ -99,7 +99,7 @@ public class RuleController extends BaseController { |
99 | 99 | RuleId ruleId = new RuleId(toUUID(strRuleId)); |
100 | 100 | RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); |
101 | 101 | ruleService.activateRuleById(ruleId); |
102 | - actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.ACTIVATED); | |
102 | + actorService.onEntityStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.ACTIVATED); | |
103 | 103 | |
104 | 104 | logEntityAction(rule.getId(), rule, |
105 | 105 | null, |
... | ... | @@ -125,7 +125,7 @@ public class RuleController extends BaseController { |
125 | 125 | RuleId ruleId = new RuleId(toUUID(strRuleId)); |
126 | 126 | RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); |
127 | 127 | ruleService.suspendRuleById(ruleId); |
128 | - actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.SUSPENDED); | |
128 | + actorService.onEntityStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.SUSPENDED); | |
129 | 129 | |
130 | 130 | logEntityAction(rule.getId(), rule, |
131 | 131 | null, |
... | ... | @@ -219,7 +219,7 @@ public class RuleController extends BaseController { |
219 | 219 | RuleId ruleId = new RuleId(toUUID(strRuleId)); |
220 | 220 | RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); |
221 | 221 | ruleService.deleteRuleById(ruleId); |
222 | - actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.DELETED); | |
222 | + actorService.onEntityStateChange(rule.getTenantId(), rule.getId(), ComponentLifecycleEvent.DELETED); | |
223 | 223 | |
224 | 224 | logEntityAction(ruleId, rule, |
225 | 225 | null, | ... | ... |