Commit 102586bed517377f1a7e068185bde05aacce93c6

Authored by Igor Kulikov
2 parents 6ece02f8 c31be45c

Merge with develop/1.5

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,6 +54,14 @@
54 <artifactId>extensions-api</artifactId> 54 <artifactId>extensions-api</artifactId>
55 </dependency> 55 </dependency>
56 <dependency> 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 <groupId>org.thingsboard</groupId> 65 <groupId>org.thingsboard</groupId>
58 <artifactId>extensions-core</artifactId> 66 <artifactId>extensions-core</artifactId>
59 </dependency> 67 </dependency>
@@ -69,6 +69,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_chain ( @@ -69,6 +69,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_chain (
69 search_text text, 69 search_text text,
70 first_rule_node_id uuid, 70 first_rule_node_id uuid,
71 root boolean, 71 root boolean,
  72 + debug_mode boolean,
72 configuration text, 73 configuration text,
73 additional_info text, 74 additional_info text,
74 PRIMARY KEY (id, tenant_id) 75 PRIMARY KEY (id, tenant_id)
@@ -85,6 +86,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_node ( @@ -85,6 +86,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_node (
85 id uuid, 86 id uuid,
86 type text, 87 type text,
87 name text, 88 name text,
  89 + debug_mode boolean,
88 search_text text, 90 search_text text,
89 configuration text, 91 configuration text,
90 additional_info text, 92 additional_info text,
@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS rule_chain ( @@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS rule_chain (
21 name varchar(255), 21 name varchar(255),
22 first_rule_node_id varchar(31), 22 first_rule_node_id varchar(31),
23 root boolean, 23 root boolean,
  24 + debug_mode boolean,
24 search_text varchar(255), 25 search_text varchar(255),
25 tenant_id varchar(31) 26 tenant_id varchar(31)
26 ); 27 );
@@ -31,5 +32,6 @@ CREATE TABLE IF NOT EXISTS rule_node ( @@ -31,5 +32,6 @@ CREATE TABLE IF NOT EXISTS rule_node (
31 configuration varchar(10000000), 32 configuration varchar(10000000),
32 type varchar(255), 33 type varchar(255),
33 name varchar(255), 34 name varchar(255),
  35 + debug_mode boolean,
34 search_text varchar(255) 36 search_text varchar(255)
35 ); 37 );
@@ -28,12 +28,16 @@ import lombok.Setter; @@ -28,12 +28,16 @@ import lombok.Setter;
28 import org.springframework.beans.factory.annotation.Autowired; 28 import org.springframework.beans.factory.annotation.Autowired;
29 import org.springframework.beans.factory.annotation.Value; 29 import org.springframework.beans.factory.annotation.Value;
30 import org.springframework.stereotype.Component; 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 import org.thingsboard.server.actors.service.ActorService; 34 import org.thingsboard.server.actors.service.ActorService;
32 import org.thingsboard.server.common.data.DataConstants; 35 import org.thingsboard.server.common.data.DataConstants;
33 import org.thingsboard.server.common.data.Event; 36 import org.thingsboard.server.common.data.Event;
34 import org.thingsboard.server.common.data.id.EntityId; 37 import org.thingsboard.server.common.data.id.EntityId;
35 import org.thingsboard.server.common.data.id.TenantId; 38 import org.thingsboard.server.common.data.id.TenantId;
36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 39 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
  40 +import org.thingsboard.server.common.msg.TbMsg;
37 import org.thingsboard.server.common.msg.cluster.ServerAddress; 41 import org.thingsboard.server.common.msg.cluster.ServerAddress;
38 import org.thingsboard.server.common.transport.auth.DeviceAuthService; 42 import org.thingsboard.server.common.transport.auth.DeviceAuthService;
39 import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint; 43 import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint;
@@ -50,6 +54,7 @@ import org.thingsboard.server.dao.rule.RuleChainService; @@ -50,6 +54,7 @@ import org.thingsboard.server.dao.rule.RuleChainService;
50 import org.thingsboard.server.dao.rule.RuleService; 54 import org.thingsboard.server.dao.rule.RuleService;
51 import org.thingsboard.server.dao.tenant.TenantService; 55 import org.thingsboard.server.dao.tenant.TenantService;
52 import org.thingsboard.server.dao.timeseries.TimeseriesService; 56 import org.thingsboard.server.dao.timeseries.TimeseriesService;
  57 +import org.thingsboard.server.dao.user.UserService;
53 import org.thingsboard.server.service.cluster.discovery.DiscoveryService; 58 import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
54 import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; 59 import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
55 import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; 60 import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
@@ -57,6 +62,7 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService; @@ -57,6 +62,7 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService;
57 62
58 import java.io.PrintWriter; 63 import java.io.PrintWriter;
59 import java.io.StringWriter; 64 import java.io.StringWriter;
  65 +import java.nio.charset.StandardCharsets;
60 import java.util.Optional; 66 import java.util.Optional;
61 67
62 @Component 68 @Component
@@ -65,101 +71,154 @@ public class ActorSystemContext { @@ -65,101 +71,154 @@ public class ActorSystemContext {
65 71
66 protected final ObjectMapper mapper = new ObjectMapper(); 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 @Autowired 78 @Autowired
71 - @Getter private DiscoveryService discoveryService; 79 + @Getter
  80 + private DiscoveryService discoveryService;
72 81
73 @Autowired 82 @Autowired
74 - @Getter @Setter private ComponentDiscoveryService componentService; 83 + @Getter
  84 + @Setter
  85 + private ComponentDiscoveryService componentService;
75 86
76 @Autowired 87 @Autowired
77 - @Getter private ClusterRoutingService routingService; 88 + @Getter
  89 + private ClusterRoutingService routingService;
78 90
79 @Autowired 91 @Autowired
80 - @Getter private ClusterRpcService rpcService; 92 + @Getter
  93 + private ClusterRpcService rpcService;
81 94
82 @Autowired 95 @Autowired
83 - @Getter private DeviceAuthService deviceAuthService; 96 + @Getter
  97 + private DeviceAuthService deviceAuthService;
84 98
85 @Autowired 99 @Autowired
86 - @Getter private DeviceService deviceService; 100 + @Getter
  101 + private DeviceService deviceService;
87 102
88 @Autowired 103 @Autowired
89 - @Getter private AssetService assetService; 104 + @Getter
  105 + private AssetService assetService;
90 106
91 @Autowired 107 @Autowired
92 - @Getter private TenantService tenantService; 108 + @Getter
  109 + private TenantService tenantService;
93 110
94 @Autowired 111 @Autowired
95 - @Getter private CustomerService customerService; 112 + @Getter
  113 + private CustomerService customerService;
96 114
97 @Autowired 115 @Autowired
98 - @Getter private RuleService ruleService; 116 + @Getter
  117 + private UserService userService;
99 118
100 @Autowired 119 @Autowired
101 - @Getter private RuleChainService ruleChainService; 120 + @Getter
  121 + private RuleService ruleService;
102 122
103 @Autowired 123 @Autowired
104 - @Getter private PluginService pluginService; 124 + @Getter
  125 + private RuleChainService ruleChainService;
105 126
106 @Autowired 127 @Autowired
107 - @Getter private TimeseriesService tsService; 128 + @Getter
  129 + private PluginService pluginService;
108 130
109 @Autowired 131 @Autowired
110 - @Getter private AttributesService attributesService; 132 + @Getter
  133 + private TimeseriesService tsService;
111 134
112 @Autowired 135 @Autowired
113 - @Getter private EventService eventService; 136 + @Getter
  137 + private AttributesService attributesService;
114 138
115 @Autowired 139 @Autowired
116 - @Getter private AlarmService alarmService; 140 + @Getter
  141 + private EventService eventService;
117 142
118 @Autowired 143 @Autowired
119 - @Getter private RelationService relationService; 144 + @Getter
  145 + private AlarmService alarmService;
120 146
121 @Autowired 147 @Autowired
122 - @Getter private AuditLogService auditLogService; 148 + @Getter
  149 + private RelationService relationService;
123 150
124 @Autowired 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 @Value("${actors.session.sync.timeout}") 160 @Value("${actors.session.sync.timeout}")
128 - @Getter private long syncSessionTimeout; 161 + @Getter
  162 + private long syncSessionTimeout;
129 163
130 @Value("${actors.plugin.termination.delay}") 164 @Value("${actors.plugin.termination.delay}")
131 - @Getter private long pluginActorTerminationDelay; 165 + @Getter
  166 + private long pluginActorTerminationDelay;
132 167
133 @Value("${actors.plugin.processing.timeout}") 168 @Value("${actors.plugin.processing.timeout}")
134 - @Getter private long pluginProcessingTimeout; 169 + @Getter
  170 + private long pluginProcessingTimeout;
135 171
136 @Value("${actors.plugin.error_persist_frequency}") 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 @Value("${actors.rule.termination.delay}") 184 @Value("${actors.rule.termination.delay}")
140 - @Getter private long ruleActorTerminationDelay; 185 + @Getter
  186 + private long ruleActorTerminationDelay;
141 187
142 @Value("${actors.rule.error_persist_frequency}") 188 @Value("${actors.rule.error_persist_frequency}")
143 - @Getter private long ruleErrorPersistFrequency; 189 + @Getter
  190 + private long ruleErrorPersistFrequency;
144 191
145 @Value("${actors.statistics.enabled}") 192 @Value("${actors.statistics.enabled}")
146 - @Getter private boolean statisticsEnabled; 193 + @Getter
  194 + private boolean statisticsEnabled;
147 195
148 @Value("${actors.statistics.persist_frequency}") 196 @Value("${actors.statistics.persist_frequency}")
149 - @Getter private long statisticsPersistFrequency; 197 + @Getter
  198 + private long statisticsPersistFrequency;
150 199
151 @Value("${actors.tenant.create_components_on_init}") 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 public ActorSystemContext() { 223 public ActorSystemContext() {
165 config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load()); 224 config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load());
@@ -191,7 +250,7 @@ public class ActorSystemContext { @@ -191,7 +250,7 @@ public class ActorSystemContext {
191 eventService.save(event); 250 eventService.save(event);
192 } 251 }
193 252
194 - private String toString(Exception e) { 253 + private String toString(Throwable e) {
195 StringWriter sw = new StringWriter(); 254 StringWriter sw = new StringWriter();
196 e.printStackTrace(new PrintWriter(sw)); 255 e.printStackTrace(new PrintWriter(sw));
197 return sw.toString(); 256 return sw.toString();
@@ -211,4 +270,69 @@ public class ActorSystemContext { @@ -211,4 +270,69 @@ public class ActorSystemContext {
211 private JsonNode toBodyJson(ServerAddress server, String method, String body) { 270 private JsonNode toBodyJson(ServerAddress server, String method, String body) {
212 return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body); 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,48 +22,41 @@ import akka.event.LoggingAdapter;
22 import akka.japi.Function; 22 import akka.japi.Function;
23 import org.thingsboard.server.actors.ActorSystemContext; 23 import org.thingsboard.server.actors.ActorSystemContext;
24 import org.thingsboard.server.actors.plugin.PluginTerminationMsg; 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 import org.thingsboard.server.actors.service.ContextBasedCreator; 26 import org.thingsboard.server.actors.service.ContextBasedCreator;
27 import org.thingsboard.server.actors.service.DefaultActorService; 27 import org.thingsboard.server.actors.service.DefaultActorService;
28 -import org.thingsboard.server.actors.shared.plugin.PluginManager;  
29 import org.thingsboard.server.actors.shared.plugin.SystemPluginManager; 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 import org.thingsboard.server.actors.tenant.TenantActor; 30 import org.thingsboard.server.actors.tenant.TenantActor;
34 import org.thingsboard.server.common.data.Tenant; 31 import org.thingsboard.server.common.data.Tenant;
35 import org.thingsboard.server.common.data.id.PluginId; 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 import org.thingsboard.server.common.data.id.TenantId; 34 import org.thingsboard.server.common.data.id.TenantId;
38 import org.thingsboard.server.common.data.page.PageDataIterable; 35 import org.thingsboard.server.common.data.page.PageDataIterable;
  36 +import org.thingsboard.server.common.msg.TbActorMsg;
39 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 37 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
40 import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; 38 import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
41 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 39 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
  40 +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
42 import org.thingsboard.server.dao.model.ModelConstants; 41 import org.thingsboard.server.dao.model.ModelConstants;
43 import org.thingsboard.server.dao.tenant.TenantService; 42 import org.thingsboard.server.dao.tenant.TenantService;
44 import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; 43 import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
45 import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg; 44 import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg;
46 -import org.thingsboard.server.extensions.api.rules.ToRuleActorMsg;  
47 import scala.concurrent.duration.Duration; 45 import scala.concurrent.duration.Duration;
48 46
49 import java.util.HashMap; 47 import java.util.HashMap;
50 import java.util.Map; 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 private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); 52 private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);
56 53
57 public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); 54 public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
58 - private final RuleManager ruleManager;  
59 - private final PluginManager pluginManager;  
60 private final TenantService tenantService; 55 private final TenantService tenantService;
61 private final Map<TenantId, ActorRef> tenantActors; 56 private final Map<TenantId, ActorRef> tenantActors;
62 57
63 private AppActor(ActorSystemContext systemContext) { 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 this.tenantService = systemContext.getTenantService(); 60 this.tenantService = systemContext.getTenantService();
68 this.tenantActors = new HashMap<>(); 61 this.tenantActors = new HashMap<>();
69 } 62 }
@@ -77,8 +70,7 @@ public class AppActor extends ContextAwareActor { @@ -77,8 +70,7 @@ public class AppActor extends ContextAwareActor {
77 public void preStart() { 70 public void preStart() {
78 logger.info("Starting main system actor."); 71 logger.info("Starting main system actor.");
79 try { 72 try {
80 - ruleManager.init(this.context());  
81 - pluginManager.init(this.context()); 73 + initRuleChains();
82 74
83 if (systemContext.isTenantComponentsInitEnabled()) { 75 if (systemContext.isTenantComponentsInitEnabled()) {
84 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT); 76 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);
@@ -96,29 +88,51 @@ public class AppActor extends ContextAwareActor { @@ -96,29 +88,51 @@ public class AppActor extends ContextAwareActor {
96 } 88 }
97 89
98 @Override 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 } else { 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 private void onPluginTerminated(PluginTerminationMsg msg) { 136 private void onPluginTerminated(PluginTerminationMsg msg) {
123 pluginManager.remove(msg.getId()); 137 pluginManager.remove(msg.getId());
124 } 138 }
@@ -128,20 +142,10 @@ public class AppActor extends ContextAwareActor { @@ -128,20 +142,10 @@ public class AppActor extends ContextAwareActor {
128 tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); 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 private void onToPluginMsg(ToPluginActorMsg msg) { 145 private void onToPluginMsg(ToPluginActorMsg msg) {
142 ActorRef target; 146 ActorRef target;
143 if (SYSTEM_TENANT.equals(msg.getPluginTenantId())) { 147 if (SYSTEM_TENANT.equals(msg.getPluginTenantId())) {
144 - target = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId()); 148 + target = pluginManager.getOrCreateActor(this.context(), msg.getPluginId());
145 } else { 149 } else {
146 target = getOrCreateTenantActor(msg.getPluginTenantId()); 150 target = getOrCreateTenantActor(msg.getPluginTenantId());
147 } 151 }
@@ -149,26 +153,16 @@ public class AppActor extends ContextAwareActor { @@ -149,26 +153,16 @@ public class AppActor extends ContextAwareActor {
149 } 153 }
150 154
151 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 155 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
152 - ActorRef target = null; 156 + ActorRef target;
153 if (SYSTEM_TENANT.equals(msg.getTenantId())) { 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 } else { 159 } else {
168 target = getOrCreateTenantActor(msg.getTenantId()); 160 target = getOrCreateTenantActor(msg.getTenantId());
169 } 161 }
170 if (target != null) { 162 if (target != null) {
171 target.tell(msg, ActorRef.noSender()); 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,7 +174,7 @@ public class AppActor extends ContextAwareActor {
180 TenantId tenantId = toDeviceActorMsg.getTenantId(); 174 TenantId tenantId = toDeviceActorMsg.getTenantId();
181 ActorRef tenantActor = getOrCreateTenantActor(tenantId); 175 ActorRef tenantActor = getOrCreateTenantActor(tenantId);
182 if (toDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) { 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 } else { 178 } else {
185 tenantActor.tell(toDeviceActorMsg, context().self()); 179 tenantActor.tell(toDeviceActorMsg, context().self());
186 } 180 }
@@ -18,19 +18,19 @@ package org.thingsboard.server.actors.device; @@ -18,19 +18,19 @@ package org.thingsboard.server.actors.device;
18 import akka.event.Logging; 18 import akka.event.Logging;
19 import akka.event.LoggingAdapter; 19 import akka.event.LoggingAdapter;
20 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
21 -import org.thingsboard.server.actors.rule.RulesProcessedMsg;  
22 import org.thingsboard.server.actors.service.ContextAwareActor; 21 import org.thingsboard.server.actors.service.ContextAwareActor;
23 import org.thingsboard.server.actors.service.ContextBasedCreator; 22 import org.thingsboard.server.actors.service.ContextBasedCreator;
24 -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg;  
25 import org.thingsboard.server.common.data.id.DeviceId; 23 import org.thingsboard.server.common.data.id.DeviceId;
26 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
  25 +import org.thingsboard.server.common.msg.TbActorMsg;
27 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 26 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
28 import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; 27 import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
29 import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg; 28 import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
30 import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg; 29 import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg;
31 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; 30 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
32 import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; 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 public class DeviceActor extends ContextAwareActor { 35 public class DeviceActor extends ContextAwareActor {
36 36
@@ -48,12 +48,17 @@ public class DeviceActor extends ContextAwareActor { @@ -48,12 +48,17 @@ public class DeviceActor extends ContextAwareActor {
48 } 48 }
49 49
50 @Override 50 @Override
  51 + protected boolean process(TbActorMsg msg) {
  52 + return false;
  53 + }
  54 +
  55 + @Override
51 public void onReceive(Object msg) throws Exception { 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 processor.process(context(), (ToDeviceActorMsg) msg); 62 processor.process(context(), (ToDeviceActorMsg) msg);
58 } else if (msg instanceof ToDeviceActorNotificationMsg) { 63 } else if (msg instanceof ToDeviceActorNotificationMsg) {
59 if (msg instanceof DeviceAttributesEventNotificationMsg) { 64 if (msg instanceof DeviceAttributesEventNotificationMsg) {
@@ -19,9 +19,7 @@ import akka.actor.ActorContext; @@ -19,9 +19,7 @@ import akka.actor.ActorContext;
19 import akka.actor.ActorRef; 19 import akka.actor.ActorRef;
20 import akka.event.LoggingAdapter; 20 import akka.event.LoggingAdapter;
21 import org.thingsboard.server.actors.ActorSystemContext; 21 import org.thingsboard.server.actors.ActorSystemContext;
22 -import org.thingsboard.server.actors.rule.*;  
23 import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; 22 import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
24 -import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg;  
25 import org.thingsboard.server.common.data.DataConstants; 23 import org.thingsboard.server.common.data.DataConstants;
26 import org.thingsboard.server.common.data.Device; 24 import org.thingsboard.server.common.data.Device;
27 import org.thingsboard.server.common.data.id.DeviceId; 25 import org.thingsboard.server.common.data.id.DeviceId;
@@ -37,15 +35,10 @@ import org.thingsboard.server.common.msg.session.FromDeviceMsg; @@ -37,15 +35,10 @@ import org.thingsboard.server.common.msg.session.FromDeviceMsg;
37 import org.thingsboard.server.common.msg.session.MsgType; 35 import org.thingsboard.server.common.msg.session.MsgType;
38 import org.thingsboard.server.common.msg.session.SessionType; 36 import org.thingsboard.server.common.msg.session.SessionType;
39 import org.thingsboard.server.common.msg.session.ToDeviceMsg; 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 import java.util.*; 43 import java.util.*;
51 import java.util.concurrent.ExecutionException; 44 import java.util.concurrent.ExecutionException;
@@ -230,18 +223,18 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -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 void processRpcResponses(ActorContext context, ToDeviceActorMsg msg) { 239 void processRpcResponses(ActorContext context, ToDeviceActorMsg msg) {
247 SessionId sessionId = msg.getSessionId(); 240 SessionId sessionId = msg.getSessionId();
@@ -302,18 +295,18 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso @@ -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 private void processSubscriptionCommands(ActorContext context, ToDeviceActorMsg msg) { 311 private void processSubscriptionCommands(ActorContext context, ToDeviceActorMsg msg) {
319 SessionId sessionId = msg.getSessionId(); 312 SessionId sessionId = msg.getSessionId();
@@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator;
23 import org.thingsboard.server.actors.stats.StatsPersistTick; 23 import org.thingsboard.server.actors.stats.StatsPersistTick;
24 import org.thingsboard.server.common.data.id.PluginId; 24 import org.thingsboard.server.common.data.id.PluginId;
25 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
  26 +import org.thingsboard.server.common.msg.TbActorMsg;
26 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 27 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
27 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 28 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
28 import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg; 29 import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
@@ -41,6 +42,12 @@ public class PluginActor extends ComponentActor<PluginId, PluginActorMessageProc @@ -41,6 +42,12 @@ public class PluginActor extends ComponentActor<PluginId, PluginActorMessageProc
41 } 42 }
42 43
43 @Override 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 public void onReceive(Object msg) throws Exception { 51 public void onReceive(Object msg) throws Exception {
45 if (msg instanceof PluginWebsocketMsg) { 52 if (msg instanceof PluginWebsocketMsg) {
46 onWebsocketMsg((PluginWebsocketMsg<?>) msg); 53 onWebsocketMsg((PluginWebsocketMsg<?>) msg);
@@ -57,7 +57,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> @@ -57,7 +57,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId>
57 } 57 }
58 58
59 @Override 59 @Override
60 - public void start() throws Exception { 60 + public void start(ActorContext context) throws Exception {
61 logger.info("[{}] Going to start plugin actor.", entityId); 61 logger.info("[{}] Going to start plugin actor.", entityId);
62 pluginMd = systemContext.getPluginService().findPluginById(entityId); 62 pluginMd = systemContext.getPluginService().findPluginById(entityId);
63 if (pluginMd == null) { 63 if (pluginMd == null) {
@@ -76,7 +76,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> @@ -76,7 +76,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId>
76 } 76 }
77 77
78 @Override 78 @Override
79 - public void stop() throws Exception { 79 + public void stop(ActorContext context) throws Exception {
80 onStop(); 80 onStop();
81 } 81 }
82 82
@@ -191,7 +191,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId> @@ -191,7 +191,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId>
191 if (pluginImpl != null) { 191 if (pluginImpl != null) {
192 pluginImpl.stop(trustedCtx); 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,7 +217,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor<PluginId>
217 pluginImpl.resume(trustedCtx); 217 pluginImpl.resume(trustedCtx);
218 logger.info("[{}] Plugin resumed.", entityId); 218 logger.info("[{}] Plugin resumed.", entityId);
219 } else { 219 } else {
220 - start(); 220 + start(context);
221 } 221 }
222 } 222 }
223 223
@@ -23,6 +23,7 @@ import org.thingsboard.server.actors.ActorSystemContext; @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.actors.service.ContextAwareActor; 23 import org.thingsboard.server.actors.service.ContextAwareActor;
24 import org.thingsboard.server.actors.service.ContextBasedCreator; 24 import org.thingsboard.server.actors.service.ContextBasedCreator;
25 import org.thingsboard.server.actors.service.DefaultActorService; 25 import org.thingsboard.server.actors.service.DefaultActorService;
  26 +import org.thingsboard.server.common.msg.TbActorMsg;
26 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 27 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
27 import org.thingsboard.server.common.msg.cluster.ServerAddress; 28 import org.thingsboard.server.common.msg.cluster.ServerAddress;
28 import org.thingsboard.server.gen.cluster.ClusterAPIProtos; 29 import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
@@ -57,6 +58,12 @@ public class RpcManagerActor extends ContextAwareActor { @@ -57,6 +58,12 @@ public class RpcManagerActor extends ContextAwareActor {
57 } 58 }
58 59
59 @Override 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 public void onReceive(Object msg) throws Exception { 67 public void onReceive(Object msg) throws Exception {
61 if (msg instanceof RpcSessionTellMsg) { 68 if (msg instanceof RpcSessionTellMsg) {
62 onMsg((RpcSessionTellMsg) msg); 69 onMsg((RpcSessionTellMsg) msg);
@@ -23,6 +23,7 @@ import io.grpc.stub.StreamObserver; @@ -23,6 +23,7 @@ import io.grpc.stub.StreamObserver;
23 import org.thingsboard.server.actors.ActorSystemContext; 23 import org.thingsboard.server.actors.ActorSystemContext;
24 import org.thingsboard.server.actors.service.ContextAwareActor; 24 import org.thingsboard.server.actors.service.ContextAwareActor;
25 import org.thingsboard.server.actors.service.ContextBasedCreator; 25 import org.thingsboard.server.actors.service.ContextBasedCreator;
  26 +import org.thingsboard.server.common.msg.TbActorMsg;
26 import org.thingsboard.server.common.msg.cluster.ServerAddress; 27 import org.thingsboard.server.common.msg.cluster.ServerAddress;
27 import org.thingsboard.server.gen.cluster.ClusterAPIProtos; 28 import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
28 import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; 29 import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc;
@@ -48,6 +49,12 @@ public class RpcSessionActor extends ContextAwareActor { @@ -48,6 +49,12 @@ public class RpcSessionActor extends ContextAwareActor {
48 } 49 }
49 50
50 @Override 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 public void onReceive(Object msg) throws Exception { 58 public void onReceive(Object msg) throws Exception {
52 if (msg instanceof RpcSessionTellMsg) { 59 if (msg instanceof RpcSessionTellMsg) {
53 tell((RpcSessionTellMsg) msg); 60 tell((RpcSessionTellMsg) msg);
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 -}  
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 -}  
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 -}  
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 +}
  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 +}
  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,78 +13,84 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.thingsboard.server.actors.rule; 16 +package org.thingsboard.server.actors.ruleChain;
17 17
18 import org.thingsboard.server.actors.ActorSystemContext; 18 import org.thingsboard.server.actors.ActorSystemContext;
19 import org.thingsboard.server.actors.service.ComponentActor; 19 import org.thingsboard.server.actors.service.ComponentActor;
20 import org.thingsboard.server.actors.service.ContextBasedCreator; 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 import org.thingsboard.server.common.data.id.TenantId; 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 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 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 @Override 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 private static final long serialVersionUID = 1L; 71 private static final long serialVersionUID = 1L;
70 72
71 private final TenantId tenantId; 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 super(context); 78 super(context);
76 this.tenantId = tenantId; 79 this.tenantId = tenantId;
77 - this.ruleId = ruleId; 80 + this.ruleChainId = ruleChainId;
  81 + this.ruleNodeId = ruleNodeId;
  82 +
78 } 83 }
79 84
80 @Override 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 @Override 91 @Override
87 protected long getErrorPersistFrequency() { 92 protected long getErrorPersistFrequency() {
88 - return systemContext.getRuleErrorPersistFrequency(); 93 + return systemContext.getRuleNodeErrorPersistFrequency();
89 } 94 }
  95 +
90 } 96 }
  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 +}
  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,20 +15,19 @@
15 */ 15 */
16 package org.thingsboard.server.actors.service; 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 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 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 import org.thingsboard.server.common.transport.SessionMsgProcessor; 22 import org.thingsboard.server.common.transport.SessionMsgProcessor;
24 import org.thingsboard.server.service.cluster.discovery.DiscoveryServiceListener; 23 import org.thingsboard.server.service.cluster.discovery.DiscoveryServiceListener;
25 import org.thingsboard.server.service.cluster.rpc.RpcMsgListener; 24 import org.thingsboard.server.service.cluster.rpc.RpcMsgListener;
26 25
27 public interface ActorService extends SessionMsgProcessor, WebSocketMsgProcessor, RestMsgProcessor, RpcMsgListener, DiscoveryServiceListener { 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 void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId); 32 void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId);
34 33
@@ -54,7 +54,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -54,7 +54,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
54 @Override 54 @Override
55 public void preStart() { 55 public void preStart() {
56 try { 56 try {
57 - processor.start(); 57 + processor.start(context());
58 logLifecycleEvent(ComponentLifecycleEvent.STARTED); 58 logLifecycleEvent(ComponentLifecycleEvent.STARTED);
59 if (systemContext.isStatisticsEnabled()) { 59 if (systemContext.isStatisticsEnabled()) {
60 scheduleStatsPersistTick(); 60 scheduleStatsPersistTick();
@@ -78,7 +78,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -78,7 +78,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
78 @Override 78 @Override
79 public void postStop() { 79 public void postStop() {
80 try { 80 try {
81 - processor.stop(); 81 + processor.stop(context());
82 logLifecycleEvent(ComponentLifecycleEvent.STOPPED); 82 logLifecycleEvent(ComponentLifecycleEvent.STOPPED);
83 } catch (Exception e) { 83 } catch (Exception e) {
84 logger.warning("[{}][{}] Failed to stop {} processor: {}", tenantId, id, id.getEntityType(), e.getMessage()); 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,7 +141,6 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
141 messagesProcessed++; 141 messagesProcessed++;
142 } 142 }
143 143
144 -  
145 protected void logAndPersist(String method, Exception e) { 144 protected void logAndPersist(String method, Exception e) {
146 logAndPersist(method, e, false); 145 logAndPersist(method, e, false);
147 } 146 }
@@ -16,9 +16,13 @@ @@ -16,9 +16,13 @@
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
18 import akka.actor.UntypedActor; 18 import akka.actor.UntypedActor;
  19 +import akka.event.Logging;
  20 +import akka.event.LoggingAdapter;
19 import org.thingsboard.server.actors.ActorSystemContext; 21 import org.thingsboard.server.actors.ActorSystemContext;
  22 +import org.thingsboard.server.common.msg.TbActorMsg;
20 23
21 public abstract class ContextAwareActor extends UntypedActor { 24 public abstract class ContextAwareActor extends UntypedActor {
  25 + protected final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);
22 26
23 public static final int ENTITY_PACK_LIMIT = 1024; 27 public static final int ENTITY_PACK_LIMIT = 1024;
24 28
@@ -28,4 +32,20 @@ public abstract class ContextAwareActor extends UntypedActor { @@ -28,4 +32,20 @@ public abstract class ContextAwareActor extends UntypedActor {
28 super(); 32 super();
29 this.systemContext = systemContext; 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,16 +30,14 @@ import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg;
30 import org.thingsboard.server.actors.rpc.RpcSessionTellMsg; 30 import org.thingsboard.server.actors.rpc.RpcSessionTellMsg;
31 import org.thingsboard.server.actors.session.SessionManagerActor; 31 import org.thingsboard.server.actors.session.SessionManagerActor;
32 import org.thingsboard.server.actors.stats.StatsActor; 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 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 34 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
38 import org.thingsboard.server.common.msg.aware.SessionAwareMsg; 35 import org.thingsboard.server.common.msg.aware.SessionAwareMsg;
39 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 36 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
40 import org.thingsboard.server.common.msg.cluster.ServerAddress; 37 import org.thingsboard.server.common.msg.cluster.ServerAddress;
41 import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; 38 import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
42 import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; 39 import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
  40 +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
43 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg; 41 import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
44 import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; 42 import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
45 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 43 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
@@ -129,6 +127,11 @@ public class DefaultActorService implements ActorService { @@ -129,6 +127,11 @@ public class DefaultActorService implements ActorService {
129 } 127 }
130 128
131 @Override 129 @Override
  130 + public void onMsg(ServiceToRuleEngineMsg msg) {
  131 + appActor.tell(msg, ActorRef.noSender());
  132 + }
  133 +
  134 + @Override
132 public void process(SessionAwareMsg msg) { 135 public void process(SessionAwareMsg msg) {
133 log.debug("Processing session aware msg: {}", msg); 136 log.debug("Processing session aware msg: {}", msg);
134 sessionManagerActor.tell(msg, ActorRef.noSender()); 137 sessionManagerActor.tell(msg, ActorRef.noSender());
@@ -212,15 +215,9 @@ public class DefaultActorService implements ActorService { @@ -212,15 +215,9 @@ public class DefaultActorService implements ActorService {
212 } 215 }
213 216
214 @Override 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 @Override 223 @Override
@@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextAwareActor; @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextAwareActor;
23 import org.thingsboard.server.actors.service.ContextBasedCreator; 23 import org.thingsboard.server.actors.service.ContextBasedCreator;
24 import org.thingsboard.server.actors.shared.SessionTimeoutMsg; 24 import org.thingsboard.server.actors.shared.SessionTimeoutMsg;
25 import org.thingsboard.server.common.data.id.SessionId; 25 import org.thingsboard.server.common.data.id.SessionId;
  26 +import org.thingsboard.server.common.msg.TbActorMsg;
26 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 27 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
27 import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; 28 import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg;
28 import org.thingsboard.server.common.msg.session.ToDeviceActorSessionMsg; 29 import org.thingsboard.server.common.msg.session.ToDeviceActorSessionMsg;
@@ -61,6 +62,12 @@ public class SessionActor extends ContextAwareActor { @@ -61,6 +62,12 @@ public class SessionActor extends ContextAwareActor {
61 } 62 }
62 63
63 @Override 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 public void onReceive(Object msg) throws Exception { 71 public void onReceive(Object msg) throws Exception {
65 logger.debug("[{}] Processing: {}.", sessionId, msg); 72 logger.debug("[{}] Processing: {}.", sessionId, msg);
66 if (msg instanceof ToDeviceActorSessionMsg) { 73 if (msg instanceof ToDeviceActorSessionMsg) {
@@ -26,6 +26,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; @@ -26,6 +26,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator;
26 import org.thingsboard.server.actors.service.DefaultActorService; 26 import org.thingsboard.server.actors.service.DefaultActorService;
27 import org.thingsboard.server.actors.shared.SessionTimeoutMsg; 27 import org.thingsboard.server.actors.shared.SessionTimeoutMsg;
28 import org.thingsboard.server.common.data.id.SessionId; 28 import org.thingsboard.server.common.data.id.SessionId;
  29 +import org.thingsboard.server.common.msg.TbActorMsg;
29 import org.thingsboard.server.common.msg.aware.SessionAwareMsg; 30 import org.thingsboard.server.common.msg.aware.SessionAwareMsg;
30 31
31 import akka.event.Logging; 32 import akka.event.Logging;
@@ -49,6 +50,12 @@ public class SessionManagerActor extends ContextAwareActor { @@ -49,6 +50,12 @@ public class SessionManagerActor extends ContextAwareActor {
49 } 50 }
50 51
51 @Override 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 public void onReceive(Object msg) throws Exception { 59 public void onReceive(Object msg) throws Exception {
53 if (msg instanceof SessionCtrlMsg) { 60 if (msg instanceof SessionCtrlMsg) {
54 onSessionCtrlMsg((SessionCtrlMsg) msg); 61 onSessionCtrlMsg((SessionCtrlMsg) msg);
@@ -102,9 +102,6 @@ public abstract class AbstractContextAwareMsgProcessor { @@ -102,9 +102,6 @@ public abstract class AbstractContextAwareMsgProcessor {
102 case FILTER: 102 case FILTER:
103 configurationClazz = ((Filter) componentClazz.getAnnotation(Filter.class)).configuration(); 103 configurationClazz = ((Filter) componentClazz.getAnnotation(Filter.class)).configuration();
104 break; 104 break;
105 - case PROCESSOR:  
106 - configurationClazz = ((Processor) componentClazz.getAnnotation(Processor.class)).configuration();  
107 - break;  
108 case ACTION: 105 case ACTION:
109 configurationClazz = ((Action) componentClazz.getAnnotation(Action.class)).configuration(); 106 configurationClazz = ((Action) componentClazz.getAnnotation(Action.class)).configuration();
110 break; 107 break;
@@ -20,12 +20,14 @@ import akka.event.LoggingAdapter; @@ -20,12 +20,14 @@ import akka.event.LoggingAdapter;
20 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
21 import org.thingsboard.server.actors.stats.StatsPersistTick; 21 import org.thingsboard.server.actors.stats.StatsPersistTick;
22 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
23 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; 24 import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
24 25
25 public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgProcessor { 26 public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgProcessor {
26 27
27 protected final TenantId tenantId; 28 protected final TenantId tenantId;
28 protected final T entityId; 29 protected final T entityId;
  30 + protected ComponentLifecycleState state;
29 31
30 protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) { 32 protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) {
31 super(systemContext, logger); 33 super(systemContext, logger);
@@ -33,23 +35,44 @@ public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgPr @@ -33,23 +35,44 @@ public abstract class ComponentMsgProcessor<T> extends AbstractContextAwareMsgPr
33 this.entityId = id; 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 public void scheduleStatsPersistTick(ActorContext context, long statsPersistFrequency) { 69 public void scheduleStatsPersistTick(ActorContext context, long statsPersistFrequency) {
53 schedulePeriodicMsgWithDelay(context, new StatsPersistTick(), statsPersistFrequency, statsPersistFrequency); 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,63 +15,28 @@
15 */ 15 */
16 package org.thingsboard.server.actors.shared.plugin; 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 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
22 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.actors.plugin.PluginActor; 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 import org.thingsboard.server.common.data.id.PluginId; 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 import org.thingsboard.server.common.data.plugin.PluginMetaData; 24 import org.thingsboard.server.common.data.plugin.PluginMetaData;
30 import org.thingsboard.server.dao.plugin.PluginService; 25 import org.thingsboard.server.dao.plugin.PluginService;
31 26
32 -import java.util.HashMap;  
33 -import java.util.Map;  
34 -  
35 @Slf4j 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 protected final PluginService pluginService; 30 protected final PluginService pluginService;
40 - protected final Map<PluginId, ActorRef> pluginActors;  
41 31
42 public PluginManager(ActorSystemContext systemContext) { 32 public PluginManager(ActorSystemContext systemContext) {
43 - this.systemContext = systemContext; 33 + super(systemContext);
44 this.pluginService = systemContext.getPluginService(); 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,12 +29,12 @@ public class SystemPluginManager extends PluginManager {
29 } 29 }
30 30
31 @Override 31 @Override
32 - FetchFunction<PluginMetaData> getFetchPluginsFunction() { 32 + protected FetchFunction<PluginMetaData> getFetchEntitiesFunction() {
33 return pluginService::findSystemPlugins; 33 return pluginService::findSystemPlugins;
34 } 34 }
35 35
36 @Override 36 @Override
37 - TenantId getTenantId() { 37 + protected TenantId getTenantId() {
38 return BasePluginService.SYSTEM_TENANT; 38 return BasePluginService.SYSTEM_TENANT;
39 } 39 }
40 40
@@ -19,6 +19,7 @@ import akka.actor.ActorContext; @@ -19,6 +19,7 @@ import akka.actor.ActorContext;
19 import org.thingsboard.server.actors.ActorSystemContext; 19 import org.thingsboard.server.actors.ActorSystemContext;
20 import org.thingsboard.server.actors.service.DefaultActorService; 20 import org.thingsboard.server.actors.service.DefaultActorService;
21 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
  22 +import org.thingsboard.server.common.data.page.PageDataIterable;
22 import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; 23 import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
23 import org.thingsboard.server.common.data.plugin.PluginMetaData; 24 import org.thingsboard.server.common.data.plugin.PluginMetaData;
24 25
@@ -39,12 +40,12 @@ public class TenantPluginManager extends PluginManager { @@ -39,12 +40,12 @@ public class TenantPluginManager extends PluginManager {
39 } 40 }
40 41
41 @Override 42 @Override
42 - FetchFunction<PluginMetaData> getFetchPluginsFunction() { 43 + protected FetchFunction<PluginMetaData> getFetchEntitiesFunction() {
43 return link -> pluginService.findTenantPlugins(tenantId, link); 44 return link -> pluginService.findTenantPlugins(tenantId, link);
44 } 45 }
45 46
46 @Override 47 @Override
47 - TenantId getTenantId() { 48 + protected TenantId getTenantId() {
48 return tenantId; 49 return tenantId;
49 } 50 }
50 51
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 -}  
  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,28 +13,35 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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 import org.thingsboard.server.actors.ActorSystemContext; 18 import org.thingsboard.server.actors.ActorSystemContext;
19 import org.thingsboard.server.actors.service.DefaultActorService; 19 import org.thingsboard.server.actors.service.DefaultActorService;
  20 +import org.thingsboard.server.actors.shared.plugin.PluginManager;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
21 import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; 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 @Override 33 @Override
32 - FetchFunction<RuleMetaData> getFetchRulesFunction() {  
33 - return ruleService::findSystemRules; 34 + protected FetchFunction<RuleChain> getFetchEntitiesFunction() {
  35 + return service::findSystemRuleChains;
34 } 36 }
35 37
36 @Override 38 @Override
37 - String getDispatcherName() { 39 + protected TenantId getTenantId() {
  40 + return BasePluginService.SYSTEM_TENANT;
  41 + }
  42 +
  43 + @Override
  44 + protected String getDispatcherName() {
38 return DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME; 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,19 +13,22 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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 import akka.actor.ActorContext; 18 import akka.actor.ActorContext;
19 import org.thingsboard.server.actors.ActorSystemContext; 19 import org.thingsboard.server.actors.ActorSystemContext;
20 import org.thingsboard.server.actors.service.DefaultActorService; 20 import org.thingsboard.server.actors.service.DefaultActorService;
21 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; 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 @Override 34 @Override
@@ -36,13 +39,17 @@ public class TenantRuleManager extends RuleManager { @@ -36,13 +39,17 @@ public class TenantRuleManager extends RuleManager {
36 } 39 }
37 40
38 @Override 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 @Override 46 @Override
44 - String getDispatcherName() { 47 + protected String getDispatcherName() {
45 return DefaultActorService.TENANT_RULE_DISPATCHER_NAME; 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,6 +24,7 @@ import org.thingsboard.server.actors.service.ContextAwareActor;
24 import org.thingsboard.server.actors.service.ContextBasedCreator; 24 import org.thingsboard.server.actors.service.ContextBasedCreator;
25 import org.thingsboard.server.common.data.DataConstants; 25 import org.thingsboard.server.common.data.DataConstants;
26 import org.thingsboard.server.common.data.Event; 26 import org.thingsboard.server.common.data.Event;
  27 +import org.thingsboard.server.common.msg.TbActorMsg;
27 import org.thingsboard.server.common.msg.cluster.ServerAddress; 28 import org.thingsboard.server.common.msg.cluster.ServerAddress;
28 29
29 public class StatsActor extends ContextAwareActor { 30 public class StatsActor extends ContextAwareActor {
@@ -36,6 +37,12 @@ public class StatsActor extends ContextAwareActor { @@ -36,6 +37,12 @@ public class StatsActor extends ContextAwareActor {
36 } 37 }
37 38
38 @Override 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 public void onReceive(Object msg) throws Exception { 46 public void onReceive(Object msg) throws Exception {
40 logger.debug("Received message: {}", msg); 47 logger.debug("Received message: {}", msg);
41 if (msg instanceof StatsPersistMsg) { 48 if (msg instanceof StatsPersistMsg) {
@@ -15,52 +15,38 @@ @@ -15,52 +15,38 @@
15 */ 15 */
16 package org.thingsboard.server.actors.tenant; 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 import org.thingsboard.server.actors.ActorSystemContext; 22 import org.thingsboard.server.actors.ActorSystemContext;
23 import org.thingsboard.server.actors.device.DeviceActor; 23 import org.thingsboard.server.actors.device.DeviceActor;
24 import org.thingsboard.server.actors.plugin.PluginTerminationMsg; 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 import org.thingsboard.server.actors.service.ContextBasedCreator; 26 import org.thingsboard.server.actors.service.ContextBasedCreator;
29 import org.thingsboard.server.actors.service.DefaultActorService; 27 import org.thingsboard.server.actors.service.DefaultActorService;
30 -import org.thingsboard.server.actors.shared.plugin.PluginManager;  
31 import org.thingsboard.server.actors.shared.plugin.TenantPluginManager; 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 import org.thingsboard.server.common.data.id.DeviceId; 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 import org.thingsboard.server.common.data.id.TenantId; 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 import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; 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 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 34 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
  35 +import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
46 import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg; 36 import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
47 import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg; 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 private final TenantId tenantId; 44 private final TenantId tenantId;
55 - private final RuleManager ruleManager;  
56 - private final PluginManager pluginManager;  
57 private final Map<DeviceId, ActorRef> deviceActors; 45 private final Map<DeviceId, ActorRef> deviceActors;
58 46
59 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { 47 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) {
60 - super(systemContext); 48 + super(systemContext, new TenantRuleChainManager(systemContext, tenantId), new TenantPluginManager(systemContext, tenantId));
61 this.tenantId = tenantId; 49 this.tenantId = tenantId;
62 - this.ruleManager = new TenantRuleManager(systemContext, tenantId);  
63 - this.pluginManager = new TenantPluginManager(systemContext, tenantId);  
64 this.deviceActors = new HashMap<>(); 50 this.deviceActors = new HashMap<>();
65 } 51 }
66 52
@@ -68,8 +54,7 @@ public class TenantActor extends ContextAwareActor { @@ -68,8 +54,7 @@ public class TenantActor extends ContextAwareActor {
68 public void preStart() { 54 public void preStart() {
69 logger.info("[{}] Starting tenant actor.", tenantId); 55 logger.info("[{}] Starting tenant actor.", tenantId);
70 try { 56 try {
71 - ruleManager.init(this.context());  
72 - pluginManager.init(this.context()); 57 + initRuleChains();
73 logger.info("[{}] Tenant actor started.", tenantId); 58 logger.info("[{}] Tenant actor started.", tenantId);
74 } catch (Exception e) { 59 } catch (Exception e) {
75 logger.error(e, "[{}] Unknown failure", tenantId); 60 logger.error(e, "[{}] Unknown failure", tenantId);
@@ -77,29 +62,45 @@ public class TenantActor extends ContextAwareActor { @@ -77,29 +62,45 @@ public class TenantActor extends ContextAwareActor {
77 } 62 }
78 63
79 @Override 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 private void broadcast(Object msg) { 104 private void broadcast(Object msg) {
104 pluginManager.broadcast(msg); 105 pluginManager.broadcast(msg);
105 deviceActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); 106 deviceActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
@@ -113,14 +114,9 @@ public class TenantActor extends ContextAwareActor { @@ -113,14 +114,9 @@ public class TenantActor extends ContextAwareActor {
113 getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); 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 private void onToPluginMsg(ToPluginActorMsg msg) { 117 private void onToPluginMsg(ToPluginActorMsg msg) {
122 if (msg.getPluginTenantId().equals(tenantId)) { 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 pluginActor.tell(msg, ActorRef.noSender()); 120 pluginActor.tell(msg, ActorRef.noSender());
125 } else { 121 } else {
126 context().parent().tell(msg, ActorRef.noSender()); 122 context().parent().tell(msg, ActorRef.noSender());
@@ -128,23 +124,11 @@ public class TenantActor extends ContextAwareActor { @@ -128,23 +124,11 @@ public class TenantActor extends ContextAwareActor {
128 } 124 }
129 125
130 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 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 target.tell(msg, ActorRef.noSender()); 129 target.tell(msg, ActorRef.noSender());
146 } else { 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,13 +136,6 @@ public class TenantActor extends ContextAwareActor {
152 pluginManager.remove(msg.getId()); 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 private ActorRef getOrCreateDeviceActor(DeviceId deviceId) { 140 private ActorRef getOrCreateDeviceActor(DeviceId deviceId) {
164 return deviceActors.computeIfAbsent(deviceId, k -> context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId)) 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,7 +71,7 @@ public class PluginController extends BaseController {
71 boolean created = source.getId() == null; 71 boolean created = source.getId() == null;
72 source.setTenantId(getCurrentUser().getTenantId()); 72 source.setTenantId(getCurrentUser().getTenantId());
73 PluginMetaData plugin = checkNotNull(pluginService.savePlugin(source)); 73 PluginMetaData plugin = checkNotNull(pluginService.savePlugin(source));
74 - actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), 74 + actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(),
75 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 75 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
76 76
77 logEntityAction(plugin.getId(), plugin, 77 logEntityAction(plugin.getId(), plugin,
@@ -97,7 +97,7 @@ public class PluginController extends BaseController { @@ -97,7 +97,7 @@ public class PluginController extends BaseController {
97 PluginId pluginId = new PluginId(toUUID(strPluginId)); 97 PluginId pluginId = new PluginId(toUUID(strPluginId));
98 PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); 98 PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId));
99 pluginService.activatePluginById(pluginId); 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 logEntityAction(plugin.getId(), plugin, 102 logEntityAction(plugin.getId(), plugin,
103 null, 103 null,
@@ -123,7 +123,7 @@ public class PluginController extends BaseController { @@ -123,7 +123,7 @@ public class PluginController extends BaseController {
123 PluginId pluginId = new PluginId(toUUID(strPluginId)); 123 PluginId pluginId = new PluginId(toUUID(strPluginId));
124 PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); 124 PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId));
125 pluginService.suspendPluginById(pluginId); 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 logEntityAction(plugin.getId(), plugin, 128 logEntityAction(plugin.getId(), plugin,
129 null, 129 null,
@@ -221,7 +221,7 @@ public class PluginController extends BaseController { @@ -221,7 +221,7 @@ public class PluginController extends BaseController {
221 PluginId pluginId = new PluginId(toUUID(strPluginId)); 221 PluginId pluginId = new PluginId(toUUID(strPluginId));
222 PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId)); 222 PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId));
223 pluginService.deletePluginById(pluginId); 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 logEntityAction(pluginId, plugin, 226 logEntityAction(pluginId, plugin,
227 null, 227 null,
@@ -78,6 +78,9 @@ public class RuleChainController extends BaseController { @@ -78,6 +78,9 @@ public class RuleChainController extends BaseController {
78 ruleChain.setTenantId(getCurrentUser().getTenantId()); 78 ruleChain.setTenantId(getCurrentUser().getTenantId());
79 RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); 79 RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain));
80 80
  81 + actorService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(),
  82 + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
  83 +
81 logEntityAction(savedRuleChain.getId(), savedRuleChain, 84 logEntityAction(savedRuleChain.getId(), savedRuleChain,
82 null, 85 null,
83 created ? ActionType.ADDED : ActionType.UPDATED, null); 86 created ? ActionType.ADDED : ActionType.UPDATED, null);
@@ -100,6 +103,8 @@ public class RuleChainController extends BaseController { @@ -100,6 +103,8 @@ public class RuleChainController extends BaseController {
100 RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId()); 103 RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId());
101 RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(ruleChainMetaData)); 104 RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(ruleChainMetaData));
102 105
  106 + actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
  107 +
103 logEntityAction(ruleChain.getId(), ruleChain, 108 logEntityAction(ruleChain.getId(), ruleChain,
104 null, 109 null,
105 ActionType.UPDATED, null, ruleChainMetaData); 110 ActionType.UPDATED, null, ruleChainMetaData);
@@ -183,6 +188,8 @@ public class RuleChainController extends BaseController { @@ -183,6 +188,8 @@ public class RuleChainController extends BaseController {
183 RuleChain ruleChain = checkRuleChain(ruleChainId); 188 RuleChain ruleChain = checkRuleChain(ruleChainId);
184 ruleChainService.deleteRuleChainById(ruleChainId); 189 ruleChainService.deleteRuleChainById(ruleChainId);
185 190
  191 + actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED);
  192 +
186 logEntityAction(ruleChainId, ruleChain, 193 logEntityAction(ruleChainId, ruleChain,
187 null, 194 null,
188 ActionType.DELETED, null, strRuleChainId); 195 ActionType.DELETED, null, strRuleChainId);
@@ -73,7 +73,7 @@ public class RuleController extends BaseController { @@ -73,7 +73,7 @@ public class RuleController extends BaseController {
73 boolean created = source.getId() == null; 73 boolean created = source.getId() == null;
74 source.setTenantId(getCurrentUser().getTenantId()); 74 source.setTenantId(getCurrentUser().getTenantId());
75 RuleMetaData rule = checkNotNull(ruleService.saveRule(source)); 75 RuleMetaData rule = checkNotNull(ruleService.saveRule(source));
76 - actorService.onRuleStateChange(rule.getTenantId(), rule.getId(), 76 + actorService.onEntityStateChange(rule.getTenantId(), rule.getId(),
77 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 77 created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
78 78
79 logEntityAction(rule.getId(), rule, 79 logEntityAction(rule.getId(), rule,
@@ -99,7 +99,7 @@ public class RuleController extends BaseController { @@ -99,7 +99,7 @@ public class RuleController extends BaseController {
99 RuleId ruleId = new RuleId(toUUID(strRuleId)); 99 RuleId ruleId = new RuleId(toUUID(strRuleId));
100 RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); 100 RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId));
101 ruleService.activateRuleById(ruleId); 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 logEntityAction(rule.getId(), rule, 104 logEntityAction(rule.getId(), rule,
105 null, 105 null,
@@ -125,7 +125,7 @@ public class RuleController extends BaseController { @@ -125,7 +125,7 @@ public class RuleController extends BaseController {
125 RuleId ruleId = new RuleId(toUUID(strRuleId)); 125 RuleId ruleId = new RuleId(toUUID(strRuleId));
126 RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); 126 RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId));
127 ruleService.suspendRuleById(ruleId); 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 logEntityAction(rule.getId(), rule, 130 logEntityAction(rule.getId(), rule,
131 null, 131 null,
@@ -219,7 +219,7 @@ public class RuleController extends BaseController { @@ -219,7 +219,7 @@ public class RuleController extends BaseController {
219 RuleId ruleId = new RuleId(toUUID(strRuleId)); 219 RuleId ruleId = new RuleId(toUUID(strRuleId));
220 RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId)); 220 RuleMetaData rule = checkRule(ruleService.findRuleById(ruleId));
221 ruleService.deleteRuleById(ruleId); 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 logEntityAction(ruleId, rule, 224 logEntityAction(ruleId, rule,
225 null, 225 null,
@@ -26,6 +26,10 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen @@ -26,6 +26,10 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen
26 import org.springframework.core.env.Environment; 26 import org.springframework.core.env.Environment;
27 import org.springframework.core.type.filter.AnnotationTypeFilter; 27 import org.springframework.core.type.filter.AnnotationTypeFilter;
28 import org.springframework.stereotype.Service; 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 import org.thingsboard.server.common.data.plugin.ComponentDescriptor; 33 import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
30 import org.thingsboard.server.common.data.plugin.ComponentType; 34 import org.thingsboard.server.common.data.plugin.ComponentType;
31 import org.thingsboard.server.dao.component.ComponentDescriptorService; 35 import org.thingsboard.server.dao.component.ComponentDescriptorService;
@@ -79,8 +83,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @@ -79,8 +83,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
79 private List<ComponentDescriptor> persist(Set<BeanDefinition> filterDefs, ComponentType type) { 83 private List<ComponentDescriptor> persist(Set<BeanDefinition> filterDefs, ComponentType type) {
80 List<ComponentDescriptor> result = new ArrayList<>(); 84 List<ComponentDescriptor> result = new ArrayList<>();
81 for (BeanDefinition def : filterDefs) { 85 for (BeanDefinition def : filterDefs) {
82 - ComponentDescriptor scannedComponent = scanAndPersistComponent(def, type);  
83 - result.add(scannedComponent); 86 + result.add(scanAndPersistComponent(def, type));
84 } 87 }
85 return result; 88 return result;
86 } 89 }
@@ -93,24 +96,36 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @@ -93,24 +96,36 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
93 Class<?> clazz = Class.forName(clazzName); 96 Class<?> clazz = Class.forName(clazzName);
94 String descriptorResourceName; 97 String descriptorResourceName;
95 switch (type) { 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 case FILTER: 105 case FILTER:
97 - Filter filterAnnotation = clazz.getAnnotation(Filter.class); 106 + FilterNode filterAnnotation = clazz.getAnnotation(FilterNode.class);
98 scannedComponent.setName(filterAnnotation.name()); 107 scannedComponent.setName(filterAnnotation.name());
99 scannedComponent.setScope(filterAnnotation.scope()); 108 scannedComponent.setScope(filterAnnotation.scope());
100 descriptorResourceName = filterAnnotation.descriptor(); 109 descriptorResourceName = filterAnnotation.descriptor();
101 break; 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 break; 116 break;
108 case ACTION: 117 case ACTION:
109 - Action actionAnnotation = clazz.getAnnotation(Action.class); 118 + ActionNode actionAnnotation = clazz.getAnnotation(ActionNode.class);
110 scannedComponent.setName(actionAnnotation.name()); 119 scannedComponent.setName(actionAnnotation.name());
111 scannedComponent.setScope(actionAnnotation.scope()); 120 scannedComponent.setScope(actionAnnotation.scope());
112 descriptorResourceName = actionAnnotation.descriptor(); 121 descriptorResourceName = actionAnnotation.descriptor();
113 break; 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 case PLUGIN: 129 case PLUGIN:
115 Plugin pluginAnnotation = clazz.getAnnotation(Plugin.class); 130 Plugin pluginAnnotation = clazz.getAnnotation(Plugin.class);
116 scannedComponent.setName(pluginAnnotation.name()); 131 scannedComponent.setName(pluginAnnotation.name());
@@ -122,12 +137,12 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @@ -122,12 +137,12 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
122 log.error("Can't initialize plugin {}, due to missing action {}!", def.getBeanClassName(), actionClazz.getName()); 137 log.error("Can't initialize plugin {}, due to missing action {}!", def.getBeanClassName(), actionClazz.getName());
123 return new ClassNotFoundException("Action: " + actionClazz.getName() + "is missing!"); 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 log.error("Plugin {} action {} has wrong component type!", def.getBeanClassName(), actionClazz.getName(), actionComponent.getType()); 141 log.error("Plugin {} action {} has wrong component type!", def.getBeanClassName(), actionClazz.getName(), actionComponent.getType());
127 throw new RuntimeException("Plugin " + def.getBeanClassName() + "action " + actionClazz.getName() + " has wrong component type!"); 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 break; 146 break;
132 default: 147 default:
133 throw new RuntimeException(type + " is not supported yet!"); 148 throw new RuntimeException(type + " is not supported yet!");
@@ -168,11 +183,15 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @@ -168,11 +183,15 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
168 183
169 @Override 184 @Override
170 public void discoverComponents() { 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 registerComponents(ComponentType.PLUGIN, Plugin.class); 196 registerComponents(ComponentType.PLUGIN, Plugin.class);
178 197
@@ -199,7 +218,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @@ -199,7 +218,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe
199 } 218 }
200 List<ComponentDescriptor> result = new ArrayList<>(); 219 List<ComponentDescriptor> result = new ArrayList<>();
201 for (String action : plugin.getActions().split(",")) { 220 for (String action : plugin.getActions().split(",")) {
202 - getComponent(action).ifPresent(v -> result.add(v)); 221 + getComponent(action).ifPresent(result::add);
203 } 222 }
204 return result; 223 return result;
205 } else { 224 } else {
@@ -62,7 +62,7 @@ cluster: @@ -62,7 +62,7 @@ cluster:
62 # Plugins configuration parameters 62 # Plugins configuration parameters
63 plugins: 63 plugins:
64 # Comma seperated package list used during classpath scanning for plugins 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 # JWT Token parameters 67 # JWT Token parameters
68 security.jwt: 68 security.jwt:
@@ -215,6 +215,12 @@ actors: @@ -215,6 +215,12 @@ actors:
215 termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}" 215 termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}"
216 # Errors for particular actor are persisted once per specified amount of milliseconds 216 # Errors for particular actor are persisted once per specified amount of milliseconds
217 error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}" 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 statistics: 224 statistics:
219 # Enable/disable actor statistics 225 # Enable/disable actor statistics
220 enabled: "${ACTORS_STATISTICS_ENABLED:true}" 226 enabled: "${ACTORS_STATISTICS_ENABLED:true}"
@@ -96,6 +96,8 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC @@ -96,6 +96,8 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
96 @Slf4j 96 @Slf4j
97 public abstract class AbstractControllerTest { 97 public abstract class AbstractControllerTest {
98 98
  99 + protected ObjectMapper mapper = new ObjectMapper();
  100 +
99 protected static final String TEST_TENANT_NAME = "TEST TENANT"; 101 protected static final String TEST_TENANT_NAME = "TEST TENANT";
100 102
101 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org"; 103 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
  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,11 +13,14 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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 import org.thingsboard.server.dao.service.DaoSqlTest; 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 @DaoSqlTest 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,29 +13,14 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId;
23 23
24 import com.fasterxml.jackson.databind.JsonNode; 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 private static final long serialVersionUID = -1599722990298929275L; 28 private static final long serialVersionUID = -1599722990298929275L;
29 29
@@ -37,7 +37,12 @@ public class DataConstants { @@ -37,7 +37,12 @@ public class DataConstants {
37 public static final String ERROR = "ERROR"; 37 public static final String ERROR = "ERROR";
38 public static final String LC_EVENT = "LC_EVENT"; 38 public static final String LC_EVENT = "LC_EVENT";
39 public static final String STATS = "STATS"; 39 public static final String STATS = "STATS";
  40 + public static final String DEBUG = "DEBUG";
40 41
41 public static final String ONEWAY = "ONEWAY"; 42 public static final String ONEWAY = "ONEWAY";
42 public static final String TWOWAY = "TWOWAY"; 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,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId;
23 import com.fasterxml.jackson.databind.JsonNode; 23 import com.fasterxml.jackson.databind.JsonNode;
24 24
25 @EqualsAndHashCode(callSuper = true) 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 private static final long serialVersionUID = 2807343040519543363L; 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,8 +13,11 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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,12 +13,11 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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,7 +25,7 @@ import org.thingsboard.server.common.data.security.Authority;
25 import com.fasterxml.jackson.databind.JsonNode; 25 import com.fasterxml.jackson.databind.JsonNode;
26 26
27 @EqualsAndHashCode(callSuper = true) 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 private static final long serialVersionUID = 8250339805336035966L; 30 private static final long serialVersionUID = 8250339805336035966L;
31 31
@@ -22,6 +22,7 @@ import lombok.Builder; @@ -22,6 +22,7 @@ import lombok.Builder;
22 import lombok.Data; 22 import lombok.Data;
23 import org.thingsboard.server.common.data.BaseData; 23 import org.thingsboard.server.common.data.BaseData;
24 import org.thingsboard.server.common.data.HasName; 24 import org.thingsboard.server.common.data.HasName;
  25 +import org.thingsboard.server.common.data.HasTenantId;
25 import org.thingsboard.server.common.data.id.EntityId; 26 import org.thingsboard.server.common.data.id.EntityId;
26 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
27 28
@@ -31,7 +32,7 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -31,7 +32,7 @@ import org.thingsboard.server.common.data.id.TenantId;
31 @Data 32 @Data
32 @Builder 33 @Builder
33 @AllArgsConstructor 34 @AllArgsConstructor
34 -public class Alarm extends BaseData<AlarmId> implements HasName { 35 +public class Alarm extends BaseData<AlarmId> implements HasName, HasTenantId {
35 36
36 private TenantId tenantId; 37 private TenantId tenantId;
37 private String type; 38 private String type;
@@ -17,16 +17,13 @@ package org.thingsboard.server.common.data.asset; @@ -17,16 +17,13 @@ package org.thingsboard.server.common.data.asset;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 import lombok.EqualsAndHashCode; 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 import org.thingsboard.server.common.data.id.AssetId; 21 import org.thingsboard.server.common.data.id.AssetId;
25 import org.thingsboard.server.common.data.id.CustomerId; 22 import org.thingsboard.server.common.data.id.CustomerId;
26 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
27 24
28 @EqualsAndHashCode(callSuper = true) 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 private static final long serialVersionUID = 2807343040519543363L; 28 private static final long serialVersionUID = 2807343040519543363L;
32 29
@@ -20,6 +20,7 @@ import java.util.List; @@ -20,6 +20,7 @@ import java.util.List;
20 import java.util.NoSuchElementException; 20 import java.util.NoSuchElementException;
21 21
22 import org.thingsboard.server.common.data.SearchTextBased; 22 import org.thingsboard.server.common.data.SearchTextBased;
  23 +import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.UUIDBased; 24 import org.thingsboard.server.common.data.id.UUIDBased;
24 25
25 public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> implements Iterable<T>, Iterator<T> { 26 public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> implements Iterable<T>, Iterator<T> {
@@ -20,6 +20,6 @@ package org.thingsboard.server.common.data.plugin; @@ -20,6 +20,6 @@ package org.thingsboard.server.common.data.plugin;
20 */ 20 */
21 public enum ComponentType { 21 public enum ComponentType {
22 22
23 - FILTER, PROCESSOR, ACTION, PLUGIN 23 + ENRICHMENT, FILTER, TRANSFORMATION, ACTION, OLD_ACTION, PLUGIN
24 24
25 } 25 }
@@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
21 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
22 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
23 import org.thingsboard.server.common.data.HasName; 23 import org.thingsboard.server.common.data.HasName;
  24 +import org.thingsboard.server.common.data.HasTenantId;
24 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; 25 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
25 import org.thingsboard.server.common.data.id.PluginId; 26 import org.thingsboard.server.common.data.id.PluginId;
26 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
@@ -32,7 +33,7 @@ import java.io.IOException; @@ -32,7 +33,7 @@ import java.io.IOException;
32 33
33 @EqualsAndHashCode(callSuper = true) 34 @EqualsAndHashCode(callSuper = true)
34 @Slf4j 35 @Slf4j
35 -public class PluginMetaData extends SearchTextBasedWithAdditionalInfo<PluginId> implements HasName { 36 +public class PluginMetaData extends SearchTextBasedWithAdditionalInfo<PluginId> implements HasName, HasTenantId {
36 37
37 private static final long serialVersionUID = 1L; 38 private static final long serialVersionUID = 1L;
38 39
  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,6 +21,7 @@ import lombok.Data;
21 import lombok.EqualsAndHashCode; 21 import lombok.EqualsAndHashCode;
22 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
23 import org.thingsboard.server.common.data.HasName; 23 import org.thingsboard.server.common.data.HasName;
  24 +import org.thingsboard.server.common.data.HasTenantId;
24 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; 25 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
25 import org.thingsboard.server.common.data.id.RuleChainId; 26 import org.thingsboard.server.common.data.id.RuleChainId;
26 import org.thingsboard.server.common.data.id.RuleNodeId; 27 import org.thingsboard.server.common.data.id.RuleNodeId;
@@ -29,7 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId; @@ -29,7 +30,7 @@ import org.thingsboard.server.common.data.id.TenantId;
29 @Data 30 @Data
30 @EqualsAndHashCode(callSuper = true) 31 @EqualsAndHashCode(callSuper = true)
31 @Slf4j 32 @Slf4j
32 -public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> implements HasName { 33 +public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> implements HasName, HasTenantId {
33 34
34 private static final long serialVersionUID = -5656679015121935465L; 35 private static final long serialVersionUID = -5656679015121935465L;
35 36
@@ -37,6 +38,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im @@ -37,6 +38,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im
37 private String name; 38 private String name;
38 private RuleNodeId firstRuleNodeId; 39 private RuleNodeId firstRuleNodeId;
39 private boolean root; 40 private boolean root;
  41 + private boolean debugMode;
40 private transient JsonNode configuration; 42 private transient JsonNode configuration;
41 @JsonIgnore 43 @JsonIgnore
42 private byte[] configurationBytes; 44 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.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,20 +59,4 @@ public class RuleChainMetaData {
59 } 59 }
60 ruleChainConnections.add(connectionInfo); 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,6 +23,7 @@ import lombok.Data;
23 import lombok.EqualsAndHashCode; 23 import lombok.EqualsAndHashCode;
24 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
25 import org.thingsboard.server.common.data.HasName; 25 import org.thingsboard.server.common.data.HasName;
  26 +import org.thingsboard.server.common.data.HasTenantId;
26 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; 27 import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
27 import org.thingsboard.server.common.data.id.RuleId; 28 import org.thingsboard.server.common.data.id.RuleId;
28 import org.thingsboard.server.common.data.id.TenantId; 29 import org.thingsboard.server.common.data.id.TenantId;
@@ -31,7 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; @@ -31,7 +32,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
31 @Data 32 @Data
32 @EqualsAndHashCode(callSuper = true) 33 @EqualsAndHashCode(callSuper = true)
33 @Slf4j 34 @Slf4j
34 -public class RuleMetaData extends SearchTextBasedWithAdditionalInfo<RuleId> implements HasName { 35 +public class RuleMetaData extends SearchTextBasedWithAdditionalInfo<RuleId> implements HasName, HasTenantId {
35 36
36 private static final long serialVersionUID = -5656679015122935465L; 37 private static final long serialVersionUID = -5656679015122935465L;
37 38
@@ -34,6 +34,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl @@ -34,6 +34,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
34 34
35 private String type; 35 private String type;
36 private String name; 36 private String name;
  37 + private boolean debugMode;
37 private transient JsonNode configuration; 38 private transient JsonNode configuration;
38 @JsonIgnore 39 @JsonIgnore
39 private byte[] configurationBytes; 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,18 +13,13 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 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,6 +17,7 @@ package org.thingsboard.server.common.msg;
17 17
18 import com.google.protobuf.ByteString; 18 import com.google.protobuf.ByteString;
19 import com.google.protobuf.InvalidProtocolBufferException; 19 import com.google.protobuf.InvalidProtocolBufferException;
  20 +import lombok.AllArgsConstructor;
20 import lombok.Data; 21 import lombok.Data;
21 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
22 import org.thingsboard.server.common.data.id.EntityIdFactory; 23 import org.thingsboard.server.common.data.id.EntityIdFactory;
@@ -30,15 +31,25 @@ import java.util.UUID; @@ -30,15 +31,25 @@ import java.util.UUID;
30 * Created by ashvayka on 13.01.18. 31 * Created by ashvayka on 13.01.18.
31 */ 32 */
32 @Data 33 @Data
  34 +@AllArgsConstructor
33 public final class TbMsg implements Serializable { 35 public final class TbMsg implements Serializable {
34 36
35 private final UUID id; 37 private final UUID id;
36 private final String type; 38 private final String type;
37 private final EntityId originator; 39 private final EntityId originator;
38 private final TbMsgMetaData metaData; 40 private final TbMsgMetaData metaData;
39 - 41 + private final TbMsgDataType dataType;
40 private final byte[] data; 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 public static ByteBuffer toBytes(TbMsg msg) { 53 public static ByteBuffer toBytes(TbMsg msg) {
43 MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder(); 54 MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder();
44 builder.setId(msg.getId().toString()); 55 builder.setId(msg.getId().toString());
@@ -49,11 +60,10 @@ public final class TbMsg implements Serializable { @@ -49,11 +60,10 @@ public final class TbMsg implements Serializable {
49 } 60 }
50 61
51 if (msg.getMetaData() != null) { 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 builder.setData(ByteString.copyFrom(msg.getData())); 67 builder.setData(ByteString.copyFrom(msg.getData()));
58 byte[] bytes = builder.build().toByteArray(); 68 byte[] bytes = builder.build().toByteArray();
59 return ByteBuffer.wrap(bytes); 69 return ByteBuffer.wrap(bytes);
@@ -62,19 +72,19 @@ public final class TbMsg implements Serializable { @@ -62,19 +72,19 @@ public final class TbMsg implements Serializable {
62 public static TbMsg fromBytes(ByteBuffer buffer) { 72 public static TbMsg fromBytes(ByteBuffer buffer) {
63 try { 73 try {
64 MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array()); 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 } catch (InvalidProtocolBufferException e) { 79 } catch (InvalidProtocolBufferException e) {
77 throw new IllegalStateException("Could not parse protobuf for TbMsg", e); 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,24 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.common.msg; 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,9 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.common.msg; 16 package org.thingsboard.server.common.msg;
17 17
  18 +import lombok.AllArgsConstructor;
18 import lombok.Data; 19 import lombok.Data;
  20 +import lombok.NoArgsConstructor;
19 21
20 import java.io.Serializable; 22 import java.io.Serializable;
  23 +import java.util.HashMap;
21 import java.util.Map; 24 import java.util.Map;
22 import java.util.concurrent.ConcurrentHashMap; 25 import java.util.concurrent.ConcurrentHashMap;
23 26
@@ -25,10 +28,15 @@ import java.util.concurrent.ConcurrentHashMap; @@ -25,10 +28,15 @@ import java.util.concurrent.ConcurrentHashMap;
25 * Created by ashvayka on 13.01.18. 28 * Created by ashvayka on 13.01.18.
26 */ 29 */
27 @Data 30 @Data
  31 +@NoArgsConstructor
28 public final class TbMsgMetaData implements Serializable { 32 public final class TbMsgMetaData implements Serializable {
29 33
30 private Map<String, String> data = new ConcurrentHashMap<>(); 34 private Map<String, String> data = new ConcurrentHashMap<>();
31 35
  36 + TbMsgMetaData(Map<String, String> data) {
  37 + this.data = data;
  38 + }
  39 +
32 public String getValue(String key) { 40 public String getValue(String key) {
33 return data.get(key); 41 return data.get(key);
34 } 42 }
@@ -37,4 +45,7 @@ public final class TbMsgMetaData implements Serializable { @@ -37,4 +45,7 @@ public final class TbMsgMetaData implements Serializable {
37 data.put(key, value); 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,14 +15,14 @@
15 */ 15 */
16 package org.thingsboard.server.common.msg.plugin; 16 package org.thingsboard.server.common.msg.plugin;
17 17
18 -import lombok.Data;  
19 import lombok.Getter; 18 import lombok.Getter;
20 import lombok.ToString; 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 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 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 import org.thingsboard.server.common.msg.aware.TenantAwareMsg; 26 import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
27 import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg; 27 import org.thingsboard.server.common.msg.cluster.ToAllNodesMsg;
28 28
@@ -32,34 +32,34 @@ import java.util.Optional; @@ -32,34 +32,34 @@ import java.util.Optional;
32 * @author Andrew Shvayka 32 * @author Andrew Shvayka
33 */ 33 */
34 @ToString 34 @ToString
35 -public class ComponentLifecycleMsg implements TenantAwareMsg, ToAllNodesMsg { 35 +public class ComponentLifecycleMsg implements TbActorMsg, TenantAwareMsg, ToAllNodesMsg {
36 @Getter 36 @Getter
37 private final TenantId tenantId; 37 private final TenantId tenantId;
38 - private final PluginId pluginId;  
39 - private final RuleId ruleId; 38 + @Getter
  39 + private final EntityId entityId;
40 @Getter 40 @Getter
41 private final ComponentLifecycleEvent event; 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 this.tenantId = tenantId; 44 this.tenantId = tenantId;
53 - this.pluginId = pluginId;  
54 - this.ruleId = ruleId; 45 + this.entityId = entityId;
55 this.event = event; 46 this.event = event;
56 } 47 }
57 48
58 public Optional<PluginId> getPluginId() { 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 public Optional<RuleId> getRuleId() { 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 }
  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,6 +19,9 @@ package msgqueue;
19 option java_package = "org.thingsboard.server.common.msg.gen"; 19 option java_package = "org.thingsboard.server.common.msg.gen";
20 option java_outer_classname = "MsgProtos"; 20 option java_outer_classname = "MsgProtos";
21 21
  22 +message TbMsgMetaDataProto {
  23 + map<string, string> data = 1;
  24 +}
22 25
23 message TbMsgProto { 26 message TbMsgProto {
24 string id = 1; 27 string id = 1;
@@ -26,11 +29,8 @@ message TbMsgProto { @@ -26,11 +29,8 @@ message TbMsgProto {
26 string entityType = 3; 29 string entityType = 3;
27 string entityId = 4; 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 }
@@ -332,6 +332,8 @@ public class ModelConstants { @@ -332,6 +332,8 @@ public class ModelConstants {
332 public static final String EVENT_BY_TYPE_AND_ID_VIEW_NAME = "event_by_type_and_id"; 332 public static final String EVENT_BY_TYPE_AND_ID_VIEW_NAME = "event_by_type_and_id";
333 public static final String EVENT_BY_ID_VIEW_NAME = "event_by_id"; 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 * Cassandra rule chain constants. 338 * Cassandra rule chain constants.
337 */ 339 */
@@ -22,6 +22,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey; @@ -22,6 +22,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey;
22 import com.datastax.driver.mapping.annotations.Table; 22 import com.datastax.driver.mapping.annotations.Table;
23 import com.fasterxml.jackson.databind.JsonNode; 23 import com.fasterxml.jackson.databind.JsonNode;
24 import lombok.EqualsAndHashCode; 24 import lombok.EqualsAndHashCode;
  25 +import lombok.Getter;
  26 +import lombok.Setter;
25 import lombok.ToString; 27 import lombok.ToString;
26 import org.thingsboard.server.common.data.id.RuleChainId; 28 import org.thingsboard.server.common.data.id.RuleChainId;
27 import org.thingsboard.server.common.data.id.RuleNodeId; 29 import org.thingsboard.server.common.data.id.RuleNodeId;
@@ -54,6 +56,10 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> { @@ -54,6 +56,10 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> {
54 private UUID firstRuleNodeId; 56 private UUID firstRuleNodeId;
55 @Column(name = RULE_CHAIN_ROOT_PROPERTY) 57 @Column(name = RULE_CHAIN_ROOT_PROPERTY)
56 private boolean root; 58 private boolean root;
  59 + @Getter
  60 + @Setter
  61 + @Column(name = DEBUG_MODE)
  62 + private boolean debugMode;
57 @Column(name = RULE_CHAIN_CONFIGURATION_PROPERTY, codec = JsonCodec.class) 63 @Column(name = RULE_CHAIN_CONFIGURATION_PROPERTY, codec = JsonCodec.class)
58 private JsonNode configuration; 64 private JsonNode configuration;
59 @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) 65 @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class)
@@ -71,6 +77,7 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> { @@ -71,6 +77,7 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> {
71 this.searchText = ruleChain.getName(); 77 this.searchText = ruleChain.getName();
72 this.firstRuleNodeId = DaoUtil.getId(ruleChain.getFirstRuleNodeId()); 78 this.firstRuleNodeId = DaoUtil.getId(ruleChain.getFirstRuleNodeId());
73 this.root = ruleChain.isRoot(); 79 this.root = ruleChain.isRoot();
  80 + this.debugMode = ruleChain.isDebugMode();
74 this.configuration = ruleChain.getConfiguration(); 81 this.configuration = ruleChain.getConfiguration();
75 this.additionalInfo = ruleChain.getAdditionalInfo(); 82 this.additionalInfo = ruleChain.getAdditionalInfo();
76 } 83 }
@@ -157,6 +164,7 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> { @@ -157,6 +164,7 @@ public class RuleChainEntity implements SearchTextEntity<RuleChain> {
157 ruleChain.setFirstRuleNodeId(new RuleNodeId(this.firstRuleNodeId)); 164 ruleChain.setFirstRuleNodeId(new RuleNodeId(this.firstRuleNodeId));
158 } 165 }
159 ruleChain.setRoot(this.root); 166 ruleChain.setRoot(this.root);
  167 + ruleChain.setDebugMode(this.debugMode);
160 ruleChain.setConfiguration(this.configuration); 168 ruleChain.setConfiguration(this.configuration);
161 ruleChain.setAdditionalInfo(this.additionalInfo); 169 ruleChain.setAdditionalInfo(this.additionalInfo);
162 return ruleChain; 170 return ruleChain;
@@ -21,6 +21,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey; @@ -21,6 +21,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey;
21 import com.datastax.driver.mapping.annotations.Table; 21 import com.datastax.driver.mapping.annotations.Table;
22 import com.fasterxml.jackson.databind.JsonNode; 22 import com.fasterxml.jackson.databind.JsonNode;
23 import lombok.EqualsAndHashCode; 23 import lombok.EqualsAndHashCode;
  24 +import lombok.Getter;
  25 +import lombok.Setter;
24 import lombok.ToString; 26 import lombok.ToString;
25 import org.thingsboard.server.common.data.id.RuleNodeId; 27 import org.thingsboard.server.common.data.id.RuleNodeId;
26 import org.thingsboard.server.common.data.rule.RuleNode; 28 import org.thingsboard.server.common.data.rule.RuleNode;
@@ -49,6 +51,11 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> { @@ -49,6 +51,11 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> {
49 private JsonNode configuration; 51 private JsonNode configuration;
50 @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) 52 @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class)
51 private JsonNode additionalInfo; 53 private JsonNode additionalInfo;
  54 + @Getter
  55 + @Setter
  56 + @Column(name = DEBUG_MODE)
  57 + private boolean debugMode;
  58 +
52 59
53 public RuleNodeEntity() { 60 public RuleNodeEntity() {
54 } 61 }
@@ -59,6 +66,7 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> { @@ -59,6 +66,7 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> {
59 } 66 }
60 this.type = ruleNode.getType(); 67 this.type = ruleNode.getType();
61 this.name = ruleNode.getName(); 68 this.name = ruleNode.getName();
  69 + this.debugMode = ruleNode.isDebugMode();
62 this.searchText = ruleNode.getName(); 70 this.searchText = ruleNode.getName();
63 this.configuration = ruleNode.getConfiguration(); 71 this.configuration = ruleNode.getConfiguration();
64 this.additionalInfo = ruleNode.getAdditionalInfo(); 72 this.additionalInfo = ruleNode.getAdditionalInfo();
@@ -126,6 +134,7 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> { @@ -126,6 +134,7 @@ public class RuleNodeEntity implements SearchTextEntity<RuleNode> {
126 ruleNode.setCreatedTime(UUIDs.unixTimestamp(id)); 134 ruleNode.setCreatedTime(UUIDs.unixTimestamp(id));
127 ruleNode.setType(this.type); 135 ruleNode.setType(this.type);
128 ruleNode.setName(this.name); 136 ruleNode.setName(this.name);
  137 + ruleNode.setDebugMode(this.debugMode);
129 ruleNode.setConfiguration(this.configuration); 138 ruleNode.setConfiguration(this.configuration);
130 ruleNode.setAdditionalInfo(this.additionalInfo); 139 ruleNode.setAdditionalInfo(this.additionalInfo);
131 return ruleNode; 140 return ruleNode;
@@ -58,6 +58,9 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT @@ -58,6 +58,9 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT
58 @Column(name = ModelConstants.RULE_CHAIN_ROOT_PROPERTY) 58 @Column(name = ModelConstants.RULE_CHAIN_ROOT_PROPERTY)
59 private boolean root; 59 private boolean root;
60 60
  61 + @Column(name = ModelConstants.DEBUG_MODE)
  62 + private boolean debugMode;
  63 +
61 @Type(type = "json") 64 @Type(type = "json")
62 @Column(name = ModelConstants.RULE_CHAIN_CONFIGURATION_PROPERTY) 65 @Column(name = ModelConstants.RULE_CHAIN_CONFIGURATION_PROPERTY)
63 private JsonNode configuration; 66 private JsonNode configuration;
@@ -80,6 +83,7 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT @@ -80,6 +83,7 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT
80 this.firstRuleNodeId = UUIDConverter.fromTimeUUID(ruleChain.getFirstRuleNodeId().getId()); 83 this.firstRuleNodeId = UUIDConverter.fromTimeUUID(ruleChain.getFirstRuleNodeId().getId());
81 } 84 }
82 this.root = ruleChain.isRoot(); 85 this.root = ruleChain.isRoot();
  86 + this.debugMode = ruleChain.isDebugMode();
83 this.configuration = ruleChain.getConfiguration(); 87 this.configuration = ruleChain.getConfiguration();
84 this.additionalInfo = ruleChain.getAdditionalInfo(); 88 this.additionalInfo = ruleChain.getAdditionalInfo();
85 } 89 }
@@ -104,6 +108,7 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT @@ -104,6 +108,7 @@ public class RuleChainEntity extends BaseSqlEntity<RuleChain> implements SearchT
104 ruleChain.setFirstRuleNodeId(new RuleNodeId(UUIDConverter.fromString(firstRuleNodeId))); 108 ruleChain.setFirstRuleNodeId(new RuleNodeId(UUIDConverter.fromString(firstRuleNodeId)));
105 } 109 }
106 ruleChain.setRoot(root); 110 ruleChain.setRoot(root);
  111 + ruleChain.setDebugMode(debugMode);
107 ruleChain.setConfiguration(configuration); 112 ruleChain.setConfiguration(configuration);
108 ruleChain.setAdditionalInfo(additionalInfo); 113 ruleChain.setAdditionalInfo(additionalInfo);
109 return ruleChain; 114 return ruleChain;