Showing
85 changed files
with
2237 additions
and
1333 deletions
Too many changes to show.
To preserve performance only 85 of 137 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,6 +86,7 @@ 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, | ... | ... |
... | ... | @@ -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,6 @@ 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 | 37 | ); |
\ No newline at end of file | ... | ... |
... | ... | @@ -28,12 +28,16 @@ import lombok.Setter; |
28 | 28 | import org.springframework.beans.factory.annotation.Autowired; |
29 | 29 | import org.springframework.beans.factory.annotation.Value; |
30 | 30 | import org.springframework.stereotype.Component; |
31 | +import org.springframework.util.Base64Utils; | |
32 | +import org.thingsboard.rule.engine.api.ListeningExecutor; | |
33 | +import org.thingsboard.rule.engine.js.JsExecutorService; | |
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; |
... | ... | @@ -50,6 +54,7 @@ import org.thingsboard.server.dao.rule.RuleChainService; |
50 | 54 | import org.thingsboard.server.dao.rule.RuleService; |
51 | 55 | import org.thingsboard.server.dao.tenant.TenantService; |
52 | 56 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
57 | +import org.thingsboard.server.dao.user.UserService; | |
53 | 58 | import org.thingsboard.server.service.cluster.discovery.DiscoveryService; |
54 | 59 | import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; |
55 | 60 | import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; |
... | ... | @@ -57,6 +62,7 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService; |
57 | 62 | |
58 | 63 | import java.io.PrintWriter; |
59 | 64 | import java.io.StringWriter; |
65 | +import java.nio.charset.StandardCharsets; | |
60 | 66 | import java.util.Optional; |
61 | 67 | |
62 | 68 | @Component |
... | ... | @@ -65,101 +71,154 @@ public class ActorSystemContext { |
65 | 71 | |
66 | 72 | protected final ObjectMapper mapper = new ObjectMapper(); |
67 | 73 | |
68 | - @Getter @Setter private ActorService actorService; | |
74 | + @Getter | |
75 | + @Setter | |
76 | + private ActorService actorService; | |
69 | 77 | |
70 | 78 | @Autowired |
71 | - @Getter private DiscoveryService discoveryService; | |
79 | + @Getter | |
80 | + private DiscoveryService discoveryService; | |
72 | 81 | |
73 | 82 | @Autowired |
74 | - @Getter @Setter private ComponentDiscoveryService componentService; | |
83 | + @Getter | |
84 | + @Setter | |
85 | + private ComponentDiscoveryService componentService; | |
75 | 86 | |
76 | 87 | @Autowired |
77 | - @Getter private ClusterRoutingService routingService; | |
88 | + @Getter | |
89 | + private ClusterRoutingService routingService; | |
78 | 90 | |
79 | 91 | @Autowired |
80 | - @Getter private ClusterRpcService rpcService; | |
92 | + @Getter | |
93 | + private ClusterRpcService rpcService; | |
81 | 94 | |
82 | 95 | @Autowired |
83 | - @Getter private DeviceAuthService deviceAuthService; | |
96 | + @Getter | |
97 | + private DeviceAuthService deviceAuthService; | |
84 | 98 | |
85 | 99 | @Autowired |
86 | - @Getter private DeviceService deviceService; | |
100 | + @Getter | |
101 | + private DeviceService deviceService; | |
87 | 102 | |
88 | 103 | @Autowired |
89 | - @Getter private AssetService assetService; | |
104 | + @Getter | |
105 | + private AssetService assetService; | |
90 | 106 | |
91 | 107 | @Autowired |
92 | - @Getter private TenantService tenantService; | |
108 | + @Getter | |
109 | + private TenantService tenantService; | |
93 | 110 | |
94 | 111 | @Autowired |
95 | - @Getter private CustomerService customerService; | |
112 | + @Getter | |
113 | + private CustomerService customerService; | |
96 | 114 | |
97 | 115 | @Autowired |
98 | - @Getter private RuleService ruleService; | |
116 | + @Getter | |
117 | + private UserService userService; | |
99 | 118 | |
100 | 119 | @Autowired |
101 | - @Getter private RuleChainService ruleChainService; | |
120 | + @Getter | |
121 | + private RuleService ruleService; | |
102 | 122 | |
103 | 123 | @Autowired |
104 | - @Getter private PluginService pluginService; | |
124 | + @Getter | |
125 | + private RuleChainService ruleChainService; | |
105 | 126 | |
106 | 127 | @Autowired |
107 | - @Getter private TimeseriesService tsService; | |
128 | + @Getter | |
129 | + private PluginService pluginService; | |
108 | 130 | |
109 | 131 | @Autowired |
110 | - @Getter private AttributesService attributesService; | |
132 | + @Getter | |
133 | + private TimeseriesService tsService; | |
111 | 134 | |
112 | 135 | @Autowired |
113 | - @Getter private EventService eventService; | |
136 | + @Getter | |
137 | + private AttributesService attributesService; | |
114 | 138 | |
115 | 139 | @Autowired |
116 | - @Getter private AlarmService alarmService; | |
140 | + @Getter | |
141 | + private EventService eventService; | |
117 | 142 | |
118 | 143 | @Autowired |
119 | - @Getter private RelationService relationService; | |
144 | + @Getter | |
145 | + private AlarmService alarmService; | |
120 | 146 | |
121 | 147 | @Autowired |
122 | - @Getter private AuditLogService auditLogService; | |
148 | + @Getter | |
149 | + private RelationService relationService; | |
123 | 150 | |
124 | 151 | @Autowired |
125 | - @Getter @Setter private PluginWebSocketMsgEndpoint wsMsgEndpoint; | |
152 | + @Getter | |
153 | + private AuditLogService auditLogService; | |
154 | + | |
155 | + @Autowired | |
156 | + @Getter | |
157 | + @Setter | |
158 | + private PluginWebSocketMsgEndpoint wsMsgEndpoint; | |
126 | 159 | |
127 | 160 | @Value("${actors.session.sync.timeout}") |
128 | - @Getter private long syncSessionTimeout; | |
161 | + @Getter | |
162 | + private long syncSessionTimeout; | |
129 | 163 | |
130 | 164 | @Value("${actors.plugin.termination.delay}") |
131 | - @Getter private long pluginActorTerminationDelay; | |
165 | + @Getter | |
166 | + private long pluginActorTerminationDelay; | |
132 | 167 | |
133 | 168 | @Value("${actors.plugin.processing.timeout}") |
134 | - @Getter private long pluginProcessingTimeout; | |
169 | + @Getter | |
170 | + private long pluginProcessingTimeout; | |
135 | 171 | |
136 | 172 | @Value("${actors.plugin.error_persist_frequency}") |
137 | - @Getter private long pluginErrorPersistFrequency; | |
173 | + @Getter | |
174 | + private long pluginErrorPersistFrequency; | |
175 | + | |
176 | + @Value("${actors.rule.chain.error_persist_frequency}") | |
177 | + @Getter | |
178 | + private long ruleChainErrorPersistFrequency; | |
179 | + | |
180 | + @Value("${actors.rule.node.error_persist_frequency}") | |
181 | + @Getter | |
182 | + private long ruleNodeErrorPersistFrequency; | |
138 | 183 | |
139 | 184 | @Value("${actors.rule.termination.delay}") |
140 | - @Getter private long ruleActorTerminationDelay; | |
185 | + @Getter | |
186 | + private long ruleActorTerminationDelay; | |
141 | 187 | |
142 | 188 | @Value("${actors.rule.error_persist_frequency}") |
143 | - @Getter private long ruleErrorPersistFrequency; | |
189 | + @Getter | |
190 | + private long ruleErrorPersistFrequency; | |
144 | 191 | |
145 | 192 | @Value("${actors.statistics.enabled}") |
146 | - @Getter private boolean statisticsEnabled; | |
193 | + @Getter | |
194 | + private boolean statisticsEnabled; | |
147 | 195 | |
148 | 196 | @Value("${actors.statistics.persist_frequency}") |
149 | - @Getter private long statisticsPersistFrequency; | |
197 | + @Getter | |
198 | + private long statisticsPersistFrequency; | |
150 | 199 | |
151 | 200 | @Value("${actors.tenant.create_components_on_init}") |
152 | - @Getter private boolean tenantComponentsInitEnabled; | |
201 | + @Getter | |
202 | + private boolean tenantComponentsInitEnabled; | |
153 | 203 | |
154 | - @Getter @Setter private ActorSystem actorSystem; | |
204 | + @Getter | |
205 | + @Setter | |
206 | + private ActorSystem actorSystem; | |
155 | 207 | |
156 | - @Getter @Setter private ActorRef appActor; | |
208 | + @Getter | |
209 | + @Setter | |
210 | + private ActorRef appActor; | |
157 | 211 | |
158 | - @Getter @Setter private ActorRef sessionManagerActor; | |
212 | + @Getter | |
213 | + @Setter | |
214 | + private ActorRef sessionManagerActor; | |
159 | 215 | |
160 | - @Getter @Setter private ActorRef statsActor; | |
216 | + @Getter | |
217 | + @Setter | |
218 | + private ActorRef statsActor; | |
161 | 219 | |
162 | - @Getter private final Config config; | |
220 | + @Getter | |
221 | + private final Config config; | |
163 | 222 | |
164 | 223 | public ActorSystemContext() { |
165 | 224 | config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); |
... | ... | @@ -191,7 +250,7 @@ public class ActorSystemContext { |
191 | 250 | eventService.save(event); |
192 | 251 | } |
193 | 252 | |
194 | - private String toString(Exception e) { | |
253 | + private String toString(Throwable e) { | |
195 | 254 | StringWriter sw = new StringWriter(); |
196 | 255 | e.printStackTrace(new PrintWriter(sw)); |
197 | 256 | return sw.toString(); |
... | ... | @@ -211,4 +270,69 @@ public class ActorSystemContext { |
211 | 270 | private JsonNode toBodyJson(ServerAddress server, String method, String body) { |
212 | 271 | return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body); |
213 | 272 | } |
273 | + | |
274 | + public String getServerAddress() { | |
275 | + return discoveryService.getCurrentServer().getServerAddress().toString(); | |
276 | + } | |
277 | + | |
278 | + public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg) { | |
279 | + persistDebug(tenantId, entityId, "IN", tbMsg, null); | |
280 | + } | |
281 | + | |
282 | + public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, Throwable error) { | |
283 | + persistDebug(tenantId, entityId, "IN", tbMsg, error); | |
284 | + } | |
285 | + | |
286 | + public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, Throwable error) { | |
287 | + persistDebug(tenantId, entityId, "OUT", tbMsg, error); | |
288 | + } | |
289 | + | |
290 | + public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg) { | |
291 | + persistDebug(tenantId, entityId, "OUT", tbMsg, null); | |
292 | + } | |
293 | + | |
294 | + private void persistDebug(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, Throwable error) { | |
295 | + Event event = new Event(); | |
296 | + event.setTenantId(tenantId); | |
297 | + event.setEntityId(entityId); | |
298 | + event.setType(DataConstants.DEBUG); | |
299 | + | |
300 | + ObjectNode node = mapper.createObjectNode() | |
301 | + .put("type", type) | |
302 | + .put("server", getServerAddress()) | |
303 | + .put("entityId", tbMsg.getOriginator().getId().toString()) | |
304 | + .put("entityName", tbMsg.getOriginator().getEntityType().name()) | |
305 | + .put("msgId", tbMsg.getId().toString()) | |
306 | + .put("msgType", tbMsg.getType()) | |
307 | + .put("dataType", tbMsg.getDataType().name()); | |
308 | + | |
309 | + ObjectNode mdNode = node.putObject("metadata"); | |
310 | + tbMsg.getMetaData().getData().forEach(mdNode::put); | |
311 | + | |
312 | + switch (tbMsg.getDataType()) { | |
313 | + case BINARY: | |
314 | + node.put("data", Base64Utils.encodeUrlSafe(tbMsg.getData())); | |
315 | + break; | |
316 | + default: | |
317 | + node.put("data", new String(tbMsg.getData(), StandardCharsets.UTF_8)); | |
318 | + break; | |
319 | + } | |
320 | + | |
321 | + if (error != null) { | |
322 | + node = node.put("error", toString(error)); | |
323 | + } | |
324 | + | |
325 | + event.setBody(node); | |
326 | + eventService.save(event); | |
327 | + } | |
328 | + | |
329 | + public static Exception toException(Throwable error) { | |
330 | + return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); | |
331 | + } | |
332 | + | |
333 | + public ListeningExecutor getExecutor() { | |
334 | + //TODO: take thread count from yml. | |
335 | + return new JsExecutorService(1); | |
336 | + } | |
337 | + | |
214 | 338 | } | ... | ... |
... | ... | @@ -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); | ... | ... |
... | ... | @@ -57,7 +57,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
57 | 57 | } |
58 | 58 | |
59 | 59 | @Override |
60 | - public void start() throws Exception { | |
60 | + public void start(ActorContext context) throws Exception { | |
61 | 61 | logger.info("[{}] Going to start plugin actor.", entityId); |
62 | 62 | pluginMd = systemContext.getPluginService().findPluginById(entityId); |
63 | 63 | if (pluginMd == null) { |
... | ... | @@ -76,7 +76,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
76 | 76 | } |
77 | 77 | |
78 | 78 | @Override |
79 | - public void stop() throws Exception { | |
79 | + public void stop(ActorContext context) throws Exception { | |
80 | 80 | onStop(); |
81 | 81 | } |
82 | 82 | |
... | ... | @@ -191,7 +191,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
191 | 191 | if (pluginImpl != null) { |
192 | 192 | pluginImpl.stop(trustedCtx); |
193 | 193 | } |
194 | - start(); | |
194 | + start(context); | |
195 | 195 | } |
196 | 196 | } |
197 | 197 | |
... | ... | @@ -217,7 +217,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> |
217 | 217 | pluginImpl.resume(trustedCtx); |
218 | 218 | logger.info("[{}] Plugin resumed.", entityId); |
219 | 219 | } else { |
220 | - start(); | |
220 | + start(context); | |
221 | 221 | } |
222 | 222 | } |
223 | 223 | ... | ... |
... | ... | @@ -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/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 org.thingsboard.rule.engine.api.ListeningExecutor; | |
19 | +import org.thingsboard.rule.engine.api.TbContext; | |
20 | +import org.thingsboard.server.actors.ActorSystemContext; | |
21 | +import org.thingsboard.server.common.msg.TbMsg; | |
22 | +import org.thingsboard.server.common.msg.cluster.ServerAddress; | |
23 | +import org.thingsboard.server.dao.alarm.AlarmService; | |
24 | +import org.thingsboard.server.dao.asset.AssetService; | |
25 | +import org.thingsboard.server.dao.attributes.AttributesService; | |
26 | +import org.thingsboard.server.dao.customer.CustomerService; | |
27 | +import org.thingsboard.server.dao.device.DeviceService; | |
28 | +import org.thingsboard.server.dao.plugin.PluginService; | |
29 | +import org.thingsboard.server.dao.relation.RelationService; | |
30 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
31 | +import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
32 | +import org.thingsboard.server.dao.user.UserService; | |
33 | + | |
34 | +import java.util.Set; | |
35 | + | |
36 | +/** | |
37 | + * Created by ashvayka on 19.03.18. | |
38 | + */ | |
39 | +class DefaultTbContext implements TbContext { | |
40 | + | |
41 | + private final ActorSystemContext mainCtx; | |
42 | + private final RuleNodeCtx nodeCtx; | |
43 | + | |
44 | + public DefaultTbContext(ActorSystemContext mainCtx, RuleNodeCtx nodeCtx) { | |
45 | + this.mainCtx = mainCtx; | |
46 | + this.nodeCtx = nodeCtx; | |
47 | + } | |
48 | + | |
49 | + @Override | |
50 | + public void tellNext(TbMsg msg) { | |
51 | + tellNext(msg, (String) null); | |
52 | + } | |
53 | + | |
54 | + @Override | |
55 | + public void tellNext(TbMsg msg, String relationType) { | |
56 | + if (nodeCtx.getSelf().isDebugMode()) { | |
57 | + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg); | |
58 | + } | |
59 | + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationType, msg), nodeCtx.getSelfActor()); | |
60 | + } | |
61 | + | |
62 | + @Override | |
63 | + public void tellSelf(TbMsg msg, long delayMs) { | |
64 | + throw new RuntimeException("Not Implemented!"); | |
65 | + } | |
66 | + | |
67 | + @Override | |
68 | + public void tellOthers(TbMsg msg) { | |
69 | + throw new RuntimeException("Not Implemented!"); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public void tellSibling(TbMsg msg, ServerAddress address) { | |
74 | + throw new RuntimeException("Not Implemented!"); | |
75 | + } | |
76 | + | |
77 | + @Override | |
78 | + public void spawn(TbMsg msg) { | |
79 | + throw new RuntimeException("Not Implemented!"); | |
80 | + } | |
81 | + | |
82 | + @Override | |
83 | + public void ack(TbMsg msg) { | |
84 | + | |
85 | + } | |
86 | + | |
87 | + @Override | |
88 | + public void tellError(TbMsg msg, Throwable th) { | |
89 | + if (nodeCtx.getSelf().isDebugMode()) { | |
90 | + mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, th); | |
91 | + } | |
92 | + nodeCtx.getSelfActor().tell(new RuleNodeToSelfErrorMsg(msg, th), nodeCtx.getSelfActor()); | |
93 | + } | |
94 | + | |
95 | + @Override | |
96 | + public void tellNext(TbMsg msg, Set<String> relationTypes) { | |
97 | + relationTypes.forEach(type -> tellNext(msg, type)); | |
98 | + } | |
99 | + | |
100 | + @Override | |
101 | + public ListeningExecutor getJsExecutor() { | |
102 | + return mainCtx.getExecutor(); | |
103 | + } | |
104 | + | |
105 | + @Override | |
106 | + public AttributesService getAttributesService() { | |
107 | + return mainCtx.getAttributesService(); | |
108 | + } | |
109 | + | |
110 | + @Override | |
111 | + public CustomerService getCustomerService() { | |
112 | + return mainCtx.getCustomerService(); | |
113 | + } | |
114 | + | |
115 | + @Override | |
116 | + public UserService getUserService() { | |
117 | + return mainCtx.getUserService(); | |
118 | + } | |
119 | + | |
120 | + @Override | |
121 | + public PluginService getPluginService() { | |
122 | + return mainCtx.getPluginService(); | |
123 | + } | |
124 | + | |
125 | + @Override | |
126 | + public AssetService getAssetService() { | |
127 | + return mainCtx.getAssetService(); | |
128 | + } | |
129 | + | |
130 | + @Override | |
131 | + public DeviceService getDeviceService() { | |
132 | + return mainCtx.getDeviceService(); | |
133 | + } | |
134 | + | |
135 | + @Override | |
136 | + public AlarmService getAlarmService() { | |
137 | + return mainCtx.getAlarmService(); | |
138 | + } | |
139 | + | |
140 | + @Override | |
141 | + public RuleChainService getRuleChainService() { | |
142 | + return mainCtx.getRuleChainService(); | |
143 | + } | |
144 | + | |
145 | + @Override | |
146 | + public TimeseriesService getTimeseriesService() { | |
147 | + return mainCtx.getTsService(); | |
148 | + } | |
149 | + | |
150 | + @Override | |
151 | + public RelationService getRelationService() { | |
152 | + return mainCtx.getRelationService(); | |
153 | + } | |
154 | +} | ... | ... |
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.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self); | |
96 | + } | |
97 | + } | |
98 | + | |
99 | + Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet()); | |
100 | + List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList()); | |
101 | + removedRules.forEach(ruleNodeId -> { | |
102 | + RuleNodeCtx removed = nodeActors.remove(ruleNodeId); | |
103 | + removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self); | |
104 | + }); | |
105 | + | |
106 | + initRoutes(ruleChain, ruleNodeList); | |
107 | + } | |
108 | + | |
109 | + @Override | |
110 | + public void stop(ActorContext context) throws Exception { | |
111 | + nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(context::stop); | |
112 | + nodeActors.clear(); | |
113 | + nodeRoutes.clear(); | |
114 | + context.stop(self); | |
115 | + } | |
116 | + | |
117 | + @Override | |
118 | + public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | |
119 | + | |
120 | + } | |
121 | + | |
122 | + private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) { | |
123 | + String dispatcherName = tenantId.getId().equals(EntityId.NULL_UUID) ? | |
124 | + DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME : DefaultActorService.TENANT_RULE_DISPATCHER_NAME; | |
125 | + return context.actorOf( | |
126 | + Props.create(new RuleNodeActor.ActorCreator(systemContext, tenantId, entityId, ruleNode.getId())) | |
127 | + .withDispatcher(dispatcherName), ruleNode.getId().toString()); | |
128 | + } | |
129 | + | |
130 | + private void initRoutes(RuleChain ruleChain, List<RuleNode> ruleNodeList) { | |
131 | + nodeRoutes.clear(); | |
132 | + // Populating the routes map; | |
133 | + for (RuleNode ruleNode : ruleNodeList) { | |
134 | + List<EntityRelation> relations = service.getRuleNodeRelations(ruleNode.getId()); | |
135 | + for (EntityRelation relation : relations) { | |
136 | + if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { | |
137 | + RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId())); | |
138 | + if (ruleNodeCtx == null) { | |
139 | + throw new IllegalArgumentException("Rule Node [" + relation.getFrom() + "] has invalid relation to Rule node [" + relation.getTo() + "]"); | |
140 | + } | |
141 | + } | |
142 | + nodeRoutes.computeIfAbsent(ruleNode.getId(), k -> new ArrayList<>()) | |
143 | + .add(new RuleNodeRelation(ruleNode.getId(), relation.getTo(), relation.getType())); | |
144 | + } | |
145 | + } | |
146 | + | |
147 | + firstId = ruleChain.getFirstRuleNodeId(); | |
148 | + firstNode = nodeActors.get(ruleChain.getFirstRuleNodeId()); | |
149 | + state = ComponentLifecycleState.ACTIVE; | |
150 | + } | |
151 | + | |
152 | + void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) { | |
153 | + checkActive(); | |
154 | + TbMsg tbMsg = envelope.getTbMsg(); | |
155 | + //TODO: push to queue and act on ack in async way | |
156 | + pushMstToNode(firstNode, tbMsg); | |
157 | + } | |
158 | + | |
159 | + void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) { | |
160 | + checkActive(); | |
161 | + RuleNodeId originator = envelope.getOriginator(); | |
162 | + String targetRelationType = envelope.getRelationType(); | |
163 | + List<RuleNodeRelation> relations = nodeRoutes.get(originator); | |
164 | + if (relations == null) { | |
165 | + return; | |
166 | + } | |
167 | + boolean copy = relations.size() > 1; | |
168 | + for (RuleNodeRelation relation : relations) { | |
169 | + TbMsg msg = envelope.getMsg(); | |
170 | + if (copy) { | |
171 | + msg = msg.copy(); | |
172 | + } | |
173 | + if (targetRelationType == null || targetRelationType.equalsIgnoreCase(relation.getType())) { | |
174 | + switch (relation.getOut().getEntityType()) { | |
175 | + case RULE_NODE: | |
176 | + RuleNodeId targetRuleNodeId = new RuleNodeId(relation.getOut().getId()); | |
177 | + RuleNodeCtx targetRuleNode = nodeActors.get(targetRuleNodeId); | |
178 | + pushMstToNode(targetRuleNode, msg); | |
179 | + break; | |
180 | + case RULE_CHAIN: | |
181 | +// TODO: implement | |
182 | + break; | |
183 | + } | |
184 | + } | |
185 | + } | |
186 | + } | |
187 | + | |
188 | + private void pushMstToNode(RuleNodeCtx nodeCtx, TbMsg msg) { | |
189 | + if (nodeCtx != null) { | |
190 | + nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self); | |
191 | + } | |
192 | + } | |
193 | + | |
194 | +} | ... | ... |
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 | +} | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java
renamed from
application/src/main/java/org/thingsboard/server/actors/rule/RuleActor.java
... | ... | @@ -13,78 +13,84 @@ |
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.rule; | |
16 | +package org.thingsboard.server.actors.ruleChain; | |
17 | 17 | |
18 | 18 | import org.thingsboard.server.actors.ActorSystemContext; |
19 | 19 | import org.thingsboard.server.actors.service.ComponentActor; |
20 | 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; | |
21 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
22 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
23 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
24 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
25 | 25 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
26 | -import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg; | |
27 | 26 | |
28 | -public class RuleActor extends ComponentActor<RuleId, RuleActorMessageProcessor> { | |
27 | +public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> { | |
29 | 28 | |
30 | - private RuleActor(ActorSystemContext systemContext, TenantId tenantId, RuleId ruleId) { | |
31 | - super(systemContext, tenantId, ruleId); | |
32 | - setProcessor(new RuleActorMessageProcessor(tenantId, ruleId, systemContext, logger)); | |
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())); | |
33 | 36 | } |
34 | 37 | |
35 | 38 | @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()); | |
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 | + default: | |
51 | + return false; | |
52 | + } | |
53 | + return true; | |
54 | + } | |
55 | + | |
56 | + private void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) { | |
57 | + logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg()); | |
58 | + try { | |
59 | + processor.onRuleChainToRuleNodeMsg(msg); | |
60 | + increaseMessagesProcessedCount(); | |
61 | + } catch (Exception e) { | |
62 | + logAndPersist("onRuleMsg", e); | |
65 | 63 | } |
66 | 64 | } |
67 | 65 | |
68 | - public static class ActorCreator extends ContextBasedCreator<RuleActor> { | |
66 | + private void onRuleNodeToSelfErrorMsg(RuleNodeToSelfErrorMsg msg) { | |
67 | + logAndPersist("onRuleMsg", ActorSystemContext.toException(msg.getError())); | |
68 | + } | |
69 | + | |
70 | + public static class ActorCreator extends ContextBasedCreator<RuleNodeActor> { | |
69 | 71 | private static final long serialVersionUID = 1L; |
70 | 72 | |
71 | 73 | private final TenantId tenantId; |
72 | - private final RuleId ruleId; | |
74 | + private final RuleChainId ruleChainId; | |
75 | + private final RuleNodeId ruleNodeId; | |
73 | 76 | |
74 | - public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleId ruleId) { | |
77 | + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { | |
75 | 78 | super(context); |
76 | 79 | this.tenantId = tenantId; |
77 | - this.ruleId = ruleId; | |
80 | + this.ruleChainId = ruleChainId; | |
81 | + this.ruleNodeId = ruleNodeId; | |
82 | + | |
78 | 83 | } |
79 | 84 | |
80 | 85 | @Override |
81 | - public RuleActor create() throws Exception { | |
82 | - return new RuleActor(context, tenantId, ruleId); | |
86 | + public RuleNodeActor create() throws Exception { | |
87 | + return new RuleNodeActor(context, tenantId, ruleChainId, ruleNodeId); | |
83 | 88 | } |
84 | 89 | } |
85 | 90 | |
86 | 91 | @Override |
87 | 92 | protected long getErrorPersistFrequency() { |
88 | - return systemContext.getRuleErrorPersistFrequency(); | |
93 | + return systemContext.getRuleNodeErrorPersistFrequency(); | |
89 | 94 | } |
95 | + | |
90 | 96 | } | ... | ... |
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.TbNode; | |
22 | +import org.thingsboard.rule.engine.api.TbNodeConfiguration; | |
23 | +import org.thingsboard.rule.engine.api.TbNodeState; | |
24 | +import org.thingsboard.server.actors.ActorSystemContext; | |
25 | +import org.thingsboard.server.actors.shared.ComponentMsgProcessor; | |
26 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
27 | +import org.thingsboard.server.common.data.id.RuleNodeId; | |
28 | +import org.thingsboard.server.common.data.id.TenantId; | |
29 | +import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
30 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
31 | +import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; | |
32 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
33 | + | |
34 | +/** | |
35 | + * @author Andrew Shvayka | |
36 | + */ | |
37 | +public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNodeId> { | |
38 | + | |
39 | + private final ActorRef parent; | |
40 | + private final ActorRef self; | |
41 | + private final RuleChainService service; | |
42 | + private RuleNode ruleNode; | |
43 | + private TbNode tbNode; | |
44 | + | |
45 | + RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext | |
46 | + , LoggingAdapter logger, ActorRef parent, ActorRef self) { | |
47 | + super(systemContext, logger, tenantId, ruleNodeId); | |
48 | + this.parent = parent; | |
49 | + this.self = self; | |
50 | + this.service = systemContext.getRuleChainService(); | |
51 | + this.ruleNode = systemContext.getRuleChainService().findRuleNodeById(entityId); | |
52 | + } | |
53 | + | |
54 | + @Override | |
55 | + public void start(ActorContext context) throws Exception { | |
56 | + tbNode = initComponent(ruleNode); | |
57 | + state = ComponentLifecycleState.ACTIVE; | |
58 | + } | |
59 | + | |
60 | + @Override | |
61 | + public void onUpdate(ActorContext context) throws Exception { | |
62 | + RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(entityId); | |
63 | + boolean restartRequired = !(ruleNode.getType().equals(newRuleNode.getType()) | |
64 | + && ruleNode.getConfiguration().equals(newRuleNode.getConfiguration())); | |
65 | + this.ruleNode = newRuleNode; | |
66 | + if (restartRequired) { | |
67 | + tbNode.destroy(); | |
68 | + start(context); | |
69 | + } | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public void stop(ActorContext context) throws Exception { | |
74 | + tbNode.destroy(); | |
75 | + context.stop(self); | |
76 | + } | |
77 | + | |
78 | + @Override | |
79 | + public void onClusterEventMsg(ClusterEventMsg msg) throws Exception { | |
80 | + | |
81 | + } | |
82 | + | |
83 | + void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) throws Exception { | |
84 | + checkActive(); | |
85 | + if (ruleNode.isDebugMode()) { | |
86 | + systemContext.persistDebugInput(tenantId, entityId, msg.getMsg()); | |
87 | + } | |
88 | + tbNode.onMsg(msg.getCtx(), msg.getMsg()); | |
89 | + } | |
90 | + | |
91 | + private TbNode initComponent(RuleNode ruleNode) throws Exception { | |
92 | + Class<?> componentClazz = Class.forName(ruleNode.getType()); | |
93 | + TbNode tbNode = (TbNode) (componentClazz.newInstance()); | |
94 | + tbNode.init(new TbNodeConfiguration(ruleNode.getConfiguration()), new TbNodeState()); | |
95 | + return tbNode; | |
96 | + } | |
97 | + | |
98 | + | |
99 | +} | ... | ... |
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.Data; | |
20 | +import org.thingsboard.server.common.data.id.TenantId; | |
21 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
22 | + | |
23 | +/** | |
24 | + * Created by ashvayka on 19.03.18. | |
25 | + */ | |
26 | +@Data | |
27 | +final class RuleNodeCtx { | |
28 | + private final TenantId tenantId; | |
29 | + private final ActorRef chainActor; | |
30 | + private final ActorRef selfActor; | |
31 | + private final RuleNode self; | |
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.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 | +} | ... | ... |
... | ... | @@ -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)) | ... | ... |
... | ... | @@ -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, | ... | ... |
... | ... | @@ -78,6 +78,9 @@ public class RuleChainController extends BaseController { |
78 | 78 | ruleChain.setTenantId(getCurrentUser().getTenantId()); |
79 | 79 | RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); |
80 | 80 | |
81 | + actorService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(), | |
82 | + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); | |
83 | + | |
81 | 84 | logEntityAction(savedRuleChain.getId(), savedRuleChain, |
82 | 85 | null, |
83 | 86 | created ? ActionType.ADDED : ActionType.UPDATED, null); |
... | ... | @@ -100,6 +103,8 @@ public class RuleChainController extends BaseController { |
100 | 103 | RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId()); |
101 | 104 | RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(ruleChainMetaData)); |
102 | 105 | |
106 | + actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); | |
107 | + | |
103 | 108 | logEntityAction(ruleChain.getId(), ruleChain, |
104 | 109 | null, |
105 | 110 | ActionType.UPDATED, null, ruleChainMetaData); |
... | ... | @@ -183,6 +188,8 @@ public class RuleChainController extends BaseController { |
183 | 188 | RuleChain ruleChain = checkRuleChain(ruleChainId); |
184 | 189 | ruleChainService.deleteRuleChainById(ruleChainId); |
185 | 190 | |
191 | + actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED); | |
192 | + | |
186 | 193 | logEntityAction(ruleChainId, ruleChain, |
187 | 194 | null, |
188 | 195 | ActionType.DELETED, null, strRuleChainId); | ... | ... |
... | ... | @@ -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, | ... | ... |
... | ... | @@ -26,6 +26,10 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen |
26 | 26 | import org.springframework.core.env.Environment; |
27 | 27 | import org.springframework.core.type.filter.AnnotationTypeFilter; |
28 | 28 | import org.springframework.stereotype.Service; |
29 | +import org.thingsboard.rule.engine.api.ActionNode; | |
30 | +import org.thingsboard.rule.engine.api.EnrichmentNode; | |
31 | +import org.thingsboard.rule.engine.api.FilterNode; | |
32 | +import org.thingsboard.rule.engine.api.TransformationNode; | |
29 | 33 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
30 | 34 | import org.thingsboard.server.common.data.plugin.ComponentType; |
31 | 35 | import org.thingsboard.server.dao.component.ComponentDescriptorService; |
... | ... | @@ -79,8 +83,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
79 | 83 | private List<ComponentDescriptor> persist(Set<BeanDefinition> filterDefs, ComponentType type) { |
80 | 84 | List<ComponentDescriptor> result = new ArrayList<>(); |
81 | 85 | for (BeanDefinition def : filterDefs) { |
82 | - ComponentDescriptor scannedComponent = scanAndPersistComponent(def, type); | |
83 | - result.add(scannedComponent); | |
86 | + result.add(scanAndPersistComponent(def, type)); | |
84 | 87 | } |
85 | 88 | return result; |
86 | 89 | } |
... | ... | @@ -93,24 +96,36 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
93 | 96 | Class<?> clazz = Class.forName(clazzName); |
94 | 97 | String descriptorResourceName; |
95 | 98 | switch (type) { |
99 | + case ENRICHMENT: | |
100 | + EnrichmentNode enrichmentAnnotation = clazz.getAnnotation(EnrichmentNode.class); | |
101 | + scannedComponent.setName(enrichmentAnnotation.name()); | |
102 | + scannedComponent.setScope(enrichmentAnnotation.scope()); | |
103 | + descriptorResourceName = enrichmentAnnotation.descriptor(); | |
104 | + break; | |
96 | 105 | case FILTER: |
97 | - Filter filterAnnotation = clazz.getAnnotation(Filter.class); | |
106 | + FilterNode filterAnnotation = clazz.getAnnotation(FilterNode.class); | |
98 | 107 | scannedComponent.setName(filterAnnotation.name()); |
99 | 108 | scannedComponent.setScope(filterAnnotation.scope()); |
100 | 109 | descriptorResourceName = filterAnnotation.descriptor(); |
101 | 110 | break; |
102 | - case PROCESSOR: | |
103 | - Processor processorAnnotation = clazz.getAnnotation(Processor.class); | |
104 | - scannedComponent.setName(processorAnnotation.name()); | |
105 | - scannedComponent.setScope(processorAnnotation.scope()); | |
106 | - descriptorResourceName = processorAnnotation.descriptor(); | |
111 | + case TRANSFORMATION: | |
112 | + TransformationNode trAnnotation = clazz.getAnnotation(TransformationNode.class); | |
113 | + scannedComponent.setName(trAnnotation.name()); | |
114 | + scannedComponent.setScope(trAnnotation.scope()); | |
115 | + descriptorResourceName = trAnnotation.descriptor(); | |
107 | 116 | break; |
108 | 117 | case ACTION: |
109 | - Action actionAnnotation = clazz.getAnnotation(Action.class); | |
118 | + ActionNode actionAnnotation = clazz.getAnnotation(ActionNode.class); | |
110 | 119 | scannedComponent.setName(actionAnnotation.name()); |
111 | 120 | scannedComponent.setScope(actionAnnotation.scope()); |
112 | 121 | descriptorResourceName = actionAnnotation.descriptor(); |
113 | 122 | break; |
123 | + case OLD_ACTION: | |
124 | + Action oldActionAnnotation = clazz.getAnnotation(Action.class); | |
125 | + scannedComponent.setName(oldActionAnnotation.name()); | |
126 | + scannedComponent.setScope(oldActionAnnotation.scope()); | |
127 | + descriptorResourceName = oldActionAnnotation.descriptor(); | |
128 | + break; | |
114 | 129 | case PLUGIN: |
115 | 130 | Plugin pluginAnnotation = clazz.getAnnotation(Plugin.class); |
116 | 131 | scannedComponent.setName(pluginAnnotation.name()); |
... | ... | @@ -122,12 +137,12 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
122 | 137 | log.error("Can't initialize plugin {}, due to missing action {}!", def.getBeanClassName(), actionClazz.getName()); |
123 | 138 | return new ClassNotFoundException("Action: " + actionClazz.getName() + "is missing!"); |
124 | 139 | }); |
125 | - if (actionComponent.getType() != ComponentType.ACTION) { | |
140 | + if (actionComponent.getType() != ComponentType.OLD_ACTION) { | |
126 | 141 | log.error("Plugin {} action {} has wrong component type!", def.getBeanClassName(), actionClazz.getName(), actionComponent.getType()); |
127 | 142 | throw new RuntimeException("Plugin " + def.getBeanClassName() + "action " + actionClazz.getName() + " has wrong component type!"); |
128 | 143 | } |
129 | 144 | } |
130 | - scannedComponent.setActions(Arrays.stream(pluginAnnotation.actions()).map(action -> action.getName()).collect(Collectors.joining(","))); | |
145 | + scannedComponent.setActions(Arrays.stream(pluginAnnotation.actions()).map(Class::getName).collect(Collectors.joining(","))); | |
131 | 146 | break; |
132 | 147 | default: |
133 | 148 | throw new RuntimeException(type + " is not supported yet!"); |
... | ... | @@ -168,11 +183,15 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
168 | 183 | |
169 | 184 | @Override |
170 | 185 | public void discoverComponents() { |
171 | - registerComponents(ComponentType.FILTER, Filter.class); | |
186 | + registerComponents(ComponentType.ENRICHMENT, EnrichmentNode.class); | |
187 | + | |
188 | + registerComponents(ComponentType.FILTER, FilterNode.class); | |
189 | + | |
190 | + registerComponents(ComponentType.TRANSFORMATION, TransformationNode.class); | |
172 | 191 | |
173 | - registerComponents(ComponentType.PROCESSOR, Processor.class); | |
192 | + registerComponents(ComponentType.ACTION, ActionNode.class); | |
174 | 193 | |
175 | - registerComponents(ComponentType.ACTION, Action.class); | |
194 | + registerComponents(ComponentType.OLD_ACTION, Action.class); | |
176 | 195 | |
177 | 196 | registerComponents(ComponentType.PLUGIN, Plugin.class); |
178 | 197 | |
... | ... | @@ -199,7 +218,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
199 | 218 | } |
200 | 219 | List<ComponentDescriptor> result = new ArrayList<>(); |
201 | 220 | for (String action : plugin.getActions().split(",")) { |
202 | - getComponent(action).ifPresent(v -> result.add(v)); | |
221 | + getComponent(action).ifPresent(result::add); | |
203 | 222 | } |
204 | 223 | return result; |
205 | 224 | } else { | ... | ... |
... | ... | @@ -62,7 +62,7 @@ cluster: |
62 | 62 | # Plugins configuration parameters |
63 | 63 | plugins: |
64 | 64 | # Comma seperated package list used during classpath scanning for plugins |
65 | - scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions}" | |
65 | + scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions,org.thingsboard.rule.engine}" | |
66 | 66 | |
67 | 67 | # JWT Token parameters |
68 | 68 | security.jwt: |
... | ... | @@ -215,6 +215,12 @@ actors: |
215 | 215 | termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}" |
216 | 216 | # Errors for particular actor are persisted once per specified amount of milliseconds |
217 | 217 | error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}" |
218 | + chain: | |
219 | + # Errors for particular actor are persisted once per specified amount of milliseconds | |
220 | + error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" | |
221 | + node: | |
222 | + # Errors for particular actor are persisted once per specified amount of milliseconds | |
223 | + error_persist_frequency: "${ACTORS_RULE_NODE_ERROR_FREQUENCY:3000}" | |
218 | 224 | statistics: |
219 | 225 | # Enable/disable actor statistics |
220 | 226 | enabled: "${ACTORS_STATISTICS_ENABLED:true}" | ... | ... |
... | ... | @@ -96,6 +96,8 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC |
96 | 96 | @Slf4j |
97 | 97 | public abstract class AbstractControllerTest { |
98 | 98 | |
99 | + protected ObjectMapper mapper = new ObjectMapper(); | |
100 | + | |
99 | 101 | protected static final String TEST_TENANT_NAME = "TEST TENANT"; |
100 | 102 | |
101 | 103 | protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org"; | ... | ... |
application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.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.controller; | |
17 | + | |
18 | +import com.fasterxml.jackson.core.type.TypeReference; | |
19 | +import org.thingsboard.server.common.data.DataConstants; | |
20 | +import org.thingsboard.server.common.data.Event; | |
21 | +import org.thingsboard.server.common.data.id.EntityId; | |
22 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
23 | +import org.thingsboard.server.common.data.id.TenantId; | |
24 | +import org.thingsboard.server.common.data.page.TimePageData; | |
25 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
26 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
27 | +import org.thingsboard.server.common.data.rule.RuleChainMetaData; | |
28 | + | |
29 | +/** | |
30 | + * Created by ashvayka on 20.03.18. | |
31 | + */ | |
32 | +public class AbstractRuleEngineControllerTest extends AbstractControllerTest { | |
33 | + | |
34 | + protected RuleChain saveRuleChain(RuleChain ruleChain) throws Exception { | |
35 | + return doPost("/api/ruleChain", ruleChain, RuleChain.class); | |
36 | + } | |
37 | + | |
38 | + protected RuleChain getRuleChain(RuleChainId ruleChainId) throws Exception { | |
39 | + return doGet("/api/ruleChain/" + ruleChainId.getId().toString(), RuleChain.class); | |
40 | + } | |
41 | + | |
42 | + protected RuleChainMetaData saveRuleChainMetaData(RuleChainMetaData ruleChainMD) throws Exception { | |
43 | + return doPost("/api/ruleChain/metadata", ruleChainMD, RuleChainMetaData.class); | |
44 | + } | |
45 | + | |
46 | + protected RuleChainMetaData getRuleChainMetaData(RuleChainId ruleChainId) throws Exception { | |
47 | + return doGet("/api/ruleChain/metadata/" + ruleChainId.getId().toString(), RuleChainMetaData.class); | |
48 | + } | |
49 | + | |
50 | + protected TimePageData<Event> getDebugEvents(TenantId tenantId, EntityId entityId, int limit) throws Exception { | |
51 | + TimePageLink pageLink = new TimePageLink(limit); | |
52 | + return doGetTypedWithTimePageLink("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&", | |
53 | + new TypeReference<TimePageData<Event>>() { | |
54 | + }, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG, tenantId.getId()); | |
55 | + } | |
56 | +} | ... | ... |
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.rules; | |
17 | + | |
18 | +import org.junit.ClassRule; | |
19 | +import org.junit.extensions.cpsuite.ClasspathSuite; | |
20 | +import org.junit.runner.RunWith; | |
21 | +import org.thingsboard.server.dao.CustomSqlUnit; | |
22 | + | |
23 | +import java.util.Arrays; | |
24 | + | |
25 | +@RunWith(ClasspathSuite.class) | |
26 | +@ClasspathSuite.ClassnameFilters({ | |
27 | + "org.thingsboard.server.rules.flow.*Test"}) | |
28 | +public class RuleEngineSqlTestSuite { | |
29 | + | |
30 | + @ClassRule | |
31 | + public static CustomSqlUnit sqlUnit = new CustomSqlUnit( | |
32 | + Arrays.asList("sql/schema.sql", "sql/system-data.sql"), | |
33 | + "sql/drop-all-tables.sql", | |
34 | + "sql-test.properties"); | |
35 | +} | ... | ... |
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.rules.flow; | |
17 | + | |
18 | +import com.datastax.driver.core.utils.UUIDs; | |
19 | +import lombok.Data; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.junit.After; | |
22 | +import org.junit.Assert; | |
23 | +import org.junit.Before; | |
24 | +import org.junit.Test; | |
25 | +import org.springframework.beans.factory.annotation.Autowired; | |
26 | +import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; | |
27 | +import org.thingsboard.server.actors.service.ActorService; | |
28 | +import org.thingsboard.server.common.data.*; | |
29 | +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | |
30 | +import org.thingsboard.server.common.data.kv.StringDataEntry; | |
31 | +import org.thingsboard.server.common.data.page.TimePageData; | |
32 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
33 | +import org.thingsboard.server.common.data.rule.RuleChainMetaData; | |
34 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
35 | +import org.thingsboard.server.common.data.security.Authority; | |
36 | +import org.thingsboard.server.common.msg.TbMsg; | |
37 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | |
38 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
39 | +import org.thingsboard.server.controller.AbstractRuleEngineControllerTest; | |
40 | +import org.thingsboard.server.dao.attributes.AttributesService; | |
41 | +import org.thingsboard.server.dao.rule.RuleChainService; | |
42 | + | |
43 | +import java.util.Arrays; | |
44 | +import java.util.Collections; | |
45 | + | |
46 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |
47 | + | |
48 | +/** | |
49 | + * @author Valerii Sosliuk | |
50 | + */ | |
51 | +@Slf4j | |
52 | +public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRuleEngineControllerTest { | |
53 | + | |
54 | + protected Tenant savedTenant; | |
55 | + protected User tenantAdmin; | |
56 | + | |
57 | + @Autowired | |
58 | + protected ActorService actorService; | |
59 | + | |
60 | + @Autowired | |
61 | + protected AttributesService attributesService; | |
62 | + | |
63 | + @Autowired | |
64 | + protected RuleChainService ruleChainService; | |
65 | + | |
66 | + @Before | |
67 | + public void beforeTest() throws Exception { | |
68 | + loginSysAdmin(); | |
69 | + | |
70 | + Tenant tenant = new Tenant(); | |
71 | + tenant.setTitle("My tenant"); | |
72 | + savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
73 | + Assert.assertNotNull(savedTenant); | |
74 | + | |
75 | + tenantAdmin = new User(); | |
76 | + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
77 | + tenantAdmin.setTenantId(savedTenant.getId()); | |
78 | + tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
79 | + tenantAdmin.setFirstName("Joe"); | |
80 | + tenantAdmin.setLastName("Downs"); | |
81 | + | |
82 | + createUserAndLogin(tenantAdmin, "testPassword1"); | |
83 | + } | |
84 | + | |
85 | + @After | |
86 | + public void afterTest() throws Exception { | |
87 | + loginSysAdmin(); | |
88 | + if (savedTenant != null) { | |
89 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk()); | |
90 | + } | |
91 | + } | |
92 | + | |
93 | + @Test | |
94 | + public void testRuleChainWithTwoRules() throws Exception { | |
95 | + // Creating Rule Chain | |
96 | + RuleChain ruleChain = new RuleChain(); | |
97 | + ruleChain.setName("Simple Rule Chain"); | |
98 | + ruleChain.setTenantId(savedTenant.getId()); | |
99 | + ruleChain.setRoot(true); | |
100 | + ruleChain.setDebugMode(true); | |
101 | + ruleChain = saveRuleChain(ruleChain); | |
102 | + Assert.assertNull(ruleChain.getFirstRuleNodeId()); | |
103 | + | |
104 | + RuleChainMetaData metaData = new RuleChainMetaData(); | |
105 | + metaData.setRuleChainId(ruleChain.getId()); | |
106 | + | |
107 | + RuleNode ruleNode1 = new RuleNode(); | |
108 | + ruleNode1.setName("Simple Rule Node 1"); | |
109 | + ruleNode1.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); | |
110 | + ruleNode1.setDebugMode(true); | |
111 | + TbGetAttributesNodeConfiguration configuration1 = new TbGetAttributesNodeConfiguration(); | |
112 | + configuration1.setServerAttributeNames(Collections.singletonList("serverAttributeKey1")); | |
113 | + ruleNode1.setConfiguration(mapper.valueToTree(configuration1)); | |
114 | + | |
115 | + RuleNode ruleNode2 = new RuleNode(); | |
116 | + ruleNode2.setName("Simple Rule Node 2"); | |
117 | + ruleNode2.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); | |
118 | + ruleNode2.setDebugMode(true); | |
119 | + TbGetAttributesNodeConfiguration configuration2 = new TbGetAttributesNodeConfiguration(); | |
120 | + configuration2.setServerAttributeNames(Collections.singletonList("serverAttributeKey2")); | |
121 | + ruleNode2.setConfiguration(mapper.valueToTree(configuration2)); | |
122 | + | |
123 | + | |
124 | + metaData.setNodes(Arrays.asList(ruleNode1, ruleNode2)); | |
125 | + metaData.setFirstNodeIndex(0); | |
126 | + metaData.addConnectionInfo(0, 1, "Success"); | |
127 | + metaData = saveRuleChainMetaData(metaData); | |
128 | + Assert.assertNotNull(metaData); | |
129 | + | |
130 | + ruleChain = getRuleChain(ruleChain.getId()); | |
131 | + Assert.assertNotNull(ruleChain.getFirstRuleNodeId()); | |
132 | + | |
133 | + // Saving the device | |
134 | + Device device = new Device(); | |
135 | + device.setName("My device"); | |
136 | + device.setType("default"); | |
137 | + device = doPost("/api/device", device, Device.class); | |
138 | + | |
139 | + attributesService.save(device.getId(), DataConstants.SERVER_SCOPE, | |
140 | + Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey1", "serverAttributeValue1"), System.currentTimeMillis()))); | |
141 | + attributesService.save(device.getId(), DataConstants.SERVER_SCOPE, | |
142 | + Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey2", "serverAttributeValue2"), System.currentTimeMillis()))); | |
143 | + | |
144 | + | |
145 | + Thread.sleep(1000); | |
146 | + | |
147 | + // Pushing Message to the system | |
148 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), | |
149 | + "CUSTOM", | |
150 | + device.getId(), | |
151 | + new TbMsgMetaData(), | |
152 | + new byte[]{}); | |
153 | + actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg)); | |
154 | + | |
155 | + Thread.sleep(3000); | |
156 | + | |
157 | + TimePageData<Event> events = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); | |
158 | + | |
159 | + Assert.assertEquals(2, events.getData().size()); | |
160 | + | |
161 | + Event inEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get(); | |
162 | + Assert.assertEquals(ruleChain.getFirstRuleNodeId(), inEvent.getEntityId()); | |
163 | + Assert.assertEquals(device.getId().getId().toString(), inEvent.getBody().get("entityId").asText()); | |
164 | + | |
165 | + Event outEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.OUT)).findFirst().get(); | |
166 | + Assert.assertEquals(ruleChain.getFirstRuleNodeId(), outEvent.getEntityId()); | |
167 | + Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText()); | |
168 | + | |
169 | + Assert.assertEquals("serverAttributeValue1", outEvent.getBody().get("metadata").get("ss.serverAttributeKey1").asText()); | |
170 | + | |
171 | + RuleChain finalRuleChain = ruleChain; | |
172 | + RuleNode lastRuleNode = metaData.getNodes().stream().filter(node -> !node.getId().equals(finalRuleChain.getFirstRuleNodeId())).findFirst().get(); | |
173 | + | |
174 | + events = getDebugEvents(savedTenant.getId(), lastRuleNode.getId(), 1000); | |
175 | + | |
176 | + Assert.assertEquals(2, events.getData().size()); | |
177 | + | |
178 | + inEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get(); | |
179 | + Assert.assertEquals(lastRuleNode.getId(), inEvent.getEntityId()); | |
180 | + Assert.assertEquals(device.getId().getId().toString(), inEvent.getBody().get("entityId").asText()); | |
181 | + | |
182 | + outEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.OUT)).findFirst().get(); | |
183 | + Assert.assertEquals(lastRuleNode.getId(), outEvent.getEntityId()); | |
184 | + Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText()); | |
185 | + | |
186 | + Assert.assertEquals("serverAttributeValue1", outEvent.getBody().get("metadata").get("ss.serverAttributeKey1").asText()); | |
187 | + Assert.assertEquals("serverAttributeValue2", outEvent.getBody().get("metadata").get("ss.serverAttributeKey2").asText()); | |
188 | + } | |
189 | + | |
190 | +} | ... | ... |
application/src/test/java/org/thingsboard/server/rules/flow/RuleEngineFlowSqlIntegrationTest.java
renamed from
dao/src/test/java/org/thingsboard/server/dao/service/rule/sql/RuleServiceSqlTest.java
... | ... | @@ -13,11 +13,14 @@ |
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.dao.service.rule.sql; | |
16 | +package org.thingsboard.server.rules.flow; | |
17 | 17 | |
18 | 18 | import org.thingsboard.server.dao.service.DaoSqlTest; |
19 | -import org.thingsboard.server.dao.service.rule.BaseRuleServiceTest; | |
19 | +import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcIntegrationTest; | |
20 | 20 | |
21 | +/** | |
22 | + * Created by Valerii Sosliuk on 8/22/2017. | |
23 | + */ | |
21 | 24 | @DaoSqlTest |
22 | -public class RuleServiceSqlTest extends BaseRuleServiceTest { | |
25 | +public class RuleEngineFlowSqlIntegrationTest extends AbstractRuleEngineFlowIntegrationTest { | |
23 | 26 | } | ... | ... |
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.rules.lifecycle; | |
17 | + | |
18 | +import com.datastax.driver.core.utils.UUIDs; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.junit.After; | |
21 | +import org.junit.Assert; | |
22 | +import org.junit.Before; | |
23 | +import org.junit.Test; | |
24 | +import org.springframework.beans.factory.annotation.Autowired; | |
25 | +import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; | |
26 | +import org.thingsboard.server.actors.service.ActorService; | |
27 | +import org.thingsboard.server.common.data.DataConstants; | |
28 | +import org.thingsboard.server.common.data.Device; | |
29 | +import org.thingsboard.server.common.data.Event; | |
30 | +import org.thingsboard.server.common.data.Tenant; | |
31 | +import org.thingsboard.server.common.data.User; | |
32 | +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | |
33 | +import org.thingsboard.server.common.data.kv.StringDataEntry; | |
34 | +import org.thingsboard.server.common.data.page.TimePageData; | |
35 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
36 | +import org.thingsboard.server.common.data.rule.RuleChainMetaData; | |
37 | +import org.thingsboard.server.common.data.rule.RuleNode; | |
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; | |
41 | +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg; | |
42 | +import org.thingsboard.server.controller.AbstractRuleEngineControllerTest; | |
43 | +import org.thingsboard.server.dao.attributes.AttributesService; | |
44 | + | |
45 | +import java.util.Collections; | |
46 | + | |
47 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |
48 | + | |
49 | +/** | |
50 | + * @author Valerii Sosliuk | |
51 | + */ | |
52 | +@Slf4j | |
53 | +public abstract class AbstractRuleEngineLifecycleIntegrationTest extends AbstractRuleEngineControllerTest { | |
54 | + | |
55 | + protected Tenant savedTenant; | |
56 | + protected User tenantAdmin; | |
57 | + | |
58 | + @Autowired | |
59 | + protected ActorService actorService; | |
60 | + | |
61 | + @Autowired | |
62 | + protected AttributesService attributesService; | |
63 | + | |
64 | + @Before | |
65 | + public void beforeTest() throws Exception { | |
66 | + loginSysAdmin(); | |
67 | + | |
68 | + Tenant tenant = new Tenant(); | |
69 | + tenant.setTitle("My tenant"); | |
70 | + savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
71 | + Assert.assertNotNull(savedTenant); | |
72 | + | |
73 | + tenantAdmin = new User(); | |
74 | + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
75 | + tenantAdmin.setTenantId(savedTenant.getId()); | |
76 | + tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
77 | + tenantAdmin.setFirstName("Joe"); | |
78 | + tenantAdmin.setLastName("Downs"); | |
79 | + | |
80 | + createUserAndLogin(tenantAdmin, "testPassword1"); | |
81 | + } | |
82 | + | |
83 | + @After | |
84 | + public void afterTest() throws Exception { | |
85 | + loginSysAdmin(); | |
86 | + if (savedTenant != null) { | |
87 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk()); | |
88 | + } | |
89 | + } | |
90 | + | |
91 | + @Test | |
92 | + public void testRuleChainWithOneRule() throws Exception { | |
93 | + // Creating Rule Chain | |
94 | + RuleChain ruleChain = new RuleChain(); | |
95 | + ruleChain.setName("Simple Rule Chain"); | |
96 | + ruleChain.setTenantId(savedTenant.getId()); | |
97 | + ruleChain.setRoot(true); | |
98 | + ruleChain.setDebugMode(true); | |
99 | + ruleChain = saveRuleChain(ruleChain); | |
100 | + Assert.assertNull(ruleChain.getFirstRuleNodeId()); | |
101 | + | |
102 | + RuleChainMetaData metaData = new RuleChainMetaData(); | |
103 | + metaData.setRuleChainId(ruleChain.getId()); | |
104 | + | |
105 | + RuleNode ruleNode = new RuleNode(); | |
106 | + ruleNode.setName("Simple Rule Node"); | |
107 | + ruleNode.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); | |
108 | + ruleNode.setDebugMode(true); | |
109 | + TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration(); | |
110 | + configuration.setServerAttributeNames(Collections.singletonList("serverAttributeKey")); | |
111 | + ruleNode.setConfiguration(mapper.valueToTree(configuration)); | |
112 | + | |
113 | + metaData.setNodes(Collections.singletonList(ruleNode)); | |
114 | + metaData.setFirstNodeIndex(0); | |
115 | + | |
116 | + metaData = saveRuleChainMetaData(metaData); | |
117 | + Assert.assertNotNull(metaData); | |
118 | + | |
119 | + ruleChain = getRuleChain(ruleChain.getId()); | |
120 | + Assert.assertNotNull(ruleChain.getFirstRuleNodeId()); | |
121 | + | |
122 | + // Saving the device | |
123 | + Device device = new Device(); | |
124 | + device.setName("My device"); | |
125 | + device.setType("default"); | |
126 | + device = doPost("/api/device", device, Device.class); | |
127 | + | |
128 | + attributesService.save(device.getId(), DataConstants.SERVER_SCOPE, | |
129 | + Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey", "serverAttributeValue"), System.currentTimeMillis()))); | |
130 | + | |
131 | + Thread.sleep(1000); | |
132 | + | |
133 | + // Pushing Message to the system | |
134 | + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), | |
135 | + "CUSTOM", | |
136 | + device.getId(), | |
137 | + new TbMsgMetaData(), | |
138 | + new byte[]{}); | |
139 | + actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg)); | |
140 | + | |
141 | + Thread.sleep(3000); | |
142 | + | |
143 | + TimePageData<Event> events = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); | |
144 | + | |
145 | + Assert.assertEquals(2, events.getData().size()); | |
146 | + | |
147 | + Event inEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get(); | |
148 | + Assert.assertEquals(ruleChain.getFirstRuleNodeId(), inEvent.getEntityId()); | |
149 | + Assert.assertEquals(device.getId().getId().toString(), inEvent.getBody().get("entityId").asText()); | |
150 | + | |
151 | + Event outEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.OUT)).findFirst().get(); | |
152 | + Assert.assertEquals(ruleChain.getFirstRuleNodeId(), outEvent.getEntityId()); | |
153 | + Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText()); | |
154 | + | |
155 | + Assert.assertEquals("serverAttributeValue", outEvent.getBody().get("metadata").get("ss.serverAttributeKey").asText()); | |
156 | + } | |
157 | + | |
158 | +} | ... | ... |
application/src/test/java/org/thingsboard/server/rules/lifecycle/RuleEngineLifecycleSqlIntegrationTest.java
renamed from
application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingMetaData.java
... | ... | @@ -13,29 +13,14 @@ |
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.rule; | |
16 | +package org.thingsboard.server.rules.lifecycle; | |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | -import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; | |
20 | -import org.thingsboard.server.extensions.api.device.DeviceMetaData; | |
18 | +import org.thingsboard.server.dao.service.DaoSqlTest; | |
19 | +import org.thingsboard.server.rules.flow.AbstractRuleEngineFlowIntegrationTest; | |
21 | 20 | |
22 | 21 | /** |
23 | - * Immutable part of chain processing data; | |
24 | - * | |
25 | - * @author ashvayka | |
22 | + * Created by Valerii Sosliuk on 8/22/2017. | |
26 | 23 | */ |
27 | -public final class ChainProcessingMetaData { | |
28 | - | |
29 | - final RuleActorChain chain; | |
30 | - final ToDeviceActorMsg inMsg; | |
31 | - final ActorRef originator; | |
32 | - final DeviceMetaData deviceMetaData; | |
33 | - | |
34 | - public ChainProcessingMetaData(RuleActorChain chain, ToDeviceActorMsg inMsg, DeviceMetaData deviceMetaData, ActorRef originator) { | |
35 | - super(); | |
36 | - this.chain = chain; | |
37 | - this.inMsg = inMsg; | |
38 | - this.originator = originator; | |
39 | - this.deviceMetaData = deviceMetaData; | |
40 | - } | |
24 | +@DaoSqlTest | |
25 | +public class RuleEngineLifecycleSqlIntegrationTest extends AbstractRuleEngineLifecycleIntegrationTest { | |
41 | 26 | } | ... | ... |
... | ... | @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
23 | 23 | |
24 | 24 | import com.fasterxml.jackson.databind.JsonNode; |
25 | 25 | |
26 | -public class Customer extends ContactBased<CustomerId> implements HasName { | |
26 | +public class Customer extends ContactBased<CustomerId> implements HasName, HasTenantId { | |
27 | 27 | |
28 | 28 | private static final long serialVersionUID = -1599722990298929275L; |
29 | 29 | ... | ... |
... | ... | @@ -37,7 +37,12 @@ public class DataConstants { |
37 | 37 | public static final String ERROR = "ERROR"; |
38 | 38 | public static final String LC_EVENT = "LC_EVENT"; |
39 | 39 | public static final String STATS = "STATS"; |
40 | + public static final String DEBUG = "DEBUG"; | |
40 | 41 | |
41 | 42 | public static final String ONEWAY = "ONEWAY"; |
42 | 43 | public static final String TWOWAY = "TWOWAY"; |
44 | + | |
45 | + public static final String IN = "IN"; | |
46 | + public static final String OUT = "OUT"; | |
47 | + | |
43 | 48 | } | ... | ... |
... | ... | @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
23 | 23 | import com.fasterxml.jackson.databind.JsonNode; |
24 | 24 | |
25 | 25 | @EqualsAndHashCode(callSuper = true) |
26 | -public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName { | |
26 | +public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implements HasName, HasTenantId, HasCustomerId { | |
27 | 27 | |
28 | 28 | private static final long serialVersionUID = 2807343040519543363L; |
29 | 29 | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/HasCustomerId.java
renamed from
application/src/main/java/org/thingsboard/server/actors/rule/CompoundRuleActorChain.java
... | ... | @@ -13,8 +13,11 @@ |
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.rule; | |
16 | +package org.thingsboard.server.common.data; | |
17 | 17 | |
18 | -public class CompoundRuleActorChain { | |
18 | +import org.thingsboard.server.common.data.id.CustomerId; | |
19 | 19 | |
20 | +public interface HasCustomerId { | |
21 | + | |
22 | + CustomerId getCustomerId(); | |
20 | 23 | } | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/HasTenantId.java
renamed from
application/src/main/java/org/thingsboard/server/actors/rule/RuleActorChain.java
... | ... | @@ -13,12 +13,11 @@ |
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.rule; | |
16 | +package org.thingsboard.server.common.data; | |
17 | 17 | |
18 | -public interface RuleActorChain { | |
18 | +import org.thingsboard.server.common.data.id.TenantId; | |
19 | 19 | |
20 | - int size(); | |
21 | - | |
22 | - RuleActorMetaData getRuleActorMd(int index); | |
20 | +public interface HasTenantId { | |
23 | 21 | |
22 | + TenantId getTenantId(); | |
24 | 23 | } | ... | ... |
... | ... | @@ -25,7 +25,7 @@ import org.thingsboard.server.common.data.security.Authority; |
25 | 25 | import com.fasterxml.jackson.databind.JsonNode; |
26 | 26 | |
27 | 27 | @EqualsAndHashCode(callSuper = true) |
28 | -public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements HasName { | |
28 | +public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements HasName, HasTenantId, HasCustomerId { | |
29 | 29 | |
30 | 30 | private static final long serialVersionUID = 8250339805336035966L; |
31 | 31 | ... | ... |
... | ... | @@ -22,6 +22,7 @@ import lombok.Builder; |
22 | 22 | import lombok.Data; |
23 | 23 | import org.thingsboard.server.common.data.BaseData; |
24 | 24 | import org.thingsboard.server.common.data.HasName; |
25 | +import org.thingsboard.server.common.data.HasTenantId; | |
25 | 26 | import org.thingsboard.server.common.data.id.EntityId; |
26 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
27 | 28 | |
... | ... | @@ -31,7 +32,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
31 | 32 | @Data |
32 | 33 | @Builder |
33 | 34 | @AllArgsConstructor |
34 | -public class Alarm extends BaseData<AlarmId> implements HasName { | |
35 | +public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId { | |
35 | 36 | |
36 | 37 | private TenantId tenantId; |
37 | 38 | private String type; | ... | ... |
... | ... | @@ -17,16 +17,13 @@ package org.thingsboard.server.common.data.asset; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import lombok.EqualsAndHashCode; |
20 | -import org.thingsboard.server.common.data.HasAdditionalInfo; | |
21 | -import org.thingsboard.server.common.data.HasName; | |
22 | -import org.thingsboard.server.common.data.SearchTextBased; | |
23 | -import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | |
20 | +import org.thingsboard.server.common.data.*; | |
24 | 21 | import org.thingsboard.server.common.data.id.AssetId; |
25 | 22 | import org.thingsboard.server.common.data.id.CustomerId; |
26 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
27 | 24 | |
28 | 25 | @EqualsAndHashCode(callSuper = true) |
29 | -public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements HasName { | |
26 | +public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements HasName, HasTenantId, HasCustomerId { | |
30 | 27 | |
31 | 28 | private static final long serialVersionUID = 2807343040519543363L; |
32 | 29 | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import java.util.List; |
20 | 20 | import java.util.NoSuchElementException; |
21 | 21 | |
22 | 22 | import org.thingsboard.server.common.data.SearchTextBased; |
23 | +import org.thingsboard.server.common.data.id.EntityId; | |
23 | 24 | import org.thingsboard.server.common.data.id.UUIDBased; |
24 | 25 | |
25 | 26 | public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> implements Iterable<T>, Iterator<T> { | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; |
21 | 21 | import lombok.EqualsAndHashCode; |
22 | 22 | import lombok.extern.slf4j.Slf4j; |
23 | 23 | import org.thingsboard.server.common.data.HasName; |
24 | +import org.thingsboard.server.common.data.HasTenantId; | |
24 | 25 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; |
25 | 26 | import org.thingsboard.server.common.data.id.PluginId; |
26 | 27 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -32,7 +33,7 @@ import java.io.IOException; |
32 | 33 | |
33 | 34 | @EqualsAndHashCode(callSuper = true) |
34 | 35 | @Slf4j |
35 | -public class PluginMetaData extends SearchTextBasedWithAdditionalInfo<PluginId> implements HasName { | |
36 | +public class PluginMetaData extends SearchTextBasedWithAdditionalInfo<PluginId> implements HasName, HasTenantId { | |
36 | 37 | |
37 | 38 | private static final long serialVersionUID = 1L; |
38 | 39 | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/rule/NodeConnectionInfo.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.common.data.rule; | |
17 | + | |
18 | +import lombok.Data; | |
19 | + | |
20 | +/** | |
21 | + * Created by ashvayka on 21.03.18. | |
22 | + */ | |
23 | +@Data | |
24 | +public class NodeConnectionInfo { | |
25 | + private int fromIndex; | |
26 | + private int toIndex; | |
27 | + private String type; | |
28 | +} | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import lombok.Data; |
21 | 21 | import lombok.EqualsAndHashCode; |
22 | 22 | import lombok.extern.slf4j.Slf4j; |
23 | 23 | import org.thingsboard.server.common.data.HasName; |
24 | +import org.thingsboard.server.common.data.HasTenantId; | |
24 | 25 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; |
25 | 26 | import org.thingsboard.server.common.data.id.RuleChainId; |
26 | 27 | import org.thingsboard.server.common.data.id.RuleNodeId; |
... | ... | @@ -29,7 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
29 | 30 | @Data |
30 | 31 | @EqualsAndHashCode(callSuper = true) |
31 | 32 | @Slf4j |
32 | -public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> implements HasName { | |
33 | +public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> implements HasName, HasTenantId { | |
33 | 34 | |
34 | 35 | private static final long serialVersionUID = -5656679015121935465L; |
35 | 36 | |
... | ... | @@ -37,6 +38,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im |
37 | 38 | private String name; |
38 | 39 | private RuleNodeId firstRuleNodeId; |
39 | 40 | private boolean root; |
41 | + private boolean debugMode; | |
40 | 42 | private transient JsonNode configuration; |
41 | 43 | @JsonIgnore |
42 | 44 | private byte[] configurationBytes; | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainConnectionInfo.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.common.data.rule; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
21 | + | |
22 | +/** | |
23 | + * Created by ashvayka on 21.03.18. | |
24 | + */ | |
25 | +@Data | |
26 | +public class RuleChainConnectionInfo { | |
27 | + private int fromIndex; | |
28 | + private RuleChainId targetRuleChainId; | |
29 | + private JsonNode additionalInfo; | |
30 | + private String type; | |
31 | +} | ... | ... |
... | ... | @@ -59,20 +59,4 @@ public class RuleChainMetaData { |
59 | 59 | } |
60 | 60 | ruleChainConnections.add(connectionInfo); |
61 | 61 | } |
62 | - | |
63 | - @Data | |
64 | - public static class NodeConnectionInfo { | |
65 | - private int fromIndex; | |
66 | - private int toIndex; | |
67 | - private String type; | |
68 | - } | |
69 | - | |
70 | - @Data | |
71 | - public static class RuleChainConnectionInfo { | |
72 | - private int fromIndex; | |
73 | - private RuleChainId targetRuleChainId; | |
74 | - private JsonNode additionalInfo; | |
75 | - private String type; | |
76 | - } | |
77 | - | |
78 | 62 | } | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import lombok.Data; |
23 | 23 | import lombok.EqualsAndHashCode; |
24 | 24 | import lombok.extern.slf4j.Slf4j; |
25 | 25 | import org.thingsboard.server.common.data.HasName; |
26 | +import org.thingsboard.server.common.data.HasTenantId; | |
26 | 27 | import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; |
27 | 28 | import org.thingsboard.server.common.data.id.RuleId; |
28 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -31,7 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
31 | 32 | @Data |
32 | 33 | @EqualsAndHashCode(callSuper = true) |
33 | 34 | @Slf4j |
34 | -public class RuleMetaData extends SearchTextBasedWithAdditionalInfo<RuleId> implements HasName { | |
35 | +public class RuleMetaData extends SearchTextBasedWithAdditionalInfo<RuleId> implements HasName, HasTenantId { | |
35 | 36 | |
36 | 37 | private static final long serialVersionUID = -5656679015122935465L; |
37 | 38 | ... | ... |
... | ... | @@ -34,6 +34,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl |
34 | 34 | |
35 | 35 | private String type; |
36 | 36 | private String name; |
37 | + private boolean debugMode; | |
37 | 38 | private transient JsonNode configuration; |
38 | 39 | @JsonIgnore |
39 | 40 | private byte[] configurationBytes; | ... | ... |
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.common.msg; | |
17 | + | |
18 | +/** | |
19 | + * Created by ashvayka on 15.03.18. | |
20 | + */ | |
21 | +public enum MsgType { | |
22 | + | |
23 | + /** | |
24 | + * ADDED/UPDATED/DELETED events for main entities. | |
25 | + * | |
26 | + * @See {@link org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg} | |
27 | + */ | |
28 | + COMPONENT_LIFE_CYCLE_MSG, | |
29 | + | |
30 | + /** | |
31 | + * Misc messages from the REST API/SERVICE layer to the new rule engine. | |
32 | + * | |
33 | + * @See {@link org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg} | |
34 | + */ | |
35 | + SERVICE_TO_RULE_ENGINE_MSG, | |
36 | + | |
37 | + | |
38 | + SESSION_TO_DEVICE_ACTOR_MSG, | |
39 | + DEVICE_ACTOR_TO_SESSION_MSG, | |
40 | + | |
41 | + | |
42 | + /** | |
43 | + * Message that is sent by RuleChainActor to RuleActor with command to process TbMsg. | |
44 | + */ | |
45 | + RULE_CHAIN_TO_RULE_MSG, | |
46 | + | |
47 | + /** | |
48 | + * Message that is sent by RuleActor to RuleChainActor with command to process TbMsg by next nodes in chain. | |
49 | + */ | |
50 | + RULE_TO_RULE_CHAIN_TELL_NEXT_MSG, | |
51 | + | |
52 | + /** | |
53 | + * Message that is sent by RuleActor implementation to RuleActor itself to log the error. | |
54 | + */ | |
55 | + RULE_TO_SELF_ERROR_MSG, | |
56 | + | |
57 | +} | ... | ... |
common/message/src/main/java/org/thingsboard/server/common/msg/TbActorMsg.java
renamed from
application/src/main/java/org/thingsboard/server/actors/rule/RuleTerminationMsg.java
... | ... | @@ -13,18 +13,13 @@ |
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.rule; | |
17 | - | |
18 | -import org.thingsboard.server.actors.shared.ActorTerminationMsg; | |
19 | -import org.thingsboard.server.common.data.id.PluginId; | |
20 | -import org.thingsboard.server.common.data.id.RuleId; | |
16 | +package org.thingsboard.server.common.msg; | |
21 | 17 | |
22 | 18 | /** |
23 | - * @author Andrew Shvayka | |
19 | + * Created by ashvayka on 15.03.18. | |
24 | 20 | */ |
25 | -public class RuleTerminationMsg extends ActorTerminationMsg<RuleId> { | |
21 | +public interface TbActorMsg { | |
22 | + | |
23 | + MsgType getMsgType(); | |
26 | 24 | |
27 | - public RuleTerminationMsg(RuleId id) { | |
28 | - super(id); | |
29 | - } | |
30 | 25 | } | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.common.msg; |
17 | 17 | |
18 | 18 | import com.google.protobuf.ByteString; |
19 | 19 | import com.google.protobuf.InvalidProtocolBufferException; |
20 | +import lombok.AllArgsConstructor; | |
20 | 21 | import lombok.Data; |
21 | 22 | import org.thingsboard.server.common.data.id.EntityId; |
22 | 23 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
... | ... | @@ -30,15 +31,25 @@ import java.util.UUID; |
30 | 31 | * Created by ashvayka on 13.01.18. |
31 | 32 | */ |
32 | 33 | @Data |
34 | +@AllArgsConstructor | |
33 | 35 | public final class TbMsg implements Serializable { |
34 | 36 | |
35 | 37 | private final UUID id; |
36 | 38 | private final String type; |
37 | 39 | private final EntityId originator; |
38 | 40 | private final TbMsgMetaData metaData; |
39 | - | |
41 | + private final TbMsgDataType dataType; | |
40 | 42 | private final byte[] data; |
41 | 43 | |
44 | + public TbMsg(UUID id, String type, EntityId originator, TbMsgMetaData metaData, byte[] data) { | |
45 | + this.id = id; | |
46 | + this.type = type; | |
47 | + this.originator = originator; | |
48 | + this.metaData = metaData; | |
49 | + this.dataType = TbMsgDataType.JSON; | |
50 | + this.data = data; | |
51 | + } | |
52 | + | |
42 | 53 | public static ByteBuffer toBytes(TbMsg msg) { |
43 | 54 | MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder(); |
44 | 55 | builder.setId(msg.getId().toString()); |
... | ... | @@ -49,11 +60,10 @@ public final class TbMsg implements Serializable { |
49 | 60 | } |
50 | 61 | |
51 | 62 | if (msg.getMetaData() != null) { |
52 | - MsgProtos.TbMsgProto.TbMsgMetaDataProto.Builder metadataBuilder = MsgProtos.TbMsgProto.TbMsgMetaDataProto.newBuilder(); | |
53 | - metadataBuilder.putAllData(msg.getMetaData().getData()); | |
54 | - builder.addMetaData(metadataBuilder.build()); | |
63 | + builder.setMetaData(MsgProtos.TbMsgMetaDataProto.newBuilder().putAllData(msg.getMetaData().getData()).build()); | |
55 | 64 | } |
56 | 65 | |
66 | + builder.setDataType(msg.getDataType().ordinal()); | |
57 | 67 | builder.setData(ByteString.copyFrom(msg.getData())); |
58 | 68 | byte[] bytes = builder.build().toByteArray(); |
59 | 69 | return ByteBuffer.wrap(bytes); |
... | ... | @@ -62,19 +72,19 @@ public final class TbMsg implements Serializable { |
62 | 72 | public static TbMsg fromBytes(ByteBuffer buffer) { |
63 | 73 | try { |
64 | 74 | MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array()); |
65 | - TbMsgMetaData metaData = new TbMsgMetaData(); | |
66 | - if (proto.getMetaDataCount() > 0) { | |
67 | - metaData.setData(proto.getMetaData(0).getDataMap()); | |
68 | - } | |
69 | - | |
70 | - EntityId entityId = null; | |
71 | - if (proto.getEntityId() != null) { | |
72 | - entityId = EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()); | |
73 | - } | |
74 | - | |
75 | - return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, proto.getData().toByteArray()); | |
75 | + TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); | |
76 | + EntityId entityId = EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()); | |
77 | + TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; | |
78 | + return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, dataType, proto.getData().toByteArray()); | |
76 | 79 | } catch (InvalidProtocolBufferException e) { |
77 | 80 | throw new IllegalStateException("Could not parse protobuf for TbMsg", e); |
78 | 81 | } |
79 | 82 | } |
83 | + | |
84 | + public TbMsg copy() { | |
85 | + int dataSize = data.length; | |
86 | + byte[] dataCopy = new byte[dataSize]; | |
87 | + System.arraycopy( data, 0, dataCopy, 0, data.length ); | |
88 | + return new TbMsg(id, type, originator, metaData.copy(), dataType, dataCopy); | |
89 | + } | |
80 | 90 | } | ... | ... |
common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgDataType.java
renamed from
common/message/src/main/java/org/thingsboard/server/common/msg/RuleMsg.java
... | ... | @@ -15,24 +15,12 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.msg; |
17 | 17 | |
18 | -import org.thingsboard.server.common.data.rule.Scope; | |
19 | -import org.thingsboard.server.common.data.rule.RuleType; | |
20 | -import org.thingsboard.server.common.msg.aware.RuleAwareMsg; | |
21 | - | |
22 | 18 | /** |
23 | - * Message that is used to deliver some data to the rule instance. | |
24 | - * For example: aggregated statistics or command decoded from http request. | |
25 | - * | |
26 | - * @author ashvayka | |
27 | - * | |
28 | - * @param <V> - payload | |
19 | + * Created by ashvayka on 15.03.18. | |
29 | 20 | */ |
30 | -public interface RuleMsg<V> extends RuleAwareMsg { | |
21 | +public enum TbMsgDataType { | |
22 | + | |
23 | + // Do not change ordering. We use ordinal to save some bytes on serialization | |
24 | + JSON, TEXT, BINARY; | |
31 | 25 | |
32 | - Scope getRuleLevel(); | |
33 | - | |
34 | - RuleType getRuleType(); | |
35 | - | |
36 | - V getPayload(); | |
37 | - | |
38 | 26 | } | ... | ... |
... | ... | @@ -15,9 +15,12 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.msg; |
17 | 17 | |
18 | +import lombok.AllArgsConstructor; | |
18 | 19 | import lombok.Data; |
20 | +import lombok.NoArgsConstructor; | |
19 | 21 | |
20 | 22 | import java.io.Serializable; |
23 | +import java.util.HashMap; | |
21 | 24 | import java.util.Map; |
22 | 25 | import java.util.concurrent.ConcurrentHashMap; |
23 | 26 | |
... | ... | @@ -25,10 +28,15 @@ import java.util.concurrent.ConcurrentHashMap; |
25 | 28 | * Created by ashvayka on 13.01.18. |
26 | 29 | */ |
27 | 30 | @Data |
31 | +@NoArgsConstructor | |
28 | 32 | public final class TbMsgMetaData implements Serializable { |
29 | 33 | |
30 | 34 | private Map<String, String> data = new ConcurrentHashMap<>(); |
31 | 35 | |
36 | + TbMsgMetaData(Map<String, String> data) { | |
37 | + this.data = data; | |
38 | + } | |
39 | + | |
32 | 40 | public String getValue(String key) { |
33 | 41 | return data.get(key); |
34 | 42 | } |
... | ... | @@ -37,4 +45,7 @@ public final class TbMsgMetaData implements Serializable { |
37 | 45 | data.put(key, value); |
38 | 46 | } |
39 | 47 | |
48 | + public TbMsgMetaData copy() { | |
49 | + return new TbMsgMetaData(new ConcurrentHashMap<>(data)); | |
50 | + } | |
40 | 51 | } | ... | ... |
... | ... | @@ -15,14 +15,14 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.common.msg.plugin; |
17 | 17 | |
18 | -import lombok.Data; | |
19 | 18 | import lombok.Getter; |
20 | 19 | import lombok.ToString; |
21 | -import org.thingsboard.server.common.data.id.PluginId; | |
22 | -import org.thingsboard.server.common.data.id.RuleId; | |
23 | -import org.thingsboard.server.common.data.id.TenantId; | |
20 | +import org.thingsboard.server.common.data.EntityType; | |
21 | +import org.thingsboard.server.common.data.id.*; | |
24 | 22 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
25 | -import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; | |
23 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
24 | +import org.thingsboard.server.common.msg.MsgType; | |
25 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
26 | 26 | import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
27 | 27 | import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; |
28 | 28 | |
... | ... | @@ -32,34 +32,34 @@ import java.util.Optional; |
32 | 32 | * @author Andrew Shvayka |
33 | 33 | */ |
34 | 34 | @ToString |
35 | -public class ComponentLifecycleMsg implements TenantAwareMsg, ToAllNodesMsg { | |
35 | +public class ComponentLifecycleMsg implements TbActorMsg, TenantAwareMsg, ToAllNodesMsg { | |
36 | 36 | @Getter |
37 | 37 | private final TenantId tenantId; |
38 | - private final PluginId pluginId; | |
39 | - private final RuleId ruleId; | |
38 | + @Getter | |
39 | + private final EntityId entityId; | |
40 | 40 | @Getter |
41 | 41 | private final ComponentLifecycleEvent event; |
42 | 42 | |
43 | - public static ComponentLifecycleMsg forPlugin(TenantId tenantId, PluginId pluginId, ComponentLifecycleEvent event) { | |
44 | - return new ComponentLifecycleMsg(tenantId, pluginId, null, event); | |
45 | - } | |
46 | - | |
47 | - public static ComponentLifecycleMsg forRule(TenantId tenantId, RuleId ruleId, ComponentLifecycleEvent event) { | |
48 | - return new ComponentLifecycleMsg(tenantId, null, ruleId, event); | |
49 | - } | |
50 | - | |
51 | - private ComponentLifecycleMsg(TenantId tenantId, PluginId pluginId, RuleId ruleId, ComponentLifecycleEvent event) { | |
43 | + public ComponentLifecycleMsg(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent event) { | |
52 | 44 | this.tenantId = tenantId; |
53 | - this.pluginId = pluginId; | |
54 | - this.ruleId = ruleId; | |
45 | + this.entityId = entityId; | |
55 | 46 | this.event = event; |
56 | 47 | } |
57 | 48 | |
58 | 49 | public Optional<PluginId> getPluginId() { |
59 | - return Optional.ofNullable(pluginId); | |
50 | + return entityId.getEntityType() == EntityType.PLUGIN ? Optional.of((PluginId) entityId) : Optional.empty(); | |
60 | 51 | } |
61 | 52 | |
62 | 53 | public Optional<RuleId> getRuleId() { |
63 | - return Optional.ofNullable(ruleId); | |
54 | + return entityId.getEntityType() == EntityType.RULE ? Optional.of((RuleId) entityId) : Optional.empty(); | |
55 | + } | |
56 | + | |
57 | + public Optional<RuleChainId> getRuleChainId() { | |
58 | + return entityId.getEntityType() == EntityType.RULE_CHAIN ? Optional.of((RuleChainId) entityId) : Optional.empty(); | |
59 | + } | |
60 | + | |
61 | + @Override | |
62 | + public MsgType getMsgType() { | |
63 | + return MsgType.COMPONENT_LIFE_CYCLE_MSG; | |
64 | 64 | } |
65 | 65 | } | ... | ... |
common/message/src/main/java/org/thingsboard/server/common/msg/system/ServiceToRuleEngineMsg.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.common.msg.system; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.id.TenantId; | |
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 15.03.18. | |
26 | + */ | |
27 | +@Data | |
28 | +public final class ServiceToRuleEngineMsg implements TbActorMsg { | |
29 | + | |
30 | + private final TenantId tenantId; | |
31 | + private final TbMsg tbMsg; | |
32 | + | |
33 | + @Override | |
34 | + public MsgType getMsgType() { | |
35 | + return MsgType.SERVICE_TO_RULE_ENGINE_MSG; | |
36 | + } | |
37 | +} | ... | ... |
... | ... | @@ -19,6 +19,9 @@ package msgqueue; |
19 | 19 | option java_package = "org.thingsboard.server.common.msg.gen"; |
20 | 20 | option java_outer_classname = "MsgProtos"; |
21 | 21 | |
22 | +message TbMsgMetaDataProto { | |
23 | + map<string, string> data = 1; | |
24 | +} | |
22 | 25 | |
23 | 26 | message TbMsgProto { |
24 | 27 | string id = 1; |
... | ... | @@ -26,11 +29,8 @@ message TbMsgProto { |
26 | 29 | string entityType = 3; |
27 | 30 | string entityId = 4; |
28 | 31 | |
29 | - message TbMsgMetaDataProto { | |
30 | - map<string, string> data = 1; | |
31 | - } | |
32 | + TbMsgMetaDataProto metaData = 5; | |
32 | 33 | |
33 | - repeated TbMsgMetaDataProto metaData = 5; | |
34 | - | |
35 | - bytes data = 6; | |
34 | + int32 dataType = 6; | |
35 | + bytes data = 7; | |
36 | 36 | } |
\ No newline at end of file | ... | ... |
... | ... | @@ -332,6 +332,8 @@ public class ModelConstants { |
332 | 332 | public static final String EVENT_BY_TYPE_AND_ID_VIEW_NAME = "event_by_type_and_id"; |
333 | 333 | public static final String EVENT_BY_ID_VIEW_NAME = "event_by_id"; |
334 | 334 | |
335 | + public static final String DEBUG_MODE = "debug_mode"; | |
336 | + | |
335 | 337 | /** |
336 | 338 | * Cassandra rule chain constants. |
337 | 339 | */ | ... | ... |
... | ... | @@ -22,6 +22,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey; |
22 | 22 | import com.datastax.driver.mapping.annotations.Table; |
23 | 23 | import com.fasterxml.jackson.databind.JsonNode; |
24 | 24 | import lombok.EqualsAndHashCode; |
25 | +import lombok.Getter; | |
26 | +import lombok.Setter; | |
25 | 27 | import lombok.ToString; |
26 | 28 | import org.thingsboard.server.common.data.id.RuleChainId; |
27 | 29 | import org.thingsboard.server.common.data.id.RuleNodeId; |
... | ... | @@ -54,6 +56,10 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> { |
54 | 56 | private UUID firstRuleNodeId; |
55 | 57 | @Column(name = RULE_CHAIN_ROOT_PROPERTY) |
56 | 58 | private boolean root; |
59 | + @Getter | |
60 | + @Setter | |
61 | + @Column(name = DEBUG_MODE) | |
62 | + private boolean debugMode; | |
57 | 63 | @Column(name = RULE_CHAIN_CONFIGURATION_PROPERTY, codec = JsonCodec.class) |
58 | 64 | private JsonNode configuration; |
59 | 65 | @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) |
... | ... | @@ -71,6 +77,7 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> { |
71 | 77 | this.searchText = ruleChain.getName(); |
72 | 78 | this.firstRuleNodeId = DaoUtil.getId(ruleChain.getFirstRuleNodeId()); |
73 | 79 | this.root = ruleChain.isRoot(); |
80 | + this.debugMode = ruleChain.isDebugMode(); | |
74 | 81 | this.configuration = ruleChain.getConfiguration(); |
75 | 82 | this.additionalInfo = ruleChain.getAdditionalInfo(); |
76 | 83 | } |
... | ... | @@ -157,6 +164,7 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> { |
157 | 164 | ruleChain.setFirstRuleNodeId(new RuleNodeId(this.firstRuleNodeId)); |
158 | 165 | } |
159 | 166 | ruleChain.setRoot(this.root); |
167 | + ruleChain.setDebugMode(this.debugMode); | |
160 | 168 | ruleChain.setConfiguration(this.configuration); |
161 | 169 | ruleChain.setAdditionalInfo(this.additionalInfo); |
162 | 170 | return ruleChain; | ... | ... |
... | ... | @@ -21,6 +21,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey; |
21 | 21 | import com.datastax.driver.mapping.annotations.Table; |
22 | 22 | import com.fasterxml.jackson.databind.JsonNode; |
23 | 23 | import lombok.EqualsAndHashCode; |
24 | +import lombok.Getter; | |
25 | +import lombok.Setter; | |
24 | 26 | import lombok.ToString; |
25 | 27 | import org.thingsboard.server.common.data.id.RuleNodeId; |
26 | 28 | import org.thingsboard.server.common.data.rule.RuleNode; |
... | ... | @@ -49,6 +51,11 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> { |
49 | 51 | private JsonNode configuration; |
50 | 52 | @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) |
51 | 53 | private JsonNode additionalInfo; |
54 | + @Getter | |
55 | + @Setter | |
56 | + @Column(name = DEBUG_MODE) | |
57 | + private boolean debugMode; | |
58 | + | |
52 | 59 | |
53 | 60 | public RuleNodeEntity() { |
54 | 61 | } |
... | ... | @@ -59,6 +66,7 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> { |
59 | 66 | } |
60 | 67 | this.type = ruleNode.getType(); |
61 | 68 | this.name = ruleNode.getName(); |
69 | + this.debugMode = ruleNode.isDebugMode(); | |
62 | 70 | this.searchText = ruleNode.getName(); |
63 | 71 | this.configuration = ruleNode.getConfiguration(); |
64 | 72 | this.additionalInfo = ruleNode.getAdditionalInfo(); |
... | ... | @@ -126,6 +134,7 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> { |
126 | 134 | ruleNode.setCreatedTime(UUIDs.unixTimestamp(id)); |
127 | 135 | ruleNode.setType(this.type); |
128 | 136 | ruleNode.setName(this.name); |
137 | + ruleNode.setDebugMode(this.debugMode); | |
129 | 138 | ruleNode.setConfiguration(this.configuration); |
130 | 139 | ruleNode.setAdditionalInfo(this.additionalInfo); |
131 | 140 | return ruleNode; | ... | ... |
... | ... | @@ -58,6 +58,9 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT |
58 | 58 | @Column(name = ModelConstants.RULE_CHAIN_ROOT_PROPERTY) |
59 | 59 | private boolean root; |
60 | 60 | |
61 | + @Column(name = ModelConstants.DEBUG_MODE) | |
62 | + private boolean debugMode; | |
63 | + | |
61 | 64 | @Type(type = "json") |
62 | 65 | @Column(name = ModelConstants.RULE_CHAIN_CONFIGURATION_PROPERTY) |
63 | 66 | private JsonNode configuration; |
... | ... | @@ -80,6 +83,7 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT |
80 | 83 | this.firstRuleNodeId = UUIDConverter.fromTimeUUID(ruleChain.getFirstRuleNodeId().getId()); |
81 | 84 | } |
82 | 85 | this.root = ruleChain.isRoot(); |
86 | + this.debugMode = ruleChain.isDebugMode(); | |
83 | 87 | this.configuration = ruleChain.getConfiguration(); |
84 | 88 | this.additionalInfo = ruleChain.getAdditionalInfo(); |
85 | 89 | } |
... | ... | @@ -104,6 +108,7 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT |
104 | 108 | ruleChain.setFirstRuleNodeId(new RuleNodeId(UUIDConverter.fromString(firstRuleNodeId))); |
105 | 109 | } |
106 | 110 | ruleChain.setRoot(root); |
111 | + ruleChain.setDebugMode(debugMode); | |
107 | 112 | ruleChain.setConfiguration(configuration); |
108 | 113 | ruleChain.setAdditionalInfo(additionalInfo); |
109 | 114 | return ruleChain; | ... | ... |