diff --git a/application/pom.xml b/application/pom.xml
index 8449246059..6da40a9143 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -53,6 +53,14 @@
org.thingsboard
extensions-api
+
+ org.thingsboard.rule-engine
+ rule-engine-api
+
+
+ org.thingsboard.rule-engine
+ rule-engine-components
+
org.thingsboard
extensions-core
diff --git a/application/src/main/data/upgrade/1.5.0/schema_update.cql b/application/src/main/data/upgrade/1.5.0/schema_update.cql
index aa8b10bdfd..5cdaede0ff 100644
--- a/application/src/main/data/upgrade/1.5.0/schema_update.cql
+++ b/application/src/main/data/upgrade/1.5.0/schema_update.cql
@@ -69,6 +69,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_chain (
search_text text,
first_rule_node_id uuid,
root boolean,
+ debug_mode boolean,
configuration text,
additional_info text,
PRIMARY KEY (id, tenant_id)
@@ -85,9 +86,12 @@ CREATE TABLE IF NOT EXISTS thingsboard.rule_node (
id uuid,
type text,
name text,
+ debug_mode boolean,
search_text text,
configuration text,
additional_info text,
PRIMARY KEY (id)
);
+ALTER TABLE thingsboard.device ADD last_connect bigint;
+ALTER TABLE thingsboard.device ADD last_update bigint;
\ No newline at end of file
diff --git a/application/src/main/data/upgrade/1.5.0/schema_update.sql b/application/src/main/data/upgrade/1.5.0/schema_update.sql
index 0043ed5bb0..ab91166fac 100644
--- a/application/src/main/data/upgrade/1.5.0/schema_update.sql
+++ b/application/src/main/data/upgrade/1.5.0/schema_update.sql
@@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS rule_chain (
name varchar(255),
first_rule_node_id varchar(31),
root boolean,
+ debug_mode boolean,
search_text varchar(255),
tenant_id varchar(31)
);
@@ -31,5 +32,9 @@ CREATE TABLE IF NOT EXISTS rule_node (
configuration varchar(10000000),
type varchar(255),
name varchar(255),
+ debug_mode boolean,
search_text varchar(255)
-);
\ No newline at end of file
+);
+
+ALTER TABLE device ADD COLUMN IF NOT EXISTS last_connect BIGINT;
+ALTER TABLE device ADD COLUMN IF NOT EXISTS last_update BIGINT;
\ No newline at end of file
diff --git a/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java b/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java
index c3444d43f7..751bde6303 100644
--- a/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java
+++ b/application/src/main/java/org/thingsboard/server/ThingsboardServerApplication.java
@@ -19,6 +19,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Arrays;
@@ -26,6 +27,7 @@ import java.util.Arrays;
@SpringBootConfiguration
@EnableAsync
@EnableSwagger2
+@EnableScheduling
@ComponentScan({"org.thingsboard.server"})
public class ThingsboardServerApplication {
diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
index 77953c9dc1..50d2530b53 100644
--- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
@@ -25,15 +25,19 @@ import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import lombok.Getter;
import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
+import org.thingsboard.rule.engine.api.ListeningExecutor;
+import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
+import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.common.transport.auth.DeviceAuthService;
import org.thingsboard.server.controller.plugin.PluginWebSocketMsgEndpoint;
@@ -46,116 +50,200 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.plugin.PluginService;
import org.thingsboard.server.dao.relation.RelationService;
+import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.rule.RuleService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
+import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
+import org.thingsboard.server.service.executors.DbCallbackExecutorService;
+import org.thingsboard.server.service.mail.MailExecutorService;
+import org.thingsboard.server.service.script.JsExecutorService;
+import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
+import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Optional;
+@Slf4j
@Component
public class ActorSystemContext {
private static final String AKKA_CONF_FILE_NAME = "actor-system.conf";
protected final ObjectMapper mapper = new ObjectMapper();
- @Getter @Setter private ActorService actorService;
+ @Getter
+ @Setter
+ private ActorService actorService;
@Autowired
- @Getter private DiscoveryService discoveryService;
+ @Getter
+ private DiscoveryService discoveryService;
@Autowired
- @Getter @Setter private ComponentDiscoveryService componentService;
+ @Getter
+ @Setter
+ private ComponentDiscoveryService componentService;
@Autowired
- @Getter private ClusterRoutingService routingService;
+ @Getter
+ private ClusterRoutingService routingService;
@Autowired
- @Getter private ClusterRpcService rpcService;
+ @Getter
+ private ClusterRpcService rpcService;
@Autowired
- @Getter private DeviceAuthService deviceAuthService;
+ @Getter
+ private DeviceAuthService deviceAuthService;
@Autowired
- @Getter private DeviceService deviceService;
+ @Getter
+ private DeviceService deviceService;
@Autowired
- @Getter private AssetService assetService;
+ @Getter
+ private AssetService assetService;
@Autowired
- @Getter private TenantService tenantService;
+ @Getter
+ private TenantService tenantService;
@Autowired
- @Getter private CustomerService customerService;
+ @Getter
+ private CustomerService customerService;
@Autowired
- @Getter private RuleService ruleService;
+ @Getter
+ private UserService userService;
@Autowired
- @Getter private PluginService pluginService;
+ @Getter
+ private RuleService ruleService;
@Autowired
- @Getter private TimeseriesService tsService;
+ @Getter
+ private RuleChainService ruleChainService;
@Autowired
- @Getter private AttributesService attributesService;
+ @Getter
+ private PluginService pluginService;
@Autowired
- @Getter private EventService eventService;
+ @Getter
+ private TimeseriesService tsService;
@Autowired
- @Getter private AlarmService alarmService;
+ @Getter
+ private AttributesService attributesService;
@Autowired
- @Getter private RelationService relationService;
+ @Getter
+ private EventService eventService;
@Autowired
- @Getter private AuditLogService auditLogService;
+ @Getter
+ private AlarmService alarmService;
@Autowired
- @Getter @Setter private PluginWebSocketMsgEndpoint wsMsgEndpoint;
+ @Getter
+ private RelationService relationService;
+
+ @Autowired
+ @Getter
+ private AuditLogService auditLogService;
+
+ @Autowired
+ @Getter
+ private TelemetrySubscriptionService tsSubService;
+
+ @Autowired
+ @Getter
+ @Setter
+ private PluginWebSocketMsgEndpoint wsMsgEndpoint;
+
+ @Autowired
+ @Getter
+ private JsExecutorService jsExecutor;
+
+ @Autowired
+ @Getter
+ private MailExecutorService mailExecutor;
+
+ @Autowired
+ @Getter
+ private DbCallbackExecutorService dbCallbackExecutor;
+
+ @Autowired
+ @Getter
+ private MailService mailService;
@Value("${actors.session.sync.timeout}")
- @Getter private long syncSessionTimeout;
+ @Getter
+ private long syncSessionTimeout;
@Value("${actors.plugin.termination.delay}")
- @Getter private long pluginActorTerminationDelay;
+ @Getter
+ private long pluginActorTerminationDelay;
@Value("${actors.plugin.processing.timeout}")
- @Getter private long pluginProcessingTimeout;
+ @Getter
+ private long pluginProcessingTimeout;
@Value("${actors.plugin.error_persist_frequency}")
- @Getter private long pluginErrorPersistFrequency;
+ @Getter
+ private long pluginErrorPersistFrequency;
+
+ @Value("${actors.rule.chain.error_persist_frequency}")
+ @Getter
+ private long ruleChainErrorPersistFrequency;
+
+ @Value("${actors.rule.node.error_persist_frequency}")
+ @Getter
+ private long ruleNodeErrorPersistFrequency;
@Value("${actors.rule.termination.delay}")
- @Getter private long ruleActorTerminationDelay;
+ @Getter
+ private long ruleActorTerminationDelay;
@Value("${actors.rule.error_persist_frequency}")
- @Getter private long ruleErrorPersistFrequency;
+ @Getter
+ private long ruleErrorPersistFrequency;
@Value("${actors.statistics.enabled}")
- @Getter private boolean statisticsEnabled;
+ @Getter
+ private boolean statisticsEnabled;
@Value("${actors.statistics.persist_frequency}")
- @Getter private long statisticsPersistFrequency;
+ @Getter
+ private long statisticsPersistFrequency;
@Value("${actors.tenant.create_components_on_init}")
- @Getter private boolean tenantComponentsInitEnabled;
+ @Getter
+ private boolean tenantComponentsInitEnabled;
- @Getter @Setter private ActorSystem actorSystem;
+ @Getter
+ @Setter
+ private ActorSystem actorSystem;
- @Getter @Setter private ActorRef appActor;
+ @Getter
+ @Setter
+ private ActorRef appActor;
- @Getter @Setter private ActorRef sessionManagerActor;
+ @Getter
+ @Setter
+ private ActorRef sessionManagerActor;
- @Getter @Setter private ActorRef statsActor;
+ @Getter
+ @Setter
+ private ActorRef statsActor;
- @Getter private final Config config;
+ @Getter
+ private final Config config;
public ActorSystemContext() {
config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load());
@@ -187,7 +275,7 @@ public class ActorSystemContext {
eventService.save(event);
}
- private String toString(Exception e) {
+ private String toString(Throwable e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
return sw.toString();
@@ -207,4 +295,60 @@ public class ActorSystemContext {
private JsonNode toBodyJson(ServerAddress server, String method, String body) {
return mapper.createObjectNode().put("server", server.toString()).put("method", method).put("error", body);
}
+
+ public String getServerAddress() {
+ return discoveryService.getCurrentServer().getServerAddress().toString();
+ }
+
+ public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg) {
+ persistDebug(tenantId, entityId, "IN", tbMsg, null);
+ }
+
+ public void persistDebugInput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, Throwable error) {
+ persistDebug(tenantId, entityId, "IN", tbMsg, error);
+ }
+
+ public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg, Throwable error) {
+ persistDebug(tenantId, entityId, "OUT", tbMsg, error);
+ }
+
+ public void persistDebugOutput(TenantId tenantId, EntityId entityId, TbMsg tbMsg) {
+ persistDebug(tenantId, entityId, "OUT", tbMsg, null);
+ }
+
+ private void persistDebug(TenantId tenantId, EntityId entityId, String type, TbMsg tbMsg, Throwable error) {
+ try {
+ Event event = new Event();
+ event.setTenantId(tenantId);
+ event.setEntityId(entityId);
+ event.setType(DataConstants.DEBUG_RULE_NODE);
+
+ String metadata = mapper.writeValueAsString(tbMsg.getMetaData().getData());
+
+ ObjectNode node = mapper.createObjectNode()
+ .put("type", type)
+ .put("server", getServerAddress())
+ .put("entityId", tbMsg.getOriginator().getId().toString())
+ .put("entityName", tbMsg.getOriginator().getEntityType().name())
+ .put("msgId", tbMsg.getId().toString())
+ .put("msgType", tbMsg.getType())
+ .put("dataType", tbMsg.getDataType().name())
+ .put("data", tbMsg.getData())
+ .put("metadata", metadata);
+
+ if (error != null) {
+ node = node.put("error", toString(error));
+ }
+
+ event.setBody(node);
+ eventService.save(event);
+ } catch (IOException ex) {
+ log.warn("Failed to persist rule node debug message", ex);
+ }
+ }
+
+ public static Exception toException(Throwable error) {
+ return Exception.class.isInstance(error) ? (Exception) error : new Exception(error);
+ }
+
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java
index b475277630..a75158f2dd 100644
--- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java
@@ -22,48 +22,41 @@ import akka.event.LoggingAdapter;
import akka.japi.Function;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.plugin.PluginTerminationMsg;
-import org.thingsboard.server.actors.service.ContextAwareActor;
+import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.actors.service.DefaultActorService;
-import org.thingsboard.server.actors.shared.plugin.PluginManager;
import org.thingsboard.server.actors.shared.plugin.SystemPluginManager;
-import org.thingsboard.server.actors.shared.rule.RuleManager;
-import org.thingsboard.server.actors.shared.rule.SystemRuleManager;
-import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg;
+import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager;
import org.thingsboard.server.actors.tenant.TenantActor;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.PluginId;
-import org.thingsboard.server.common.data.id.RuleId;
+import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageDataIterable;
+import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
+import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg;
-import org.thingsboard.server.extensions.api.rules.ToRuleActorMsg;
import scala.concurrent.duration.Duration;
import java.util.HashMap;
import java.util.Map;
-import java.util.Optional;
-public class AppActor extends ContextAwareActor {
+public class AppActor extends RuleChainManagerActor {
private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);
public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
- private final RuleManager ruleManager;
- private final PluginManager pluginManager;
private final TenantService tenantService;
private final Map tenantActors;
private AppActor(ActorSystemContext systemContext) {
- super(systemContext);
- this.ruleManager = new SystemRuleManager(systemContext);
- this.pluginManager = new SystemPluginManager(systemContext);
+ super(systemContext, new SystemRuleChainManager(systemContext), new SystemPluginManager(systemContext));
this.tenantService = systemContext.getTenantService();
this.tenantActors = new HashMap<>();
}
@@ -77,8 +70,7 @@ public class AppActor extends ContextAwareActor {
public void preStart() {
logger.info("Starting main system actor.");
try {
- ruleManager.init(this.context());
- pluginManager.init(this.context());
+ initRuleChains();
if (systemContext.isTenantComponentsInitEnabled()) {
PageDataIterable tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);
@@ -96,29 +88,51 @@ public class AppActor extends ContextAwareActor {
}
@Override
- public void onReceive(Object msg) throws Exception {
- logger.debug("Received message: {}", msg);
- if (msg instanceof ToDeviceActorMsg) {
- processDeviceMsg((ToDeviceActorMsg) msg);
- } else if (msg instanceof ToPluginActorMsg) {
- onToPluginMsg((ToPluginActorMsg) msg);
- } else if (msg instanceof ToRuleActorMsg) {
- onToRuleMsg((ToRuleActorMsg) msg);
- } else if (msg instanceof ToDeviceActorNotificationMsg) {
- onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg);
- } else if (msg instanceof Terminated) {
- processTermination((Terminated) msg);
- } else if (msg instanceof ClusterEventMsg) {
- broadcast(msg);
- } else if (msg instanceof ComponentLifecycleMsg) {
- onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
- } else if (msg instanceof PluginTerminationMsg) {
- onPluginTerminated((PluginTerminationMsg) msg);
+ protected boolean process(TbActorMsg msg) {
+ switch (msg.getMsgType()) {
+ case COMPONENT_LIFE_CYCLE_MSG:
+ onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
+ break;
+ case SERVICE_TO_RULE_ENGINE_MSG:
+ onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) {
+ if (SYSTEM_TENANT.equals(msg.getTenantId())) {
+ //TODO: ashvayka handle this.
} else {
- logger.warning("Unknown message: {}!", msg);
+ getOrCreateTenantActor(msg.getTenantId()).tell(msg, self());
}
}
+
+// @Override
+// public void onReceive(Object msg) throws Exception {
+// logger.debug("Received message: {}", msg);
+// if (msg instanceof ToDeviceActorMsg) {
+// processDeviceMsg((ToDeviceActorMsg) msg);
+// } else if (msg instanceof ToPluginActorMsg) {
+// onToPluginMsg((ToPluginActorMsg) msg);
+// } else if (msg instanceof ToDeviceActorNotificationMsg) {
+// onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg);
+// } else if (msg instanceof Terminated) {
+// processTermination((Terminated) msg);
+// } else if (msg instanceof ClusterEventMsg) {
+// broadcast(msg);
+// } else if (msg instanceof ComponentLifecycleMsg) {
+// onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
+// } else if (msg instanceof PluginTerminationMsg) {
+// onPluginTerminated((PluginTerminationMsg) msg);
+// } else {
+// logger.warning("Unknown message: {}!", msg);
+// }
+// }
+
private void onPluginTerminated(PluginTerminationMsg msg) {
pluginManager.remove(msg.getId());
}
@@ -128,20 +142,10 @@ public class AppActor extends ContextAwareActor {
tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
}
- private void onToRuleMsg(ToRuleActorMsg msg) {
- ActorRef target;
- if (SYSTEM_TENANT.equals(msg.getTenantId())) {
- target = ruleManager.getOrCreateRuleActor(this.context(), msg.getRuleId());
- } else {
- target = getOrCreateTenantActor(msg.getTenantId());
- }
- target.tell(msg, ActorRef.noSender());
- }
-
private void onToPluginMsg(ToPluginActorMsg msg) {
ActorRef target;
if (SYSTEM_TENANT.equals(msg.getPluginTenantId())) {
- target = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId());
+ target = pluginManager.getOrCreateActor(this.context(), msg.getPluginId());
} else {
target = getOrCreateTenantActor(msg.getPluginTenantId());
}
@@ -149,26 +153,16 @@ public class AppActor extends ContextAwareActor {
}
private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
- ActorRef target = null;
+ ActorRef target;
if (SYSTEM_TENANT.equals(msg.getTenantId())) {
- Optional pluginId = msg.getPluginId();
- Optional ruleId = msg.getRuleId();
- if (pluginId.isPresent()) {
- target = pluginManager.getOrCreatePluginActor(this.context(), pluginId.get());
- } else if (ruleId.isPresent()) {
- Optional ref = ruleManager.update(this.context(), ruleId.get(), msg.getEvent());
- if (ref.isPresent()) {
- target = ref.get();
- } else {
- logger.debug("Failed to find actor for rule: [{}]", ruleId);
- return;
- }
- }
+ target = getEntityActorRef(msg.getEntityId());
} else {
target = getOrCreateTenantActor(msg.getTenantId());
}
if (target != null) {
target.tell(msg, ActorRef.noSender());
+ } else {
+ logger.debug("Invalid component lifecycle msg: {}", msg);
}
}
@@ -180,7 +174,7 @@ public class AppActor extends ContextAwareActor {
TenantId tenantId = toDeviceActorMsg.getTenantId();
ActorRef tenantActor = getOrCreateTenantActor(tenantId);
if (toDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) {
- tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self());
+// tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self());
} else {
tenantActor.tell(toDeviceActorMsg, context().self());
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java
index 861c405e08..87bc9926d4 100644
--- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActor.java
@@ -18,19 +18,19 @@ package org.thingsboard.server.actors.device;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import org.thingsboard.server.actors.ActorSystemContext;
-import org.thingsboard.server.actors.rule.RulesProcessedMsg;
import org.thingsboard.server.actors.service.ContextAwareActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
-import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
-import org.thingsboard.server.extensions.api.plugins.msg.*;
+import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
+import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg;
public class DeviceActor extends ContextAwareActor {
@@ -47,13 +47,18 @@ public class DeviceActor extends ContextAwareActor {
this.processor = new DeviceActorMessageProcessor(systemContext, logger, deviceId);
}
+ @Override
+ protected boolean process(TbActorMsg msg) {
+ return false;
+ }
+
@Override
public void onReceive(Object msg) throws Exception {
- if (msg instanceof RuleChainDeviceMsg) {
- processor.process(context(), (RuleChainDeviceMsg) msg);
- } else if (msg instanceof RulesProcessedMsg) {
- processor.onRulesProcessedMsg(context(), (RulesProcessedMsg) msg);
- } else if (msg instanceof ToDeviceActorMsg) {
+// if (msg instanceof RuleChainDeviceMsg) {
+// processor.process(context(), (RuleChainDeviceMsg) msg);
+// } else if (msg instanceof RulesProcessedMsg) {
+// processor.onRulesProcessedMsg(context(), (RulesProcessedMsg) msg);
+ if (msg instanceof ToDeviceActorMsg) {
processor.process(context(), (ToDeviceActorMsg) msg);
} else if (msg instanceof ToDeviceActorNotificationMsg) {
if (msg instanceof DeviceAttributesEventNotificationMsg) {
diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
index 21112bf4df..3644a491a4 100644
--- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
@@ -19,9 +19,7 @@ import akka.actor.ActorContext;
import akka.actor.ActorRef;
import akka.event.LoggingAdapter;
import org.thingsboard.server.actors.ActorSystemContext;
-import org.thingsboard.server.actors.rule.*;
import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
-import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
@@ -37,15 +35,10 @@ import org.thingsboard.server.common.msg.session.FromDeviceMsg;
import org.thingsboard.server.common.msg.session.MsgType;
import org.thingsboard.server.common.msg.session.SessionType;
import org.thingsboard.server.common.msg.session.ToDeviceMsg;
-import org.thingsboard.server.extensions.api.device.*;
-import org.thingsboard.server.extensions.api.plugins.msg.FromDeviceRpcResponse;
-import org.thingsboard.server.extensions.api.plugins.msg.RpcError;
-import org.thingsboard.server.extensions.api.plugins.msg.TimeoutIntMsg;
-import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
-import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequest;
-import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestBody;
-import org.thingsboard.server.extensions.api.plugins.msg.ToDeviceRpcRequestPluginMsg;
-import org.thingsboard.server.extensions.api.plugins.msg.ToPluginRpcResponseDeviceMsg;
+import org.thingsboard.server.extensions.api.device.DeviceAttributes;
+import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
+import org.thingsboard.server.extensions.api.device.DeviceNameOrTypeUpdateMsg;
+import org.thingsboard.server.extensions.api.plugins.msg.*;
import java.util.*;
import java.util.concurrent.ExecutionException;
@@ -230,18 +223,18 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
}
}
- void process(ActorContext context, RuleChainDeviceMsg srcMsg) {
- ChainProcessingMetaData md = new ChainProcessingMetaData(srcMsg.getRuleChain(),
- srcMsg.getToDeviceActorMsg(), new DeviceMetaData(deviceId, deviceName, deviceType, deviceAttributes), context.self());
- ChainProcessingContext ctx = new ChainProcessingContext(md);
- if (ctx.getChainLength() > 0) {
- RuleProcessingMsg msg = new RuleProcessingMsg(ctx);
- ActorRef ruleActorRef = ctx.getCurrentActor();
- ruleActorRef.tell(msg, ActorRef.noSender());
- } else {
- context.self().tell(new RulesProcessedMsg(ctx), context.self());
- }
- }
+// void process(ActorContext context, RuleChainDeviceMsg srcMsg) {
+// ChainProcessingMetaData md = new ChainProcessingMetaData(srcMsg.getRuleChain(),
+// srcMsg.getToDeviceActorMsg(), new DeviceMetaData(deviceId, deviceName, deviceType, deviceAttributes), context.self());
+// ChainProcessingContext ctx = new ChainProcessingContext(md);
+// if (ctx.getChainLength() > 0) {
+// RuleProcessingMsg msg = new RuleProcessingMsg(ctx);
+// ActorRef ruleActorRef = ctx.getCurrentActor();
+// ruleActorRef.tell(msg, ActorRef.noSender());
+// } else {
+// context.self().tell(new RulesProcessedMsg(ctx), context.self());
+// }
+// }
void processRpcResponses(ActorContext context, ToDeviceActorMsg msg) {
SessionId sessionId = msg.getSessionId();
@@ -302,18 +295,18 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
);
}
- void onRulesProcessedMsg(ActorContext context, RulesProcessedMsg msg) {
- ChainProcessingContext ctx = msg.getCtx();
- ToDeviceActorMsg inMsg = ctx.getInMsg();
- SessionId sid = inMsg.getSessionId();
- ToDeviceSessionActorMsg response;
- if (ctx.getResponse() != null) {
- response = new BasicToDeviceSessionActorMsg(ctx.getResponse(), sid);
- } else {
- response = new BasicToDeviceSessionActorMsg(ctx.getError(), sid);
- }
- sendMsgToSessionActor(response, inMsg.getServerAddress());
- }
+// void onRulesProcessedMsg(ActorContext context, RulesProcessedMsg msg) {
+// ChainProcessingContext ctx = msg.getCtx();
+// ToDeviceActorMsg inMsg = ctx.getInMsg();
+// SessionId sid = inMsg.getSessionId();
+// ToDeviceSessionActorMsg response;
+// if (ctx.getResponse() != null) {
+// response = new BasicToDeviceSessionActorMsg(ctx.getResponse(), sid);
+// } else {
+// response = new BasicToDeviceSessionActorMsg(ctx.getError(), sid);
+// }
+// sendMsgToSessionActor(response, inMsg.getServerAddress());
+// }
private void processSubscriptionCommands(ActorContext context, ToDeviceActorMsg msg) {
SessionId sessionId = msg.getSessionId();
diff --git a/application/src/main/java/org/thingsboard/server/actors/plugin/PluginActor.java b/application/src/main/java/org/thingsboard/server/actors/plugin/PluginActor.java
index 265da386ff..88278f316d 100644
--- a/application/src/main/java/org/thingsboard/server/actors/plugin/PluginActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/plugin/PluginActor.java
@@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.actors.stats.StatsPersistTick;
import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.extensions.api.plugins.msg.TimeoutMsg;
@@ -40,6 +41,12 @@ public class PluginActor extends ComponentActor
}
@Override
- public void start() throws Exception {
+ public void start(ActorContext context) throws Exception {
logger.info("[{}] Going to start plugin actor.", entityId);
pluginMd = systemContext.getPluginService().findPluginById(entityId);
if (pluginMd == null) {
@@ -76,7 +81,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor
}
@Override
- public void stop() throws Exception {
+ public void stop(ActorContext context) throws Exception {
onStop();
}
@@ -98,7 +103,20 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor
public void onRuleToPluginMsg(RuleToPluginMsgWrapper msg) throws RuleException {
if (state == ComponentLifecycleState.ACTIVE) {
- pluginImpl.process(trustedCtx, msg.getRuleTenantId(), msg.getRuleId(), msg.getMsg());
+ try {
+ pluginImpl.process(trustedCtx, msg.getRuleTenantId(), msg.getRuleId(), msg.getMsg());
+ } catch (Exception ex) {
+ logger.debug("[{}] Failed to process RuleToPlugin msg: [{}] [{}]", tenantId, msg.getMsg(), ex);
+ RuleToPluginMsg ruleMsg = msg.getMsg();
+ MsgType responceMsgType = MsgType.RULE_ENGINE_ERROR;
+ Integer requestId = 0;
+ if (ruleMsg.getPayload() instanceof FromDeviceRequestMsg) {
+ requestId = ((FromDeviceRequestMsg) ruleMsg.getPayload()).getRequestId();
+ }
+ trustedCtx.reply(
+ new ResponsePluginToRuleMsg(ruleMsg.getUid(), tenantId, msg.getRuleId(),
+ BasicStatusCodeResponse.onError(responceMsgType, requestId, ex)));
+ }
} else {
//TODO: reply with plugin suspended message
}
@@ -191,7 +209,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor
if (pluginImpl != null) {
pluginImpl.stop(trustedCtx);
}
- start();
+ start(context);
}
}
@@ -217,7 +235,7 @@ public class PluginActorMessageProcessor extends ComponentMsgProcessor
pluginImpl.resume(trustedCtx);
logger.info("[{}] Plugin resumed.", entityId);
} else {
- start();
+ start(context);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/plugin/PluginProcessingContext.java b/application/src/main/java/org/thingsboard/server/actors/plugin/PluginProcessingContext.java
index ce95ee4629..10f16ce8b1 100644
--- a/application/src/main/java/org/thingsboard/server/actors/plugin/PluginProcessingContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/plugin/PluginProcessingContext.java
@@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
+import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleMetaData;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.extensions.api.device.DeviceAttributesEventNotificationMsg;
@@ -330,6 +331,9 @@ public final class PluginProcessingContext implements PluginContext {
case RULE:
validateRule(ctx, entityId, callback);
return;
+ case RULE_CHAIN:
+ validateRuleChain(ctx, entityId, callback);
+ return;
case PLUGIN:
validatePlugin(ctx, entityId, callback);
return;
@@ -411,6 +415,28 @@ public final class PluginProcessingContext implements PluginContext {
}
}
+ private void validateRuleChain(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) {
+ if (ctx.isCustomerUser()) {
+ callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
+ } else {
+ ListenableFuture ruleChainFuture = pluginCtx.ruleChainService.findRuleChainByIdAsync(new RuleChainId(entityId.getId()));
+ Futures.addCallback(ruleChainFuture, getCallback(callback, ruleChain -> {
+ if (ruleChain == null) {
+ return ValidationResult.entityNotFound("Rule chain with requested id wasn't found!");
+ } else {
+ if (ctx.isTenantAdmin() && !ruleChain.getTenantId().equals(ctx.getTenantId())) {
+ return ValidationResult.accessDenied("Rule chain doesn't belong to the current Tenant!");
+ } else if (ctx.isSystemAdmin() && !ruleChain.getTenantId().isNullUid()) {
+ return ValidationResult.accessDenied("Rule chain is not in system scope!");
+ } else {
+ return ValidationResult.ok();
+ }
+ }
+ }));
+ }
+ }
+
+
private void validatePlugin(final PluginApiCallSecurityContext ctx, EntityId entityId, ValidationCallback callback) {
if (ctx.isCustomerUser()) {
callback.onSuccess(this, ValidationResult.accessDenied(CUSTOMER_USER_IS_NOT_ALLOWED_TO_PERFORM_THIS_OPERATION));
diff --git a/application/src/main/java/org/thingsboard/server/actors/plugin/SharedPluginProcessingContext.java b/application/src/main/java/org/thingsboard/server/actors/plugin/SharedPluginProcessingContext.java
index 06138a3308..182897025e 100644
--- a/application/src/main/java/org/thingsboard/server/actors/plugin/SharedPluginProcessingContext.java
+++ b/application/src/main/java/org/thingsboard/server/actors/plugin/SharedPluginProcessingContext.java
@@ -32,6 +32,7 @@ import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.plugin.PluginService;
import org.thingsboard.server.dao.relation.RelationService;
+import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.rule.RuleService;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.timeseries.TimeseriesService;
@@ -56,6 +57,7 @@ public final class SharedPluginProcessingContext {
final AssetService assetService;
final DeviceService deviceService;
final RuleService ruleService;
+ final RuleChainService ruleChainService;
final PluginService pluginService;
final CustomerService customerService;
final TenantService tenantService;
@@ -84,6 +86,7 @@ public final class SharedPluginProcessingContext {
this.rpcService = sysContext.getRpcService();
this.routingService = sysContext.getRoutingService();
this.ruleService = sysContext.getRuleService();
+ this.ruleChainService = sysContext.getRuleChainService();
this.pluginService = sysContext.getPluginService();
this.customerService = sysContext.getCustomerService();
this.tenantService = sysContext.getTenantService();
diff --git a/application/src/main/java/org/thingsboard/server/actors/rpc/RpcManagerActor.java b/application/src/main/java/org/thingsboard/server/actors/rpc/RpcManagerActor.java
index 9290a8fe58..ba20013456 100644
--- a/application/src/main/java/org/thingsboard/server/actors/rpc/RpcManagerActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/rpc/RpcManagerActor.java
@@ -23,6 +23,7 @@ import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.service.ContextAwareActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.actors.service.DefaultActorService;
+import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
@@ -56,6 +57,12 @@ public class RpcManagerActor extends ContextAwareActor {
}
+ @Override
+ protected boolean process(TbActorMsg msg) {
+ //TODO Move everything here, to work with TbActorMsg
+ return false;
+ }
+
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof RpcSessionTellMsg) {
diff --git a/application/src/main/java/org/thingsboard/server/actors/rpc/RpcSessionActor.java b/application/src/main/java/org/thingsboard/server/actors/rpc/RpcSessionActor.java
index db029fa13b..a187444ea5 100644
--- a/application/src/main/java/org/thingsboard/server/actors/rpc/RpcSessionActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/rpc/RpcSessionActor.java
@@ -23,6 +23,7 @@ import io.grpc.stub.StreamObserver;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.service.ContextAwareActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
+import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.gen.cluster.ClusterAPIProtos;
import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc;
@@ -47,6 +48,12 @@ public class RpcSessionActor extends ContextAwareActor {
this.sessionId = sessionId;
}
+ @Override
+ protected boolean process(TbActorMsg msg) {
+ //TODO Move everything here, to work with TbActorMsg
+ return false;
+ }
+
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof RpcSessionTellMsg) {
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingContext.java b/application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingContext.java
deleted file mode 100644
index 8723a68516..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingContext.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.rule;
-
-import akka.actor.ActorRef;
-import org.thingsboard.server.common.msg.core.RuleEngineError;
-import org.thingsboard.server.common.msg.core.RuleEngineErrorMsg;
-import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
-import org.thingsboard.server.common.msg.session.ToDeviceMsg;
-import org.thingsboard.server.extensions.api.device.DeviceAttributes;
-import org.thingsboard.server.extensions.api.device.DeviceMetaData;
-
-public class ChainProcessingContext {
-
- private final ChainProcessingMetaData md;
- private final int index;
- private final RuleEngineError error;
- private ToDeviceMsg response;
-
-
- public ChainProcessingContext(ChainProcessingMetaData md) {
- super();
- this.md = md;
- this.index = 0;
- this.error = RuleEngineError.NO_RULES;
- }
-
- private ChainProcessingContext(ChainProcessingContext other, int indexOffset, RuleEngineError error) {
- super();
- this.md = other.md;
- this.index = other.index + indexOffset;
- this.error = error;
- this.response = other.response;
-
- if (this.index < 0 || this.index >= this.md.chain.size()) {
- throw new IllegalArgumentException("Can't apply offset " + indexOffset + " to the chain!");
- }
- }
-
- public ActorRef getDeviceActor() {
- return md.originator;
- }
-
- public ActorRef getCurrentActor() {
- return md.chain.getRuleActorMd(index).getActorRef();
- }
-
- public boolean hasNext() {
- return (getChainLength() - 1) > index;
- }
-
- public boolean isFailure() {
- return (error != null && error.isCritical()) || (response != null && !response.isSuccess());
- }
-
- public ChainProcessingContext getNext() {
- return new ChainProcessingContext(this, 1, this.error);
- }
-
- public ChainProcessingContext withError(RuleEngineError error) {
- if (error != null && (this.error == null || this.error.getPriority() < error.getPriority())) {
- return new ChainProcessingContext(this, 0, error);
- } else {
- return this;
- }
- }
-
- public int getChainLength() {
- return md.chain.size();
- }
-
- public ToDeviceActorMsg getInMsg() {
- return md.inMsg;
- }
-
- public DeviceMetaData getDeviceMetaData() {
- return md.deviceMetaData;
- }
-
- public String getDeviceName() {
- return md.deviceMetaData.getDeviceName();
- }
-
- public String getDeviceType() {
- return md.deviceMetaData.getDeviceType();
- }
-
- public DeviceAttributes getAttributes() {
- return md.deviceMetaData.getDeviceAttributes();
- }
-
- public ToDeviceMsg getResponse() {
- return response;
- }
-
- public void mergeResponse(ToDeviceMsg response) {
- // TODO add merge logic
- this.response = response;
- }
-
- public RuleEngineErrorMsg getError() {
- return new RuleEngineErrorMsg(md.inMsg.getPayload().getMsgType(), error);
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingMetaData.java b/application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingMetaData.java
deleted file mode 100644
index 8080d4ecc9..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/rule/ChainProcessingMetaData.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.rule;
-
-import akka.actor.ActorRef;
-import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
-import org.thingsboard.server.extensions.api.device.DeviceMetaData;
-
-/**
- * Immutable part of chain processing data;
- *
- * @author ashvayka
- */
-public final class ChainProcessingMetaData {
-
- final RuleActorChain chain;
- final ToDeviceActorMsg inMsg;
- final ActorRef originator;
- final DeviceMetaData deviceMetaData;
-
- public ChainProcessingMetaData(RuleActorChain chain, ToDeviceActorMsg inMsg, DeviceMetaData deviceMetaData, ActorRef originator) {
- super();
- this.chain = chain;
- this.inMsg = inMsg;
- this.originator = originator;
- this.deviceMetaData = deviceMetaData;
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/ComplexRuleActorChain.java b/application/src/main/java/org/thingsboard/server/actors/rule/ComplexRuleActorChain.java
deleted file mode 100644
index 89d31bdc84..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/rule/ComplexRuleActorChain.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.rule;
-
-public class ComplexRuleActorChain implements RuleActorChain {
-
- private final RuleActorChain systemChain;
- private final RuleActorChain tenantChain;
-
- public ComplexRuleActorChain(RuleActorChain systemChain, RuleActorChain tenantChain) {
- super();
- this.systemChain = systemChain;
- this.tenantChain = tenantChain;
- }
-
- @Override
- public int size() {
- return systemChain.size() + tenantChain.size();
- }
-
- @Override
- public RuleActorMetaData getRuleActorMd(int index) {
- if (index < systemChain.size()) {
- return systemChain.getRuleActorMd(index);
- } else {
- return tenantChain.getRuleActorMd(index - systemChain.size());
- }
- }
-
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActor.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleActor.java
deleted file mode 100644
index 062da2a3bb..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActor.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.rule;
-
-import org.thingsboard.server.actors.ActorSystemContext;
-import org.thingsboard.server.actors.service.ComponentActor;
-import org.thingsboard.server.actors.service.ContextBasedCreator;
-import org.thingsboard.server.actors.stats.StatsPersistTick;
-import org.thingsboard.server.common.data.id.RuleId;
-import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
-import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
-import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg;
-
-public class RuleActor extends ComponentActor {
-
- private RuleActor(ActorSystemContext systemContext, TenantId tenantId, RuleId ruleId) {
- super(systemContext, tenantId, ruleId);
- setProcessor(new RuleActorMessageProcessor(tenantId, ruleId, systemContext, logger));
- }
-
- @Override
- public void onReceive(Object msg) throws Exception {
- logger.debug("[{}] Received message: {}", id, msg);
- if (msg instanceof RuleProcessingMsg) {
- try {
- processor.onRuleProcessingMsg(context(), (RuleProcessingMsg) msg);
- increaseMessagesProcessedCount();
- } catch (Exception e) {
- logAndPersist("onDeviceMsg", e);
- }
- } else if (msg instanceof PluginToRuleMsg>) {
- try {
- processor.onPluginMsg(context(), (PluginToRuleMsg>) msg);
- } catch (Exception e) {
- logAndPersist("onPluginMsg", e);
- }
- } else if (msg instanceof ComponentLifecycleMsg) {
- onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
- } else if (msg instanceof ClusterEventMsg) {
- onClusterEventMsg((ClusterEventMsg) msg);
- } else if (msg instanceof RuleToPluginTimeoutMsg) {
- try {
- processor.onTimeoutMsg(context(), (RuleToPluginTimeoutMsg) msg);
- } catch (Exception e) {
- logAndPersist("onTimeoutMsg", e);
- }
- } else if (msg instanceof StatsPersistTick) {
- onStatsPersistTick(id);
- } else {
- logger.debug("[{}][{}] Unknown msg type.", tenantId, id, msg.getClass().getName());
- }
- }
-
- public static class ActorCreator extends ContextBasedCreator {
- private static final long serialVersionUID = 1L;
-
- private final TenantId tenantId;
- private final RuleId ruleId;
-
- public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleId ruleId) {
- super(context);
- this.tenantId = tenantId;
- this.ruleId = ruleId;
- }
-
- @Override
- public RuleActor create() throws Exception {
- return new RuleActor(context, tenantId, ruleId);
- }
- }
-
- @Override
- protected long getErrorPersistFrequency() {
- return systemContext.getRuleErrorPersistFrequency();
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMessageProcessor.java
deleted file mode 100644
index 2ebebfca33..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMessageProcessor.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.rule;
-
-import java.util.*;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import org.springframework.util.StringUtils;
-import org.thingsboard.server.actors.ActorSystemContext;
-import org.thingsboard.server.actors.plugin.RuleToPluginMsgWrapper;
-import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
-import org.thingsboard.server.common.data.id.PluginId;
-import org.thingsboard.server.common.data.id.RuleId;
-import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
-import org.thingsboard.server.common.data.plugin.PluginMetaData;
-import org.thingsboard.server.common.data.rule.RuleMetaData;
-import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
-import org.thingsboard.server.common.msg.core.BasicRequest;
-import org.thingsboard.server.common.msg.core.BasicStatusCodeResponse;
-import org.thingsboard.server.common.msg.core.RuleEngineError;
-import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
-import org.thingsboard.server.common.msg.session.MsgType;
-import org.thingsboard.server.common.msg.session.ToDeviceMsg;
-import org.thingsboard.server.common.msg.session.ex.ProcessingTimeoutException;
-import org.thingsboard.server.extensions.api.rules.*;
-import org.thingsboard.server.extensions.api.plugins.PluginAction;
-import org.thingsboard.server.extensions.api.plugins.msg.PluginToRuleMsg;
-import org.thingsboard.server.extensions.api.plugins.msg.RuleToPluginMsg;
-
-import com.fasterxml.jackson.databind.JsonNode;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import akka.event.LoggingAdapter;
-
-class RuleActorMessageProcessor extends ComponentMsgProcessor {
-
- private final RuleProcessingContext ruleCtx;
- private final Map pendingMsgMap;
-
- private RuleMetaData ruleMd;
- private ComponentLifecycleState state;
- private List filters;
- private RuleProcessor processor;
- private PluginAction action;
-
- private TenantId pluginTenantId;
- private PluginId pluginId;
-
- protected RuleActorMessageProcessor(TenantId tenantId, RuleId ruleId, ActorSystemContext systemContext, LoggingAdapter logger) {
- super(systemContext, logger, tenantId, ruleId);
- this.pendingMsgMap = new HashMap<>();
- this.ruleCtx = new RuleProcessingContext(systemContext, ruleId);
- }
-
- @Override
- public void start() throws Exception {
- logger.info("[{}][{}] Starting rule actor.", entityId, tenantId);
- ruleMd = systemContext.getRuleService().findRuleById(entityId);
- if (ruleMd == null) {
- throw new RuleInitializationException("Rule not found!");
- }
- state = ruleMd.getState();
- if (state == ComponentLifecycleState.ACTIVE) {
- logger.info("[{}] Rule is active. Going to initialize rule components.", entityId);
- initComponent();
- } else {
- logger.info("[{}] Rule is suspended. Skipping rule components initialization.", entityId);
- }
-
- logger.info("[{}][{}] Started rule actor.", entityId, tenantId);
- }
-
- @Override
- public void stop() throws Exception {
- onStop();
- }
-
-
- private void initComponent() throws RuleException {
- try {
- if (!ruleMd.getFilters().isArray()) {
- throw new RuntimeException("Filters are not array!");
- }
- fetchPluginInfo();
- initFilters();
- initProcessor();
- initAction();
- } catch (RuntimeException e) {
- throw new RuleInitializationException("Unknown runtime exception!", e);
- } catch (InstantiationException e) {
- throw new RuleInitializationException("No default constructor for rule implementation!", e);
- } catch (IllegalAccessException e) {
- throw new RuleInitializationException("Illegal Access Exception during rule initialization!", e);
- } catch (ClassNotFoundException e) {
- throw new RuleInitializationException("Rule Class not found!", e);
- } catch (Exception e) {
- throw new RuleException(e.getMessage(), e);
- }
- }
-
- private void initAction() throws Exception {
- if (ruleMd.getAction() != null && !ruleMd.getAction().isNull()) {
- action = initComponent(ruleMd.getAction());
- }
- }
-
- private void initProcessor() throws Exception {
- if (ruleMd.getProcessor() != null && !ruleMd.getProcessor().isNull()) {
- processor = initComponent(ruleMd.getProcessor());
- }
- }
-
- private void initFilters() throws Exception {
- filters = new ArrayList<>(ruleMd.getFilters().size());
- for (int i = 0; i < ruleMd.getFilters().size(); i++) {
- filters.add(initComponent(ruleMd.getFilters().get(i)));
- }
- }
-
- private void fetchPluginInfo() {
- if (!StringUtils.isEmpty(ruleMd.getPluginToken())) {
- PluginMetaData pluginMd = systemContext.getPluginService().findPluginByApiToken(ruleMd.getPluginToken());
- pluginTenantId = pluginMd.getTenantId();
- pluginId = pluginMd.getId();
- }
- }
-
- protected void onRuleProcessingMsg(ActorContext context, RuleProcessingMsg msg) throws RuleException {
- if (state != ComponentLifecycleState.ACTIVE) {
- pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_ACTIVE_RULES);
- return;
- }
- ChainProcessingContext chainCtx = msg.getCtx();
- ToDeviceActorMsg inMsg = chainCtx.getInMsg();
-
- ruleCtx.update(inMsg, chainCtx.getDeviceMetaData());
-
- logger.debug("[{}] Going to filter in msg: {}", entityId, inMsg);
- for (RuleFilter filter : filters) {
- if (!filter.filter(ruleCtx, inMsg)) {
- logger.debug("[{}] In msg is NOT valid for processing by current rule: {}", entityId, inMsg);
- pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_FILTERS_MATCHED);
- return;
- }
- }
- RuleProcessingMetaData inMsgMd;
- if (processor != null) {
- logger.debug("[{}] Going to process in msg: {}", entityId, inMsg);
- inMsgMd = processor.process(ruleCtx, inMsg);
- } else {
- inMsgMd = new RuleProcessingMetaData();
- }
- logger.debug("[{}] Going to convert in msg: {}", entityId, inMsg);
- if (action != null) {
- Optional> ruleToPluginMsgOptional = action.convert(ruleCtx, inMsg, inMsgMd);
- if (ruleToPluginMsgOptional.isPresent()) {
- RuleToPluginMsg> ruleToPluginMsg = ruleToPluginMsgOptional.get();
- logger.debug("[{}] Device msg is converted to: {}", entityId, ruleToPluginMsg);
- context.parent().tell(new RuleToPluginMsgWrapper(pluginTenantId, pluginId, tenantId, entityId, ruleToPluginMsg), context.self());
- if (action.isOneWayAction()) {
- pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_TWO_WAY_ACTIONS);
- return;
- } else {
- pendingMsgMap.put(ruleToPluginMsg.getUid(), msg);
- scheduleMsgWithDelay(context, new RuleToPluginTimeoutMsg(ruleToPluginMsg.getUid()), systemContext.getPluginProcessingTimeout());
- return;
- }
- }
- }
- logger.debug("[{}] Nothing to send to plugin: {}", entityId, pluginId);
- pushToNextRule(context, msg.getCtx(), RuleEngineError.NO_TWO_WAY_ACTIONS);
- }
-
- void onPluginMsg(ActorContext context, PluginToRuleMsg> msg) {
- RuleProcessingMsg pendingMsg = pendingMsgMap.remove(msg.getUid());
- if (pendingMsg != null) {
- ChainProcessingContext ctx = pendingMsg.getCtx();
- Optional ruleResponseOptional = action.convert(msg);
- if (ruleResponseOptional.isPresent()) {
- ctx.mergeResponse(ruleResponseOptional.get());
- pushToNextRule(context, ctx, null);
- } else {
- pushToNextRule(context, ctx, RuleEngineError.NO_RESPONSE_FROM_ACTIONS);
- }
- } else {
- logger.warning("[{}] Processing timeout detected: [{}]", entityId, msg.getUid());
- }
- }
-
- void onTimeoutMsg(ActorContext context, RuleToPluginTimeoutMsg msg) {
- RuleProcessingMsg pendingMsg = pendingMsgMap.remove(msg.getMsgId());
- if (pendingMsg != null) {
- logger.debug("[{}] Processing timeout detected [{}]: {}", entityId, msg.getMsgId(), pendingMsg);
- ChainProcessingContext ctx = pendingMsg.getCtx();
- pushToNextRule(context, ctx, RuleEngineError.PLUGIN_TIMEOUT);
- }
- }
-
- private void pushToNextRule(ActorContext context, ChainProcessingContext ctx, RuleEngineError error) {
- if (error != null) {
- ctx = ctx.withError(error);
- }
- if (ctx.isFailure()) {
- logger.debug("[{}][{}] Forwarding processing chain to device actor due to failure.", ruleMd.getId(), ctx.getInMsg().getDeviceId());
- ctx.getDeviceActor().tell(new RulesProcessedMsg(ctx), ActorRef.noSender());
- } else if (!ctx.hasNext()) {
- logger.debug("[{}][{}] Forwarding processing chain to device actor due to end of chain.", ruleMd.getId(), ctx.getInMsg().getDeviceId());
- ctx.getDeviceActor().tell(new RulesProcessedMsg(ctx), ActorRef.noSender());
- } else {
- logger.debug("[{}][{}] Forwarding processing chain to next rule actor.", ruleMd.getId(), ctx.getInMsg().getDeviceId());
- ChainProcessingContext nextTask = ctx.getNext();
- nextTask.getCurrentActor().tell(new RuleProcessingMsg(nextTask), context.self());
- }
- }
-
- @Override
- public void onCreated(ActorContext context) {
- logger.info("[{}] Going to process onCreated rule.", entityId);
- }
-
- @Override
- public void onUpdate(ActorContext context) throws RuleException {
- RuleMetaData oldRuleMd = ruleMd;
- ruleMd = systemContext.getRuleService().findRuleById(entityId);
- logger.info("[{}] Rule configuration was updated from {} to {}.", entityId, oldRuleMd, ruleMd);
- try {
- fetchPluginInfo();
- if (filters == null || !Objects.equals(oldRuleMd.getFilters(), ruleMd.getFilters())) {
- logger.info("[{}] Rule filters require restart due to json change from {} to {}.",
- entityId, mapper.writeValueAsString(oldRuleMd.getFilters()), mapper.writeValueAsString(ruleMd.getFilters()));
- stopFilters();
- initFilters();
- }
- if (processor == null || !Objects.equals(oldRuleMd.getProcessor(), ruleMd.getProcessor())) {
- logger.info("[{}] Rule processor require restart due to configuration change.", entityId);
- stopProcessor();
- initProcessor();
- }
- if (action == null || !Objects.equals(oldRuleMd.getAction(), ruleMd.getAction())) {
- logger.info("[{}] Rule action require restart due to configuration change.", entityId);
- stopAction();
- initAction();
- }
- } catch (RuntimeException e) {
- throw new RuleInitializationException("Unknown runtime exception!", e);
- } catch (InstantiationException e) {
- throw new RuleInitializationException("No default constructor for rule implementation!", e);
- } catch (IllegalAccessException e) {
- throw new RuleInitializationException("Illegal Access Exception during rule initialization!", e);
- } catch (ClassNotFoundException e) {
- throw new RuleInitializationException("Rule Class not found!", e);
- } catch (JsonProcessingException e) {
- throw new RuleInitializationException("Rule configuration is invalid!", e);
- } catch (Exception e) {
- throw new RuleInitializationException(e.getMessage(), e);
- }
- }
-
- @Override
- public void onActivate(ActorContext context) throws Exception {
- logger.info("[{}] Going to process onActivate rule.", entityId);
- this.state = ComponentLifecycleState.ACTIVE;
- if (filters != null) {
- filters.forEach(RuleLifecycleComponent::resume);
- if (processor != null) {
- processor.resume();
- } else {
- initProcessor();
- }
- if (action != null) {
- action.resume();
- }
- logger.info("[{}] Rule resumed.", entityId);
- } else {
- start();
- }
- }
-
- @Override
- public void onSuspend(ActorContext context) {
- logger.info("[{}] Going to process onSuspend rule.", entityId);
- this.state = ComponentLifecycleState.SUSPENDED;
- if (filters != null) {
- filters.forEach(f -> f.suspend());
- }
- if (processor != null) {
- processor.suspend();
- }
- if (action != null) {
- action.suspend();
- }
- }
-
- @Override
- public void onStop(ActorContext context) {
- logger.info("[{}] Going to process onStop rule.", entityId);
- onStop();
- scheduleMsgWithDelay(context, new RuleTerminationMsg(entityId), systemContext.getRuleActorTerminationDelay());
- }
-
- private void onStop() {
- this.state = ComponentLifecycleState.SUSPENDED;
- stopFilters();
- stopProcessor();
- stopAction();
- }
-
- @Override
- public void onClusterEventMsg(ClusterEventMsg msg) throws Exception {
- //Do nothing
- }
-
- private void stopAction() {
- if (action != null) {
- action.stop();
- }
- }
-
- private void stopProcessor() {
- if (processor != null) {
- processor.stop();
- }
- }
-
- private void stopFilters() {
- if (filters != null) {
- filters.forEach(f -> f.stop());
- }
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMetaData.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMetaData.java
deleted file mode 100644
index df7adac396..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorMetaData.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.rule;
-
-import java.util.Comparator;
-
-import org.thingsboard.server.common.data.id.RuleId;
-
-import akka.actor.ActorRef;
-
-public class RuleActorMetaData {
-
- private final RuleId ruleId;
- private final boolean systemRule;
- private final int weight;
- private final ActorRef actorRef;
-
- public static final Comparator RULE_ACTOR_MD_COMPARATOR = new Comparator() {
-
- @Override
- public int compare(RuleActorMetaData r1, RuleActorMetaData r2) {
- if (r1.isSystemRule() && !r2.isSystemRule()) {
- return 1;
- } else if (!r1.isSystemRule() && r2.isSystemRule()) {
- return -1;
- } else {
- return Integer.compare(r2.getWeight(), r1.getWeight());
- }
- }
- };
-
- public static RuleActorMetaData systemRule(RuleId ruleId, int weight, ActorRef actorRef) {
- return new RuleActorMetaData(ruleId, true, weight, actorRef);
- }
-
- public static RuleActorMetaData tenantRule(RuleId ruleId, int weight, ActorRef actorRef) {
- return new RuleActorMetaData(ruleId, false, weight, actorRef);
- }
-
- private RuleActorMetaData(RuleId ruleId, boolean systemRule, int weight, ActorRef actorRef) {
- super();
- this.ruleId = ruleId;
- this.systemRule = systemRule;
- this.weight = weight;
- this.actorRef = actorRef;
- }
-
- public RuleId getRuleId() {
- return ruleId;
- }
-
- public boolean isSystemRule() {
- return systemRule;
- }
-
- public int getWeight() {
- return weight;
- }
-
- public ActorRef getActorRef() {
- return actorRef;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((ruleId == null) ? 0 : ruleId.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- RuleActorMetaData other = (RuleActorMetaData) obj;
- if (ruleId == null) {
- if (other.ruleId != null)
- return false;
- } else if (!ruleId.equals(other.ruleId))
- return false;
- return true;
- }
-
- @Override
- public String toString() {
- return "RuleActorMetaData [ruleId=" + ruleId + ", systemRule=" + systemRule + ", weight=" + weight + ", actorRef=" + actorRef + "]";
- }
-
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingContext.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingContext.java
deleted file mode 100644
index 179307bb05..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingContext.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.rule;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import org.thingsboard.server.actors.ActorSystemContext;
-import org.thingsboard.server.common.data.Event;
-import org.thingsboard.server.common.data.alarm.Alarm;
-import org.thingsboard.server.common.data.alarm.AlarmId;
-import org.thingsboard.server.common.data.id.*;
-import org.thingsboard.server.dao.alarm.AlarmService;
-import org.thingsboard.server.dao.event.EventService;
-import org.thingsboard.server.dao.timeseries.TimeseriesService;
-import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
-import org.thingsboard.server.extensions.api.device.DeviceMetaData;
-import org.thingsboard.server.extensions.api.rules.RuleContext;
-
-import java.util.Optional;
-import java.util.concurrent.ExecutionException;
-
-public class RuleProcessingContext implements RuleContext {
-
- private final TimeseriesService tsService;
- private final EventService eventService;
- private final AlarmService alarmService;
- private final RuleId ruleId;
- private TenantId tenantId;
- private CustomerId customerId;
- private DeviceId deviceId;
- private DeviceMetaData deviceMetaData;
-
- RuleProcessingContext(ActorSystemContext systemContext, RuleId ruleId) {
- this.tsService = systemContext.getTsService();
- this.eventService = systemContext.getEventService();
- this.alarmService = systemContext.getAlarmService();
- this.ruleId = ruleId;
- }
-
- void update(ToDeviceActorMsg toDeviceActorMsg, DeviceMetaData deviceMetaData) {
- this.tenantId = toDeviceActorMsg.getTenantId();
- this.customerId = toDeviceActorMsg.getCustomerId();
- this.deviceId = toDeviceActorMsg.getDeviceId();
- this.deviceMetaData = deviceMetaData;
- }
-
- @Override
- public RuleId getRuleId() {
- return ruleId;
- }
-
- @Override
- public DeviceMetaData getDeviceMetaData() {
- return deviceMetaData;
- }
-
- @Override
- public Event save(Event event) {
- checkEvent(event);
- return eventService.save(event);
- }
-
- @Override
- public Optional saveIfNotExists(Event event) {
- checkEvent(event);
- return eventService.saveIfNotExists(event);
- }
-
- @Override
- public Optional findEvent(String eventType, String eventUid) {
- return eventService.findEvent(tenantId, deviceId, eventType, eventUid);
- }
-
- @Override
- public Alarm createOrUpdateAlarm(Alarm alarm) {
- alarm.setTenantId(tenantId);
- return alarmService.createOrUpdateAlarm(alarm);
- }
-
- public Optional findLatestAlarm(EntityId originator, String alarmType) {
- try {
- return Optional.ofNullable(alarmService.findLatestByOriginatorAndType(tenantId, originator, alarmType).get());
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException("Failed to lookup alarm!", e);
- }
- }
-
- @Override
- public ListenableFuture clearAlarm(AlarmId alarmId, long clearTs) {
- return alarmService.clearAlarm(alarmId, clearTs);
- }
-
- private void checkEvent(Event event) {
- if (event.getTenantId() == null) {
- event.setTenantId(tenantId);
- } else if (!tenantId.equals(event.getTenantId())) {
- throw new IllegalArgumentException("Invalid Tenant id!");
- }
- if (event.getEntityId() == null) {
- event.setEntityId(deviceId);
- }
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
new file mode 100644
index 0000000000..8ffd378da7
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
@@ -0,0 +1,209 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import akka.actor.ActorRef;
+import akka.actor.Cancellable;
+import com.google.common.base.Function;
+import org.thingsboard.rule.engine.api.*;
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.common.data.id.RuleNodeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.rule.RuleNode;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.cluster.ServerAddress;
+import org.thingsboard.server.dao.alarm.AlarmService;
+import org.thingsboard.server.dao.asset.AssetService;
+import org.thingsboard.server.dao.attributes.AttributesService;
+import org.thingsboard.server.dao.customer.CustomerService;
+import org.thingsboard.server.dao.device.DeviceService;
+import org.thingsboard.server.dao.plugin.PluginService;
+import org.thingsboard.server.dao.relation.RelationService;
+import org.thingsboard.server.dao.rule.RuleChainService;
+import org.thingsboard.server.dao.timeseries.TimeseriesService;
+import org.thingsboard.server.dao.user.UserService;
+import org.thingsboard.server.service.script.NashornJsEngine;
+import scala.concurrent.duration.Duration;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Created by ashvayka on 19.03.18.
+ */
+class DefaultTbContext implements TbContext {
+
+ private static final Function super List, ? extends Void> LIST_VOID_FUNCTION = v -> null;
+ private final ActorSystemContext mainCtx;
+ private final RuleNodeCtx nodeCtx;
+
+ public DefaultTbContext(ActorSystemContext mainCtx, RuleNodeCtx nodeCtx) {
+ this.mainCtx = mainCtx;
+ this.nodeCtx = nodeCtx;
+ }
+
+ @Override
+ public void tellNext(TbMsg msg) {
+ tellNext(msg, (String) null);
+ }
+
+ @Override
+ public void tellNext(TbMsg msg, String relationType) {
+ if (nodeCtx.getSelf().isDebugMode()) {
+ mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg);
+ }
+ nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationType, msg), nodeCtx.getSelfActor());
+ }
+
+ @Override
+ public void tellSelf(TbMsg msg, long delayMs) {
+ //TODO: add persistence layer
+ scheduleMsgWithDelay(new RuleNodeToSelfMsg(msg), delayMs, nodeCtx.getSelfActor());
+ }
+
+ private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) {
+ mainCtx.getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, mainCtx.getActorSystem().dispatcher(), nodeCtx.getSelfActor());
+ }
+
+ @Override
+ public void tellOthers(TbMsg msg) {
+ throw new RuntimeException("Not Implemented!");
+ }
+
+ @Override
+ public void tellSibling(TbMsg msg, ServerAddress address) {
+ throw new RuntimeException("Not Implemented!");
+ }
+
+ @Override
+ public void spawn(TbMsg msg) {
+ throw new RuntimeException("Not Implemented!");
+ }
+
+ @Override
+ public void ack(TbMsg msg) {
+
+ }
+
+ @Override
+ public void tellError(TbMsg msg, Throwable th) {
+ if (nodeCtx.getSelf().isDebugMode()) {
+ mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, th);
+ }
+ nodeCtx.getSelfActor().tell(new RuleNodeToSelfErrorMsg(msg, th), nodeCtx.getSelfActor());
+ }
+
+ @Override
+ public void updateSelf(RuleNode self) {
+ nodeCtx.setSelf(self);
+ }
+
+ @Override
+ public RuleNodeId getSelfId() {
+ return nodeCtx.getSelf().getId();
+ }
+
+ @Override
+ public TenantId getTenantId() {
+ return nodeCtx.getTenantId();
+ }
+
+ @Override
+ public void tellNext(TbMsg msg, Set relationTypes) {
+ relationTypes.forEach(type -> tellNext(msg, type));
+ }
+
+ @Override
+ public ListeningExecutor getJsExecutor() {
+ return mainCtx.getJsExecutor();
+ }
+
+ @Override
+ public ListeningExecutor getMailExecutor() {
+ return mainCtx.getMailExecutor();
+ }
+
+ @Override
+ public ListeningExecutor getDbCallbackExecutor() {
+ return mainCtx.getDbCallbackExecutor();
+ }
+
+ @Override
+ public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) {
+ return new NashornJsEngine(script, functionName, argNames);
+ }
+
+ @Override
+ public AttributesService getAttributesService() {
+ return mainCtx.getAttributesService();
+ }
+
+ @Override
+ public CustomerService getCustomerService() {
+ return mainCtx.getCustomerService();
+ }
+
+ @Override
+ public UserService getUserService() {
+ return mainCtx.getUserService();
+ }
+
+ @Override
+ public PluginService getPluginService() {
+ return mainCtx.getPluginService();
+ }
+
+ @Override
+ public AssetService getAssetService() {
+ return mainCtx.getAssetService();
+ }
+
+ @Override
+ public DeviceService getDeviceService() {
+ return mainCtx.getDeviceService();
+ }
+
+ @Override
+ public AlarmService getAlarmService() {
+ return mainCtx.getAlarmService();
+ }
+
+ @Override
+ public RuleChainService getRuleChainService() {
+ return mainCtx.getRuleChainService();
+ }
+
+ @Override
+ public TimeseriesService getTimeseriesService() {
+ return mainCtx.getTsService();
+ }
+
+ @Override
+ public RuleEngineTelemetryService getTelemetryService() {
+ return mainCtx.getTsSubService();
+ }
+
+ @Override
+ public RelationService getRelationService() {
+ return mainCtx.getRelationService();
+ }
+
+ @Override
+ public MailService getMailService() {
+ return mainCtx.getMailService();
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java
new file mode 100644
index 0000000000..f539e32a3c
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import akka.actor.OneForOneStrategy;
+import akka.actor.SupervisorStrategy;
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.actors.service.ComponentActor;
+import org.thingsboard.server.actors.service.ContextBasedCreator;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.msg.TbActorMsg;
+import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
+import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
+import scala.concurrent.duration.Duration;
+
+public class RuleChainActor extends ComponentActor {
+
+ private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) {
+ super(systemContext, tenantId, ruleChainId);
+ setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext,
+ logger, context().parent(), context().self()));
+ }
+
+ @Override
+ protected boolean process(TbActorMsg msg) {
+ switch (msg.getMsgType()) {
+ case COMPONENT_LIFE_CYCLE_MSG:
+ onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
+ break;
+ case SERVICE_TO_RULE_ENGINE_MSG:
+ processor.onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
+ break;
+ case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG:
+ processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ public static class ActorCreator extends ContextBasedCreator {
+ private static final long serialVersionUID = 1L;
+
+ private final TenantId tenantId;
+ private final RuleChainId ruleChainId;
+
+ public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId pluginId) {
+ super(context);
+ this.tenantId = tenantId;
+ this.ruleChainId = pluginId;
+ }
+
+ @Override
+ public RuleChainActor create() throws Exception {
+ return new RuleChainActor(context, tenantId, ruleChainId);
+ }
+ }
+
+ @Override
+ protected long getErrorPersistFrequency() {
+ return systemContext.getRuleChainErrorPersistFrequency();
+ }
+
+ @Override
+ public SupervisorStrategy supervisorStrategy() {
+ return strategy;
+ }
+
+ private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> {
+ logAndPersist("Unknown Failure", ActorSystemContext.toException(t));
+ return SupervisorStrategy.resume();
+ });
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
new file mode 100644
index 0000000000..d588a63637
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActorMessageProcessor.java
@@ -0,0 +1,195 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import akka.actor.ActorContext;
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.event.LoggingAdapter;
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.actors.service.DefaultActorService;
+import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.RuleNodeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
+import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
+import org.thingsboard.server.common.data.relation.EntityRelation;
+import org.thingsboard.server.common.data.rule.RuleChain;
+import org.thingsboard.server.common.data.rule.RuleNode;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
+import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
+import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
+import org.thingsboard.server.dao.rule.RuleChainService;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author Andrew Shvayka
+ */
+public class RuleChainActorMessageProcessor extends ComponentMsgProcessor {
+
+ private final ActorRef parent;
+ private final ActorRef self;
+ private final Map nodeActors;
+ private final Map> nodeRoutes;
+ private final RuleChainService service;
+
+ private RuleNodeId firstId;
+ private RuleNodeCtx firstNode;
+
+ RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext
+ , LoggingAdapter logger, ActorRef parent, ActorRef self) {
+ super(systemContext, logger, tenantId, ruleChainId);
+ this.parent = parent;
+ this.self = self;
+ this.nodeActors = new HashMap<>();
+ this.nodeRoutes = new HashMap<>();
+ this.service = systemContext.getRuleChainService();
+ }
+
+ @Override
+ public void start(ActorContext context) throws Exception {
+ RuleChain ruleChain = service.findRuleChainById(entityId);
+ List ruleNodeList = service.getRuleChainNodes(entityId);
+ // Creating and starting the actors;
+ for (RuleNode ruleNode : ruleNodeList) {
+ ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
+ nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
+ }
+ initRoutes(ruleChain, ruleNodeList);
+ }
+
+ @Override
+ public void onUpdate(ActorContext context) throws Exception {
+ RuleChain ruleChain = service.findRuleChainById(entityId);
+ List ruleNodeList = service.getRuleChainNodes(entityId);
+
+ for (RuleNode ruleNode : ruleNodeList) {
+ RuleNodeCtx existing = nodeActors.get(ruleNode.getId());
+ if (existing == null) {
+ ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
+ nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
+ } else {
+ existing.setSelf(ruleNode);
+ existing.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self);
+ }
+ }
+
+ Set existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet());
+ List removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList());
+ removedRules.forEach(ruleNodeId -> {
+ RuleNodeCtx removed = nodeActors.remove(ruleNodeId);
+ removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self);
+ });
+
+ initRoutes(ruleChain, ruleNodeList);
+ }
+
+ @Override
+ public void stop(ActorContext context) throws Exception {
+ nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(context::stop);
+ nodeActors.clear();
+ nodeRoutes.clear();
+ context.stop(self);
+ }
+
+ @Override
+ public void onClusterEventMsg(ClusterEventMsg msg) throws Exception {
+
+ }
+
+ private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) {
+ String dispatcherName = tenantId.getId().equals(EntityId.NULL_UUID) ?
+ DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME : DefaultActorService.TENANT_RULE_DISPATCHER_NAME;
+ return context.actorOf(
+ Props.create(new RuleNodeActor.ActorCreator(systemContext, tenantId, entityId, ruleNode.getId()))
+ .withDispatcher(dispatcherName), ruleNode.getId().toString());
+ }
+
+ private void initRoutes(RuleChain ruleChain, List ruleNodeList) {
+ nodeRoutes.clear();
+ // Populating the routes map;
+ for (RuleNode ruleNode : ruleNodeList) {
+ List relations = service.getRuleNodeRelations(ruleNode.getId());
+ for (EntityRelation relation : relations) {
+ if (relation.getTo().getEntityType() == EntityType.RULE_NODE) {
+ RuleNodeCtx ruleNodeCtx = nodeActors.get(new RuleNodeId(relation.getTo().getId()));
+ if (ruleNodeCtx == null) {
+ throw new IllegalArgumentException("Rule Node [" + relation.getFrom() + "] has invalid relation to Rule node [" + relation.getTo() + "]");
+ }
+ }
+ nodeRoutes.computeIfAbsent(ruleNode.getId(), k -> new ArrayList<>())
+ .add(new RuleNodeRelation(ruleNode.getId(), relation.getTo(), relation.getType()));
+ }
+ }
+
+ firstId = ruleChain.getFirstRuleNodeId();
+ firstNode = nodeActors.get(ruleChain.getFirstRuleNodeId());
+ state = ComponentLifecycleState.ACTIVE;
+ }
+
+ void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg envelope) {
+ checkActive();
+ TbMsg tbMsg = envelope.getTbMsg();
+ //TODO: push to queue and act on ack in async way
+ pushMsgToNode(firstNode, tbMsg);
+ }
+
+ void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) {
+ checkActive();
+ RuleNodeId originator = envelope.getOriginator();
+ String targetRelationType = envelope.getRelationType();
+ List relations = nodeRoutes.get(originator);
+ if (relations == null) {
+ return;
+ }
+ boolean copy = relations.size() > 1;
+ for (RuleNodeRelation relation : relations) {
+ TbMsg msg = envelope.getMsg();
+ if (copy) {
+ msg = msg.copy();
+ }
+ if (targetRelationType == null || targetRelationType.equalsIgnoreCase(relation.getType())) {
+ switch (relation.getOut().getEntityType()) {
+ case RULE_NODE:
+ RuleNodeId targetRuleNodeId = new RuleNodeId(relation.getOut().getId());
+ RuleNodeCtx targetRuleNode = nodeActors.get(targetRuleNodeId);
+ pushMsgToNode(targetRuleNode, msg);
+ break;
+ case RULE_CHAIN:
+// TODO: implement
+ break;
+ }
+ }
+ }
+ }
+
+ private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg) {
+ if (nodeCtx != null) {
+ nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg), self);
+ }
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java
new file mode 100644
index 0000000000..940bd5b0fb
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainManagerActor.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import akka.actor.ActorRef;
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.actors.service.ContextAwareActor;
+import org.thingsboard.server.actors.shared.plugin.PluginManager;
+import org.thingsboard.server.actors.shared.rulechain.RuleChainManager;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.PluginId;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.dao.rule.RuleChainService;
+
+/**
+ * Created by ashvayka on 15.03.18.
+ */
+public abstract class RuleChainManagerActor extends ContextAwareActor {
+
+ protected final RuleChainManager ruleChainManager;
+ protected final PluginManager pluginManager;
+ protected final RuleChainService ruleChainService;
+
+ public RuleChainManagerActor(ActorSystemContext systemContext, RuleChainManager ruleChainManager, PluginManager pluginManager) {
+ super(systemContext);
+ this.ruleChainManager = ruleChainManager;
+ this.pluginManager = pluginManager;
+ this.ruleChainService = systemContext.getRuleChainService();
+ }
+
+ protected void initRuleChains() {
+ pluginManager.init(this.context());
+ ruleChainManager.init(this.context());
+ }
+
+ protected ActorRef getEntityActorRef(EntityId entityId) {
+ ActorRef target = null;
+ switch (entityId.getEntityType()) {
+ case PLUGIN:
+ target = pluginManager.getOrCreateActor(this.context(), (PluginId) entityId);
+ break;
+ case RULE_CHAIN:
+ target = ruleChainManager.getOrCreateActor(this.context(), (RuleChainId) entityId);
+ break;
+ }
+ return target;
+ }
+}
diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/RuleMsg.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleNodeMsg.java
similarity index 54%
rename from common/message/src/main/java/org/thingsboard/server/common/msg/RuleMsg.java
rename to application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleNodeMsg.java
index ee352ad722..e7d866c1eb 100644
--- a/common/message/src/main/java/org/thingsboard/server/common/msg/RuleMsg.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainToRuleNodeMsg.java
@@ -13,26 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.thingsboard.server.common.msg;
+package org.thingsboard.server.actors.ruleChain;
-import org.thingsboard.server.common.data.rule.Scope;
-import org.thingsboard.server.common.data.rule.RuleType;
-import org.thingsboard.server.common.msg.aware.RuleAwareMsg;
+import lombok.Data;
+import org.thingsboard.rule.engine.api.TbContext;
+import org.thingsboard.server.common.msg.MsgType;
+import org.thingsboard.server.common.msg.TbActorMsg;
+import org.thingsboard.server.common.msg.TbMsg;
/**
- * Message that is used to deliver some data to the rule instance.
- * For example: aggregated statistics or command decoded from http request.
- *
- * @author ashvayka
- *
- * @param - payload
+ * Created by ashvayka on 19.03.18.
*/
-public interface RuleMsg extends RuleAwareMsg {
+@Data
+final class RuleChainToRuleNodeMsg implements TbActorMsg {
+
+ private final TbContext ctx;
+ private final TbMsg msg;
- Scope getRuleLevel();
-
- RuleType getRuleType();
-
- V getPayload();
-
+ @Override
+ public MsgType getMsgType() {
+ return MsgType.RULE_CHAIN_TO_RULE_MSG;
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java
new file mode 100644
index 0000000000..f7ca0d8cc7
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActor.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.actors.service.ComponentActor;
+import org.thingsboard.server.actors.service.ContextBasedCreator;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.RuleNodeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.msg.TbActorMsg;
+import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
+
+public class RuleNodeActor extends ComponentActor {
+
+ private final RuleChainId ruleChainId;
+
+ private RuleNodeActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
+ super(systemContext, tenantId, ruleNodeId);
+ this.ruleChainId = ruleChainId;
+ setProcessor(new RuleNodeActorMessageProcessor(tenantId, ruleChainId, ruleNodeId, systemContext,
+ logger, context().parent(), context().self()));
+ }
+
+ @Override
+ protected boolean process(TbActorMsg msg) {
+ switch (msg.getMsgType()) {
+ case COMPONENT_LIFE_CYCLE_MSG:
+ onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
+ break;
+ case RULE_CHAIN_TO_RULE_MSG:
+ onRuleChainToRuleNodeMsg((RuleChainToRuleNodeMsg) msg);
+ break;
+ case RULE_TO_SELF_ERROR_MSG:
+ onRuleNodeToSelfErrorMsg((RuleNodeToSelfErrorMsg) msg);
+ break;
+ case RULE_TO_SELF_MSG:
+ onRuleNodeToSelfMsg((RuleNodeToSelfMsg) msg);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ private void onRuleNodeToSelfMsg(RuleNodeToSelfMsg msg) {
+ logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg());
+ try {
+ processor.onRuleToSelfMsg(msg);
+ increaseMessagesProcessedCount();
+ } catch (Exception e) {
+ logAndPersist("onRuleMsg", e);
+ }
+ }
+
+ private void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) {
+ logger.debug("[{}] Going to process rule msg: {}", id, msg.getMsg());
+ try {
+ processor.onRuleChainToRuleNodeMsg(msg);
+ increaseMessagesProcessedCount();
+ } catch (Exception e) {
+ logAndPersist("onRuleMsg", e);
+ }
+ }
+
+ private void onRuleNodeToSelfErrorMsg(RuleNodeToSelfErrorMsg msg) {
+ logAndPersist("onRuleMsg", ActorSystemContext.toException(msg.getError()));
+ }
+
+ public static class ActorCreator extends ContextBasedCreator {
+ private static final long serialVersionUID = 1L;
+
+ private final TenantId tenantId;
+ private final RuleChainId ruleChainId;
+ private final RuleNodeId ruleNodeId;
+
+ public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
+ super(context);
+ this.tenantId = tenantId;
+ this.ruleChainId = ruleChainId;
+ this.ruleNodeId = ruleNodeId;
+
+ }
+
+ @Override
+ public RuleNodeActor create() throws Exception {
+ return new RuleNodeActor(context, tenantId, ruleChainId, ruleNodeId);
+ }
+ }
+
+ @Override
+ protected long getErrorPersistFrequency() {
+ return systemContext.getRuleNodeErrorPersistFrequency();
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
new file mode 100644
index 0000000000..ea857dbbb4
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import akka.actor.ActorContext;
+import akka.actor.ActorRef;
+import akka.event.LoggingAdapter;
+import org.thingsboard.rule.engine.api.TbContext;
+import org.thingsboard.rule.engine.api.TbNode;
+import org.thingsboard.rule.engine.api.TbNodeConfiguration;
+import org.thingsboard.rule.engine.api.TbNodeException;
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.RuleNodeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
+import org.thingsboard.server.common.data.rule.RuleNode;
+import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
+import org.thingsboard.server.dao.rule.RuleChainService;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * @author Andrew Shvayka
+ */
+public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor {
+
+ private final ActorRef parent;
+ private final ActorRef self;
+ private final RuleChainService service;
+ private RuleNode ruleNode;
+ private TbNode tbNode;
+ private TbContext defaultCtx;
+
+ RuleNodeActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, RuleNodeId ruleNodeId, ActorSystemContext systemContext
+ , LoggingAdapter logger, ActorRef parent, ActorRef self) {
+ super(systemContext, logger, tenantId, ruleNodeId);
+ this.parent = parent;
+ this.self = self;
+ this.service = systemContext.getRuleChainService();
+ this.ruleNode = systemContext.getRuleChainService().findRuleNodeById(entityId);
+ this.defaultCtx = new DefaultTbContext(systemContext, new RuleNodeCtx(tenantId, parent, self, ruleNode));
+ }
+
+ @Override
+ public void start(ActorContext context) throws Exception {
+ tbNode = initComponent(ruleNode);
+ state = ComponentLifecycleState.ACTIVE;
+ }
+
+ @Override
+ public void onUpdate(ActorContext context) throws Exception {
+ RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(entityId);
+ boolean restartRequired = !(ruleNode.getType().equals(newRuleNode.getType())
+ && ruleNode.getConfiguration().equals(newRuleNode.getConfiguration()));
+ this.ruleNode = newRuleNode;
+ this.defaultCtx.updateSelf(newRuleNode);
+ if (restartRequired) {
+ if (tbNode != null) {
+ tbNode.destroy();
+ }
+ start(context);
+ }
+ }
+
+ @Override
+ public void stop(ActorContext context) throws Exception {
+ if (tbNode != null) {
+ tbNode.destroy();
+ }
+ context.stop(self);
+ }
+
+ @Override
+ public void onClusterEventMsg(ClusterEventMsg msg) throws Exception {
+
+ }
+
+ public void onRuleToSelfMsg(RuleNodeToSelfMsg msg) throws Exception {
+ checkActive();
+ if (ruleNode.isDebugMode()) {
+ systemContext.persistDebugInput(tenantId, entityId, msg.getMsg());
+ }
+ tbNode.onMsg(defaultCtx, msg.getMsg());
+ }
+
+ void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) throws Exception {
+ checkActive();
+ if (ruleNode.isDebugMode()) {
+ systemContext.persistDebugInput(tenantId, entityId, msg.getMsg());
+ }
+ tbNode.onMsg(msg.getCtx(), msg.getMsg());
+ }
+
+ private TbNode initComponent(RuleNode ruleNode) throws Exception {
+ Class> componentClazz = Class.forName(ruleNode.getType());
+ TbNode tbNode = (TbNode) (componentClazz.newInstance());
+ tbNode.init(defaultCtx, new TbNodeConfiguration(ruleNode.getConfiguration()));
+ return tbNode;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeCtx.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeCtx.java
new file mode 100644
index 0000000000..10fcc8b606
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeCtx.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import akka.actor.ActorRef;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.rule.RuleNode;
+
+/**
+ * Created by ashvayka on 19.03.18.
+ */
+@Data
+@AllArgsConstructor
+final class RuleNodeCtx {
+ private final TenantId tenantId;
+ private final ActorRef chainActor;
+ private final ActorRef selfActor;
+ private RuleNode self;
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingMsg.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeRelation.java
similarity index 67%
rename from application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingMsg.java
rename to application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeRelation.java
index 291a9a7cef..7861e5473c 100644
--- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingMsg.java
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeRelation.java
@@ -13,19 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.thingsboard.server.actors.rule;
+package org.thingsboard.server.actors.ruleChain;
-public class RuleProcessingMsg {
+import lombok.Data;
+import org.thingsboard.server.common.data.id.EntityId;
- private final ChainProcessingContext ctx;
+/**
+ * Created by ashvayka on 19.03.18.
+ */
- public RuleProcessingMsg(ChainProcessingContext ctx) {
- super();
- this.ctx = ctx;
- }
+@Data
+final class RuleNodeRelation {
- public ChainProcessingContext getCtx() {
- return ctx;
- }
+ private final EntityId in;
+ private final EntityId out;
+ private final String type;
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToRuleChainTellNextMsg.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToRuleChainTellNextMsg.java
new file mode 100644
index 0000000000..054284dc59
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToRuleChainTellNextMsg.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import lombok.Data;
+import org.thingsboard.server.common.data.id.RuleNodeId;
+import org.thingsboard.server.common.msg.MsgType;
+import org.thingsboard.server.common.msg.TbActorMsg;
+import org.thingsboard.server.common.msg.TbMsg;
+
+/**
+ * Created by ashvayka on 19.03.18.
+ */
+@Data
+final class RuleNodeToRuleChainTellNextMsg implements TbActorMsg {
+
+ private final RuleNodeId originator;
+ private final String relationType;
+ private final TbMsg msg;
+
+ @Override
+ public MsgType getMsgType() {
+ return MsgType.RULE_TO_RULE_CHAIN_TELL_NEXT_MSG;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java
new file mode 100644
index 0000000000..e6248f199f
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import lombok.Data;
+import org.thingsboard.server.common.msg.MsgType;
+import org.thingsboard.server.common.msg.TbActorMsg;
+import org.thingsboard.server.common.msg.TbMsg;
+
+/**
+ * Created by ashvayka on 19.03.18.
+ */
+@Data
+final class RuleNodeToSelfErrorMsg implements TbActorMsg {
+
+ private final TbMsg msg;
+ private final Throwable error;
+
+ @Override
+ public MsgType getMsgType() {
+ return MsgType.RULE_TO_SELF_ERROR_MSG;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfMsg.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfMsg.java
new file mode 100644
index 0000000000..5c5af42207
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfMsg.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.ruleChain;
+
+import lombok.Data;
+import org.thingsboard.server.common.data.id.RuleNodeId;
+import org.thingsboard.server.common.msg.MsgType;
+import org.thingsboard.server.common.msg.TbActorMsg;
+import org.thingsboard.server.common.msg.TbMsg;
+
+/**
+ * Created by ashvayka on 19.03.18.
+ */
+@Data
+final class RuleNodeToSelfMsg implements TbActorMsg {
+
+ private final TbMsg msg;
+
+ @Override
+ public MsgType getMsgType() {
+ return MsgType.RULE_TO_SELF_MSG;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/service/ActorService.java b/application/src/main/java/org/thingsboard/server/actors/service/ActorService.java
index baae376c64..0be0385365 100644
--- a/application/src/main/java/org/thingsboard/server/actors/service/ActorService.java
+++ b/application/src/main/java/org/thingsboard/server/actors/service/ActorService.java
@@ -15,20 +15,19 @@
*/
package org.thingsboard.server.actors.service;
-import org.thingsboard.server.common.data.id.DeviceId;
-import org.thingsboard.server.common.data.id.PluginId;
-import org.thingsboard.server.common.data.id.RuleId;
-import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.common.transport.SessionMsgProcessor;
import org.thingsboard.server.service.cluster.discovery.DiscoveryServiceListener;
import org.thingsboard.server.service.cluster.rpc.RpcMsgListener;
public interface ActorService extends SessionMsgProcessor, WebSocketMsgProcessor, RestMsgProcessor, RpcMsgListener, DiscoveryServiceListener {
- void onPluginStateChange(TenantId tenantId, PluginId pluginId, ComponentLifecycleEvent state);
+ void onEntityStateChange(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state);
- void onRuleStateChange(TenantId tenantId, RuleId ruleId, ComponentLifecycleEvent state);
+ void onMsg(ServiceToRuleEngineMsg msg);
void onCredentialsUpdate(TenantId tenantId, DeviceId deviceId);
diff --git a/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java b/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java
index 76b9be96b3..6aa68d3c5b 100644
--- a/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java
@@ -54,7 +54,7 @@ public abstract class ComponentActor(INITIAL_SESSION_MAP_SIZE);
}
+ @Override
+ protected boolean process(TbActorMsg msg) {
+ //TODO Move everything here, to work with TbActorMsg
+ return false;
+ }
+
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof SessionCtrlMsg) {
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java b/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java
index 73b221ffc5..e1313d20ef 100644
--- a/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java
@@ -102,9 +102,6 @@ public abstract class AbstractContextAwareMsgProcessor {
case FILTER:
configurationClazz = ((Filter) componentClazz.getAnnotation(Filter.class)).configuration();
break;
- case PROCESSOR:
- configurationClazz = ((Processor) componentClazz.getAnnotation(Processor.class)).configuration();
- break;
case ACTION:
configurationClazz = ((Action) componentClazz.getAnnotation(Action.class)).configuration();
break;
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java b/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java
index 18d32d9476..e25d3a7af9 100644
--- a/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java
@@ -20,12 +20,14 @@ import akka.event.LoggingAdapter;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.stats.StatsPersistTick;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
public abstract class ComponentMsgProcessor extends AbstractContextAwareMsgProcessor {
protected final TenantId tenantId;
protected final T entityId;
+ protected ComponentLifecycleState state;
protected ComponentMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, T id) {
super(systemContext, logger);
@@ -33,23 +35,44 @@ public abstract class ComponentMsgProcessor extends AbstractContextAwareMsgPr
this.entityId = id;
}
- public abstract void start() throws Exception;
+ public abstract void start(ActorContext context) throws Exception;
- public abstract void stop() throws Exception;
+ public abstract void stop(ActorContext context) throws Exception;
- public abstract void onCreated(ActorContext context) throws Exception;
+ public abstract void onClusterEventMsg(ClusterEventMsg msg) throws Exception;
- public abstract void onUpdate(ActorContext context) throws Exception;
+ public void onCreated(ActorContext context) throws Exception {
+ start(context);
+ }
- public abstract void onActivate(ActorContext context) throws Exception;
+ public void onUpdate(ActorContext context) throws Exception {
+ restart(context);
+ }
- public abstract void onSuspend(ActorContext context) throws Exception;
+ public void onActivate(ActorContext context) throws Exception {
+ restart(context);
+ }
- public abstract void onStop(ActorContext context) throws Exception;
+ public void onSuspend(ActorContext context) throws Exception {
+ stop(context);
+ }
- public abstract void onClusterEventMsg(ClusterEventMsg msg) throws Exception;
+ public void onStop(ActorContext context) throws Exception {
+ stop(context);
+ }
+
+ private void restart(ActorContext context) throws Exception {
+ stop(context);
+ start(context);
+ }
public void scheduleStatsPersistTick(ActorContext context, long statsPersistFrequency) {
schedulePeriodicMsgWithDelay(context, new StatsPersistTick(), statsPersistFrequency, statsPersistFrequency);
}
+
+ protected void checkActive() {
+ if (state != ComponentLifecycleState.ACTIVE) {
+ throw new IllegalStateException("Rule chain is not active!");
+ }
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java
new file mode 100644
index 0000000000..d4a1f34006
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.shared;
+
+import akka.actor.ActorContext;
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.actor.UntypedActor;
+import akka.japi.Creator;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.actors.service.ContextAwareActor;
+import org.thingsboard.server.common.data.SearchTextBased;
+import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.UUIDBased;
+import org.thingsboard.server.common.data.page.PageDataIterable;
+import org.thingsboard.server.common.data.plugin.PluginMetaData;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by ashvayka on 15.03.18.
+ */
+@Slf4j
+public abstract class EntityActorsManager> {
+
+ protected final ActorSystemContext systemContext;
+ protected final Map actors;
+
+ public EntityActorsManager(ActorSystemContext systemContext) {
+ this.systemContext = systemContext;
+ this.actors = new HashMap<>();
+ }
+
+ protected abstract TenantId getTenantId();
+
+ protected abstract String getDispatcherName();
+
+ protected abstract Creator creator(T entityId);
+
+ protected abstract PageDataIterable.FetchFunction getFetchEntitiesFunction();
+
+ public void init(ActorContext context) {
+ for (M entity : new PageDataIterable<>(getFetchEntitiesFunction(), ContextAwareActor.ENTITY_PACK_LIMIT)) {
+ T entityId = (T) entity.getId();
+ log.debug("[{}|{}] Creating entity actor", entityId.getEntityType(), entityId.getId());
+ //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.
+ ActorRef actorRef = getOrCreateActor(context, entityId);
+ visit(entity, actorRef);
+ log.debug("[{}|{}] Entity actor created.", entityId.getEntityType(), entityId.getId());
+ }
+ }
+
+ protected void visit(M entity, ActorRef actorRef) {}
+
+ public ActorRef getOrCreateActor(ActorContext context, T entityId) {
+ return actors.computeIfAbsent(entityId, eId ->
+ context.actorOf(Props.create(creator(eId))
+ .withDispatcher(getDispatcherName()), eId.toString()));
+ }
+
+ public void broadcast(Object msg) {
+ actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
+ }
+
+ public void remove(T id) {
+ actors.remove(id);
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/plugin/PluginManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/plugin/PluginManager.java
index 4f5871f585..3345e5fff5 100644
--- a/application/src/main/java/org/thingsboard/server/actors/shared/plugin/PluginManager.java
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/plugin/PluginManager.java
@@ -15,63 +15,28 @@
*/
package org.thingsboard.server.actors.shared.plugin;
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import akka.actor.Props;
+import akka.japi.Creator;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.plugin.PluginActor;
-import org.thingsboard.server.actors.service.ContextAwareActor;
+import org.thingsboard.server.actors.shared.EntityActorsManager;
import org.thingsboard.server.common.data.id.PluginId;
-import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.common.data.page.PageDataIterable;
-import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.dao.plugin.PluginService;
-import java.util.HashMap;
-import java.util.Map;
-
@Slf4j
-public abstract class PluginManager {
+public abstract class PluginManager extends EntityActorsManager {
- protected final ActorSystemContext systemContext;
protected final PluginService pluginService;
- protected final Map pluginActors;
public PluginManager(ActorSystemContext systemContext) {
- this.systemContext = systemContext;
+ super(systemContext);
this.pluginService = systemContext.getPluginService();
- this.pluginActors = new HashMap<>();
}
- public void init(ActorContext context) {
- PageDataIterable pluginIterator = new PageDataIterable<>(getFetchPluginsFunction(),
- ContextAwareActor.ENTITY_PACK_LIMIT);
- for (PluginMetaData plugin : pluginIterator) {
- log.debug("[{}] Creating plugin actor", plugin.getId());
- getOrCreatePluginActor(context, plugin.getId());
- log.debug("Plugin actor created.");
- }
+ @Override
+ public Creator creator(PluginId entityId){
+ return new PluginActor.ActorCreator(systemContext, getTenantId(), entityId);
}
- abstract FetchFunction getFetchPluginsFunction();
-
- abstract TenantId getTenantId();
-
- abstract String getDispatcherName();
-
- public ActorRef getOrCreatePluginActor(ActorContext context, PluginId pluginId) {
- return pluginActors.computeIfAbsent(pluginId, pId ->
- context.actorOf(Props.create(new PluginActor.ActorCreator(systemContext, getTenantId(), pId))
- .withDispatcher(getDispatcherName()), pId.toString()));
- }
-
- public void broadcast(Object msg) {
- pluginActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
- }
-
- public void remove(PluginId id) {
- pluginActors.remove(id);
- }
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/plugin/SystemPluginManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/plugin/SystemPluginManager.java
index 0888e23f25..88c52a6043 100644
--- a/application/src/main/java/org/thingsboard/server/actors/shared/plugin/SystemPluginManager.java
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/plugin/SystemPluginManager.java
@@ -29,12 +29,12 @@ public class SystemPluginManager extends PluginManager {
}
@Override
- FetchFunction getFetchPluginsFunction() {
+ protected FetchFunction getFetchEntitiesFunction() {
return pluginService::findSystemPlugins;
}
@Override
- TenantId getTenantId() {
+ protected TenantId getTenantId() {
return BasePluginService.SYSTEM_TENANT;
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/plugin/TenantPluginManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/plugin/TenantPluginManager.java
index 14ea2aa7f8..09115f0f7d 100644
--- a/application/src/main/java/org/thingsboard/server/actors/shared/plugin/TenantPluginManager.java
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/plugin/TenantPluginManager.java
@@ -19,6 +19,7 @@ import akka.actor.ActorContext;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
@@ -39,12 +40,12 @@ public class TenantPluginManager extends PluginManager {
}
@Override
- FetchFunction getFetchPluginsFunction() {
+ protected FetchFunction getFetchEntitiesFunction() {
return link -> pluginService.findTenantPlugins(tenantId, link);
}
@Override
- TenantId getTenantId() {
+ protected TenantId getTenantId() {
return tenantId;
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/rule/RuleManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/rule/RuleManager.java
deleted file mode 100644
index 95d762afdf..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/shared/rule/RuleManager.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.shared.rule;
-
-import akka.actor.ActorContext;
-import akka.actor.ActorRef;
-import akka.actor.Props;
-import lombok.extern.slf4j.Slf4j;
-import org.thingsboard.server.actors.ActorSystemContext;
-import org.thingsboard.server.actors.rule.RuleActor;
-import org.thingsboard.server.actors.rule.RuleActorChain;
-import org.thingsboard.server.actors.rule.RuleActorMetaData;
-import org.thingsboard.server.actors.rule.SimpleRuleActorChain;
-import org.thingsboard.server.actors.service.ContextAwareActor;
-import org.thingsboard.server.common.data.id.RuleId;
-import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.common.data.page.PageDataIterable;
-import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
-import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
-import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
-import org.thingsboard.server.common.data.rule.RuleMetaData;
-import org.thingsboard.server.dao.rule.RuleService;
-
-import java.util.*;
-
-@Slf4j
-public abstract class RuleManager {
-
- protected final ActorSystemContext systemContext;
- protected final RuleService ruleService;
- protected final Map ruleActors;
- protected final TenantId tenantId;
-
- private Map ruleMap;
- private RuleActorChain ruleChain;
-
- public RuleManager(ActorSystemContext systemContext, TenantId tenantId) {
- this.systemContext = systemContext;
- this.ruleService = systemContext.getRuleService();
- this.ruleActors = new HashMap<>();
- this.tenantId = tenantId;
- }
-
- public void init(ActorContext context) {
- doInit(context);
- }
-
- private void doInit(ActorContext context) {
- PageDataIterable ruleIterator = new PageDataIterable<>(getFetchRulesFunction(),
- ContextAwareActor.ENTITY_PACK_LIMIT);
- ruleMap = new HashMap<>();
-
- for (RuleMetaData rule : ruleIterator) {
- log.debug("[{}] Creating rule actor {}", rule.getId(), rule);
- ActorRef ref = getOrCreateRuleActor(context, rule.getId());
- ruleMap.put(rule, RuleActorMetaData.systemRule(rule.getId(), rule.getWeight(), ref));
- log.debug("[{}] Rule actor created.", rule.getId());
- }
-
- refreshRuleChain();
- }
-
- public Optional update(ActorContext context, RuleId ruleId, ComponentLifecycleEvent event) {
- if (ruleMap == null) {
- doInit(context);
- }
- RuleMetaData rule;
- if (event != ComponentLifecycleEvent.DELETED) {
- rule = systemContext.getRuleService().findRuleById(ruleId);
- } else {
- rule = ruleMap.keySet().stream()
- .filter(r -> r.getId().equals(ruleId))
- .peek(r -> r.setState(ComponentLifecycleState.SUSPENDED))
- .findFirst()
- .orElse(null);
- if (rule != null) {
- ruleMap.remove(rule);
- ruleActors.remove(ruleId);
- }
- }
- if (rule != null) {
- RuleActorMetaData actorMd = ruleMap.get(rule);
- if (actorMd == null) {
- ActorRef ref = getOrCreateRuleActor(context, rule.getId());
- actorMd = RuleActorMetaData.systemRule(rule.getId(), rule.getWeight(), ref);
- ruleMap.put(rule, actorMd);
- }
- refreshRuleChain();
- return Optional.of(actorMd.getActorRef());
- } else {
- log.warn("[{}] Can't process unknown rule!", ruleId);
- return Optional.empty();
- }
- }
-
- abstract FetchFunction getFetchRulesFunction();
-
- abstract String getDispatcherName();
-
- public ActorRef getOrCreateRuleActor(ActorContext context, RuleId ruleId) {
- return ruleActors.computeIfAbsent(ruleId, rId ->
- context.actorOf(Props.create(new RuleActor.ActorCreator(systemContext, tenantId, rId))
- .withDispatcher(getDispatcherName()), rId.toString()));
- }
-
- public RuleActorChain getRuleChain(ActorContext context) {
- if (ruleChain == null) {
- doInit(context);
- }
- return ruleChain;
- }
-
- private void refreshRuleChain() {
- Set activeRuleSet = new HashSet<>();
- for (Map.Entry rule : ruleMap.entrySet()) {
- if (rule.getKey().getState() == ComponentLifecycleState.ACTIVE) {
- activeRuleSet.add(rule.getValue());
- }
- }
- ruleChain = new SimpleRuleActorChain(activeRuleSet);
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/RuleChainManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/RuleChainManager.java
new file mode 100644
index 0000000000..ff0c52ef45
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/RuleChainManager.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors.shared.rulechain;
+
+import akka.actor.ActorRef;
+import akka.japi.Creator;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.actors.ActorSystemContext;
+import org.thingsboard.server.actors.ruleChain.RuleChainActor;
+import org.thingsboard.server.actors.shared.EntityActorsManager;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.rule.RuleChain;
+import org.thingsboard.server.dao.rule.RuleChainService;
+
+/**
+ * Created by ashvayka on 15.03.18.
+ */
+@Slf4j
+public abstract class RuleChainManager extends EntityActorsManager {
+
+ protected final RuleChainService service;
+ @Getter
+ protected RuleChain rootChain;
+ @Getter
+ protected ActorRef rootChainActor;
+
+ public RuleChainManager(ActorSystemContext systemContext) {
+ super(systemContext);
+ this.service = systemContext.getRuleChainService();
+ }
+
+ @Override
+ public Creator creator(RuleChainId entityId) {
+ return new RuleChainActor.ActorCreator(systemContext, getTenantId(), entityId);
+ }
+
+ @Override
+ protected void visit(RuleChain entity, ActorRef actorRef) {
+ if (entity.isRoot()) {
+ rootChain = entity;
+ rootChainActor = actorRef;
+ }
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/rule/SystemRuleManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java
similarity index 57%
rename from application/src/main/java/org/thingsboard/server/actors/shared/rule/SystemRuleManager.java
rename to application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java
index d10731caed..a8bb069685 100644
--- a/application/src/main/java/org/thingsboard/server/actors/shared/rule/SystemRuleManager.java
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java
@@ -13,28 +13,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.thingsboard.server.actors.shared.rule;
+package org.thingsboard.server.actors.shared.rulechain;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.service.DefaultActorService;
+import org.thingsboard.server.actors.shared.plugin.PluginManager;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
-import org.thingsboard.server.common.data.rule.RuleMetaData;
-import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.common.data.plugin.PluginMetaData;
+import org.thingsboard.server.common.data.rule.RuleChain;
+import org.thingsboard.server.dao.plugin.BasePluginService;
-public class SystemRuleManager extends RuleManager {
+public class SystemRuleChainManager extends RuleChainManager {
- public SystemRuleManager(ActorSystemContext systemContext) {
- super(systemContext, new TenantId(ModelConstants.NULL_UUID));
+ public SystemRuleChainManager(ActorSystemContext systemContext) {
+ super(systemContext);
}
@Override
- FetchFunction getFetchRulesFunction() {
- return ruleService::findSystemRules;
+ protected FetchFunction getFetchEntitiesFunction() {
+ return service::findSystemRuleChains;
}
@Override
- String getDispatcherName() {
+ protected TenantId getTenantId() {
+ return BasePluginService.SYSTEM_TENANT;
+ }
+
+ @Override
+ protected String getDispatcherName() {
return DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME;
}
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/rule/TenantRuleManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java
similarity index 65%
rename from application/src/main/java/org/thingsboard/server/actors/shared/rule/TenantRuleManager.java
rename to application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java
index e4d023ca90..731d8d8e6c 100644
--- a/application/src/main/java/org/thingsboard/server/actors/shared/rule/TenantRuleManager.java
+++ b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java
@@ -13,19 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.thingsboard.server.actors.shared.rule;
+package org.thingsboard.server.actors.shared.rulechain;
import akka.actor.ActorContext;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
-import org.thingsboard.server.common.data.rule.RuleMetaData;
+import org.thingsboard.server.common.data.rule.RuleChain;
-public class TenantRuleManager extends RuleManager {
-
- public TenantRuleManager(ActorSystemContext systemContext, TenantId tenantId) {
- super(systemContext, tenantId);
+public class TenantRuleChainManager extends RuleChainManager {
+
+ private final TenantId tenantId;
+
+ public TenantRuleChainManager(ActorSystemContext systemContext, TenantId tenantId) {
+ super(systemContext);
+ this.tenantId = tenantId;
}
@Override
@@ -36,13 +39,17 @@ public class TenantRuleManager extends RuleManager {
}
@Override
- FetchFunction getFetchRulesFunction() {
- return link -> ruleService.findTenantRules(tenantId, link);
+ protected TenantId getTenantId() {
+ return tenantId;
}
@Override
- String getDispatcherName() {
+ protected String getDispatcherName() {
return DefaultActorService.TENANT_RULE_DISPATCHER_NAME;
}
+ @Override
+ protected FetchFunction getFetchEntitiesFunction() {
+ return link -> service.findTenantRuleChains(tenantId, link);
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java b/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java
index ccc31cca29..8623370896 100644
--- a/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java
@@ -24,6 +24,7 @@ import org.thingsboard.server.actors.service.ContextAwareActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Event;
+import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress;
public class StatsActor extends ContextAwareActor {
@@ -35,6 +36,12 @@ public class StatsActor extends ContextAwareActor {
super(context);
}
+ @Override
+ protected boolean process(TbActorMsg msg) {
+ //TODO Move everything here, to work with TbActorMsg\
+ return false;
+ }
+
@Override
public void onReceive(Object msg) throws Exception {
logger.debug("Received message: {}", msg);
diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/RuleChainDeviceMsg.java b/application/src/main/java/org/thingsboard/server/actors/tenant/RuleChainDeviceMsg.java
deleted file mode 100644
index a84e0b5fd4..0000000000
--- a/application/src/main/java/org/thingsboard/server/actors/tenant/RuleChainDeviceMsg.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright © 2016-2018 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.actors.tenant;
-
-import org.thingsboard.server.actors.rule.RuleActorChain;
-import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
-
-public class RuleChainDeviceMsg {
-
- private final ToDeviceActorMsg toDeviceActorMsg;
- private final RuleActorChain ruleChain;
-
- public RuleChainDeviceMsg(ToDeviceActorMsg toDeviceActorMsg, RuleActorChain ruleChain) {
- super();
- this.toDeviceActorMsg = toDeviceActorMsg;
- this.ruleChain = ruleChain;
- }
-
- public ToDeviceActorMsg getToDeviceActorMsg() {
- return toDeviceActorMsg;
- }
-
- public RuleActorChain getRuleChain() {
- return ruleChain;
- }
-
-}
diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
index b923fe15a3..d53c054414 100644
--- a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
@@ -15,52 +15,38 @@
*/
package org.thingsboard.server.actors.tenant;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.device.DeviceActor;
import org.thingsboard.server.actors.plugin.PluginTerminationMsg;
-import org.thingsboard.server.actors.rule.ComplexRuleActorChain;
-import org.thingsboard.server.actors.rule.RuleActorChain;
-import org.thingsboard.server.actors.service.ContextAwareActor;
+import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.actors.service.DefaultActorService;
-import org.thingsboard.server.actors.shared.plugin.PluginManager;
import org.thingsboard.server.actors.shared.plugin.TenantPluginManager;
-import org.thingsboard.server.actors.shared.rule.RuleManager;
-import org.thingsboard.server.actors.shared.rule.TenantRuleManager;
+import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager;
import org.thingsboard.server.common.data.id.DeviceId;
-import org.thingsboard.server.common.data.id.PluginId;
-import org.thingsboard.server.common.data.id.RuleId;
import org.thingsboard.server.common.data.id.TenantId;
-import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
+import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.device.ToDeviceActorMsg;
-
-import akka.actor.ActorRef;
-import akka.actor.Props;
-import akka.event.Logging;
-import akka.event.LoggingAdapter;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
+import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.extensions.api.device.ToDeviceActorNotificationMsg;
import org.thingsboard.server.extensions.api.plugins.msg.ToPluginActorMsg;
-import org.thingsboard.server.extensions.api.rules.ToRuleActorMsg;
-public class TenantActor extends ContextAwareActor {
+import java.util.HashMap;
+import java.util.Map;
- private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this);
+public class TenantActor extends RuleChainManagerActor {
private final TenantId tenantId;
- private final RuleManager ruleManager;
- private final PluginManager pluginManager;
private final Map deviceActors;
private TenantActor(ActorSystemContext systemContext, TenantId tenantId) {
- super(systemContext);
+ super(systemContext, new TenantRuleChainManager(systemContext, tenantId), new TenantPluginManager(systemContext, tenantId));
this.tenantId = tenantId;
- this.ruleManager = new TenantRuleManager(systemContext, tenantId);
- this.pluginManager = new TenantPluginManager(systemContext, tenantId);
this.deviceActors = new HashMap<>();
}
@@ -68,8 +54,7 @@ public class TenantActor extends ContextAwareActor {
public void preStart() {
logger.info("[{}] Starting tenant actor.", tenantId);
try {
- ruleManager.init(this.context());
- pluginManager.init(this.context());
+ initRuleChains();
logger.info("[{}] Tenant actor started.", tenantId);
} catch (Exception e) {
logger.error(e, "[{}] Unknown failure", tenantId);
@@ -77,29 +62,45 @@ public class TenantActor extends ContextAwareActor {
}
@Override
- public void onReceive(Object msg) throws Exception {
- logger.debug("[{}] Received message: {}", tenantId, msg);
- if (msg instanceof RuleChainDeviceMsg) {
- process((RuleChainDeviceMsg) msg);
- } else if (msg instanceof ToDeviceActorMsg) {
- onToDeviceActorMsg((ToDeviceActorMsg) msg);
- } else if (msg instanceof ToPluginActorMsg) {
- onToPluginMsg((ToPluginActorMsg) msg);
- } else if (msg instanceof ToRuleActorMsg) {
- onToRuleMsg((ToRuleActorMsg) msg);
- } else if (msg instanceof ToDeviceActorNotificationMsg) {
- onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg);
- } else if (msg instanceof ClusterEventMsg) {
- broadcast(msg);
- } else if (msg instanceof ComponentLifecycleMsg) {
- onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
- } else if (msg instanceof PluginTerminationMsg) {
- onPluginTerminated((PluginTerminationMsg) msg);
- } else {
- logger.warning("[{}] Unknown message: {}!", tenantId, msg);
+ protected boolean process(TbActorMsg msg) {
+ switch (msg.getMsgType()) {
+ case COMPONENT_LIFE_CYCLE_MSG:
+ onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
+ break;
+ case SERVICE_TO_RULE_ENGINE_MSG:
+ onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg);
+ break;
+ default:
+ return false;
}
+ return true;
}
+ private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) {
+ ruleChainManager.getRootChainActor().tell(msg, self());
+ }
+
+
+// @Override
+// public void onReceive(Object msg) throws Exception {
+// logger.debug("[{}] Received message: {}", tenantId, msg);
+// if (msg instanceof ToDeviceActorMsg) {
+// onToDeviceActorMsg((ToDeviceActorMsg) msg);
+// } else if (msg instanceof ToPluginActorMsg) {
+// onToPluginMsg((ToPluginActorMsg) msg);
+// } else if (msg instanceof ToDeviceActorNotificationMsg) {
+// onToDeviceActorMsg((ToDeviceActorNotificationMsg) msg);
+// } else if (msg instanceof ClusterEventMsg) {
+// broadcast(msg);
+// } else if (msg instanceof ComponentLifecycleMsg) {
+// onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
+// } else if (msg instanceof PluginTerminationMsg) {
+// onPluginTerminated((PluginTerminationMsg) msg);
+// } else {
+// logger.warning("[{}] Unknown message: {}!", tenantId, msg);
+// }
+// }
+
private void broadcast(Object msg) {
pluginManager.broadcast(msg);
deviceActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
@@ -113,14 +114,9 @@ public class TenantActor extends ContextAwareActor {
getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender());
}
- private void onToRuleMsg(ToRuleActorMsg msg) {
- ActorRef target = ruleManager.getOrCreateRuleActor(this.context(), msg.getRuleId());
- target.tell(msg, ActorRef.noSender());
- }
-
private void onToPluginMsg(ToPluginActorMsg msg) {
if (msg.getPluginTenantId().equals(tenantId)) {
- ActorRef pluginActor = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId());
+ ActorRef pluginActor = pluginManager.getOrCreateActor(this.context(), msg.getPluginId());
pluginActor.tell(msg, ActorRef.noSender());
} else {
context().parent().tell(msg, ActorRef.noSender());
@@ -128,23 +124,11 @@ public class TenantActor extends ContextAwareActor {
}
private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
- Optional pluginId = msg.getPluginId();
- Optional ruleId = msg.getRuleId();
- if (pluginId.isPresent()) {
- ActorRef pluginActor = pluginManager.getOrCreatePluginActor(this.context(), pluginId.get());
- pluginActor.tell(msg, ActorRef.noSender());
- } else if (ruleId.isPresent()) {
- ActorRef target;
- Optional ref = ruleManager.update(this.context(), ruleId.get(), msg.getEvent());
- if (ref.isPresent()) {
- target = ref.get();
- } else {
- logger.debug("Failed to find actor for rule: [{}]", ruleId);
- return;
- }
+ ActorRef target = getEntityActorRef(msg.getEntityId());
+ if (target != null) {
target.tell(msg, ActorRef.noSender());
} else {
- logger.debug("[{}] Invalid component lifecycle msg.", tenantId);
+ logger.debug("Invalid component lifecycle msg: {}", msg);
}
}
@@ -152,13 +136,6 @@ public class TenantActor extends ContextAwareActor {
pluginManager.remove(msg.getId());
}
- private void process(RuleChainDeviceMsg msg) {
- ToDeviceActorMsg toDeviceActorMsg = msg.getToDeviceActorMsg();
- ActorRef deviceActor = getOrCreateDeviceActor(toDeviceActorMsg.getDeviceId());
- RuleActorChain tenantChain = ruleManager.getRuleChain(this.context());
- RuleActorChain chain = new ComplexRuleActorChain(msg.getRuleChain(), tenantChain);
- deviceActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, chain), context().self());
- }
private ActorRef getOrCreateDeviceActor(DeviceId deviceId) {
return deviceActors.computeIfAbsent(deviceId, k -> context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId))
diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
index 2952529812..24c533c59d 100644
--- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
@@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
@@ -37,7 +36,6 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.thingsboard.server.dao.audit.AuditLogLevelFilter;
diff --git a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
index a75ecb1353..2e5050a9ad 100644
--- a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
@@ -17,9 +17,9 @@ package org.thingsboard.server.config;
import java.util.Map;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
-import org.thingsboard.server.exception.ThingsboardException;
-import org.thingsboard.server.controller.plugin.PluginWebSocketHandler;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.controller.plugin.TbWebSocketHandler;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -54,7 +54,7 @@ public class WebSocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
- registry.addHandler(pluginWsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*")
+ registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*")
.addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() {
@Override
@@ -82,8 +82,8 @@ public class WebSocketConfiguration implements WebSocketConfigurer {
}
@Bean
- public WebSocketHandler pluginWsHandler() {
- return new PluginWebSocketHandler();
+ public WebSocketHandler wsHandler() {
+ return new TbWebSocketHandler();
}
protected SecurityUser getCurrentUser() throws ThingsboardException {
diff --git a/application/src/main/java/org/thingsboard/server/controller/AdminController.java b/application/src/main/java/org/thingsboard/server/controller/AdminController.java
index e9a6ba3816..5a43125bbf 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AdminController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AdminController.java
@@ -20,8 +20,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.dao.settings.AdminSettingsService;
-import org.thingsboard.server.exception.ThingsboardException;
-import org.thingsboard.server.service.mail.MailService;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.service.update.UpdateService;
import org.thingsboard.server.service.update.model.UpdateMessage;
diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
index 1959f4e528..81bcf7e765 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -23,8 +23,8 @@ import org.thingsboard.server.common.data.alarm.*;
import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
@RestController
@RequestMapping("/api")
diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
index 9b439133d3..0e348f997e 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
@@ -33,8 +33,8 @@ import org.thingsboard.server.common.data.asset.AssetSearchQuery;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.ArrayList;
diff --git a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
index 75bcf2ab15..e8685c74f9 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AuditLogController.java
@@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
import java.util.UUID;
diff --git a/application/src/main/java/org/thingsboard/server/controller/AuthController.java b/application/src/main/java/org/thingsboard/server/controller/AuthController.java
index ef38d802ec..96ff5162c7 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AuthController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AuthController.java
@@ -28,9 +28,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.security.UserCredentials;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
-import org.thingsboard.server.exception.ThingsboardException;
-import org.thingsboard.server.service.mail.MailService;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.model.UserPrincipal;
diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
index 83b304fb8b..29436c1500 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -15,12 +15,9 @@
*/
package org.thingsboard.server.controller;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -30,7 +27,6 @@ import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmId;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.asset.Asset;
-import org.thingsboard.server.common.data.audit.ActionStatus;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.page.TextPageLink;
@@ -49,6 +45,7 @@ import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
+import org.thingsboard.server.dao.device.DeviceOfflineService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
@@ -57,12 +54,13 @@ import org.thingsboard.server.dao.plugin.PluginService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.rule.RuleService;
+import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.security.model.SecurityUser;
@@ -71,6 +69,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.UUID;
import static org.thingsboard.server.dao.service.Validator.validateId;
@@ -84,6 +83,9 @@ public abstract class BaseController {
@Autowired
private ThingsboardErrorResponseHandler errorResponseHandler;
+ @Autowired
+ protected TenantService tenantService;
+
@Autowired
protected CustomerService customerService;
@@ -132,6 +134,9 @@ public abstract class BaseController {
@Autowired
protected AuditLogService auditLogService;
+ @Autowired
+ protected DeviceOfflineService offlineService;
+
@ExceptionHandler(ThingsboardException.class)
public void handleThingsboardException(ThingsboardException ex, HttpServletResponse response) {
errorResponseHandler.handle(ex, response);
@@ -480,6 +485,15 @@ public abstract class BaseController {
}
}
+ List checkComponentDescriptorsByTypes(Set types) throws ThingsboardException {
+ try {
+ log.debug("[{}] Lookup component descriptors", types);
+ return componentDescriptorService.getComponents(types);
+ } catch (Exception e) {
+ throw handleException(e, false);
+ }
+ }
+
List checkPluginActionsByPluginClazz(String pluginClazz) throws ThingsboardException {
try {
checkComponentDescriptorByClazz(pluginClazz);
@@ -550,6 +564,8 @@ public abstract class BaseController {
throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
ThingsboardErrorCode.PERMISSION_DENIED);
+ } else if (tenantId.getId().equals(ModelConstants.NULL_UUID)) {
+ ruleChain.setConfiguration(null);
}
}
return ruleChain;
@@ -590,5 +606,8 @@ public abstract class BaseController {
auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo);
}
+ protected static Exception toException(Throwable error) {
+ return Exception.class.isInstance(error) ? (Exception) error : new Exception(error);
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
index e63a443769..6313d615a3 100644
--- a/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/ComponentDescriptorController.java
@@ -19,9 +19,11 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
@RestController
@RequestMapping("/api")
@@ -51,6 +53,22 @@ public class ComponentDescriptorController extends BaseController {
}
}
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
+ @RequestMapping(value = "/components", params = {"componentTypes"}, method = RequestMethod.GET)
+ @ResponseBody
+ public List getComponentDescriptorsByTypes(@RequestParam("componentTypes") String[] strComponentTypes) throws ThingsboardException {
+ checkArrayParameter("componentTypes", strComponentTypes);
+ try {
+ Set componentTypes = new HashSet<>();
+ for (String strComponentType : strComponentTypes) {
+ componentTypes.add(ComponentType.valueOf(strComponentType));
+ }
+ return checkComponentDescriptorsByTypes(componentTypes);
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
@PreAuthorize("hasAnyAuthority('SYS_ADMIN','TENANT_ADMIN')")
@RequestMapping(value = "/components/actions/{pluginClazz:.+}", method = RequestMethod.GET)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
index b16470216a..7763f3c00a 100644
--- a/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/CustomerController.java
@@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
@RestController
@RequestMapping("/api")
diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
index d2952a16cb..4ec2bbab05 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
@@ -27,9 +27,7 @@ import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
-import org.thingsboard.server.dao.exception.IncorrectParameterException;
-import org.thingsboard.server.dao.model.ModelConstants;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
import java.util.HashSet;
import java.util.Set;
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
index bceea54135..f97603e40f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
@@ -23,9 +23,11 @@ import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
-import org.thingsboard.server.common.data.audit.ActionStatus;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.device.DeviceSearchQuery;
+import org.thingsboard.server.common.data.device.DeviceStatusQuery;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
@@ -35,8 +37,6 @@ import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
-import org.thingsboard.server.exception.ThingsboardException;
import org.thingsboard.server.service.security.model.SecurityUser;
import java.util.ArrayList;
@@ -70,7 +70,7 @@ public class DeviceController extends BaseController {
device.setTenantId(getCurrentUser().getTenantId());
if (getCurrentUser().getAuthority() == Authority.CUSTOMER_USER) {
if (device.getId() == null || device.getId().isNullUid() ||
- device.getCustomerId() == null || device.getCustomerId().isNullUid()) {
+ device.getCustomerId() == null || device.getCustomerId().isNullUid()) {
throw new ThingsboardException("You don't have permission to perform this operation!",
ThingsboardErrorCode.PERMISSION_DENIED);
} else {
@@ -368,4 +368,32 @@ public class DeviceController extends BaseController {
throw handleException(e);
}
}
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
+ @RequestMapping(value = "/device/offline", method = RequestMethod.GET)
+ @ResponseBody
+ public List getOfflineDevices(@RequestParam("contactType") DeviceStatusQuery.ContactType contactType,
+ @RequestParam("threshold") long threshold) throws ThingsboardException {
+ try {
+ TenantId tenantId = getCurrentUser().getTenantId();
+ ListenableFuture> offlineDevices = offlineService.findOfflineDevices(tenantId.getId(), contactType, threshold);
+ return checkNotNull(offlineDevices.get());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
+ @RequestMapping(value = "/device/online", method = RequestMethod.GET)
+ @ResponseBody
+ public List getOnlineDevices(@RequestParam("contactType") DeviceStatusQuery.ContactType contactType,
+ @RequestParam("threshold") long threshold) throws ThingsboardException {
+ try {
+ TenantId tenantId = getCurrentUser().getTenantId();
+ ListenableFuture> offlineDevices = offlineService.findOnlineDevices(tenantId.getId(), contactType, threshold);
+ return checkNotNull(offlineDevices.get());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
index 03054df985..3a3b78b52f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
@@ -24,8 +24,8 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationInfo;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
import java.util.List;
diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java
index 331b15eb09..f67f113144 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EventController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java
@@ -24,8 +24,8 @@ import org.thingsboard.server.common.data.page.TimePageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.dao.model.ModelConstants;
-import org.thingsboard.server.exception.ThingsboardErrorCode;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
@RestController
@RequestMapping("/api")
diff --git a/application/src/main/java/org/thingsboard/server/controller/HttpValidationCallback.java b/application/src/main/java/org/thingsboard/server/controller/HttpValidationCallback.java
new file mode 100644
index 0000000000..fb1f3e7bee
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/controller/HttpValidationCallback.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.controller;
+
+import com.google.common.util.concurrent.FutureCallback;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.context.request.async.DeferredResult;
+import org.thingsboard.server.service.security.ValidationCallback;
+
+/**
+ * Created by ashvayka on 21.02.17.
+ */
+public class HttpValidationCallback extends ValidationCallback> {
+
+ public HttpValidationCallback(DeferredResult response, FutureCallback> action) {
+ super(response, action);
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/controller/PluginController.java b/application/src/main/java/org/thingsboard/server/controller/PluginController.java
index 2c69248faa..3bc385d7b2 100644
--- a/application/src/main/java/org/thingsboard/server/controller/PluginController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/PluginController.java
@@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.model.ModelConstants;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
import java.util.List;
@@ -71,7 +71,7 @@ public class PluginController extends BaseController {
boolean created = source.getId() == null;
source.setTenantId(getCurrentUser().getTenantId());
PluginMetaData plugin = checkNotNull(pluginService.savePlugin(source));
- actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(),
+ actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(),
created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
logEntityAction(plugin.getId(), plugin,
@@ -97,7 +97,7 @@ public class PluginController extends BaseController {
PluginId pluginId = new PluginId(toUUID(strPluginId));
PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId));
pluginService.activatePluginById(pluginId);
- actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.ACTIVATED);
+ actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.ACTIVATED);
logEntityAction(plugin.getId(), plugin,
null,
@@ -123,7 +123,7 @@ public class PluginController extends BaseController {
PluginId pluginId = new PluginId(toUUID(strPluginId));
PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId));
pluginService.suspendPluginById(pluginId);
- actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.SUSPENDED);
+ actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.SUSPENDED);
logEntityAction(plugin.getId(), plugin,
null,
@@ -221,7 +221,7 @@ public class PluginController extends BaseController {
PluginId pluginId = new PluginId(toUUID(strPluginId));
PluginMetaData plugin = checkPlugin(pluginService.findPluginById(pluginId));
pluginService.deletePluginById(pluginId);
- actorService.onPluginStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.DELETED);
+ actorService.onEntityStateChange(plugin.getTenantId(), plugin.getId(), ComponentLifecycleEvent.DELETED);
logEntityAction(pluginId, plugin,
null,
diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
index 012e0770b3..48c9cd5342 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
@@ -15,31 +15,46 @@
*/
package org.thingsboard.server.controller;
+import com.datastax.driver.core.utils.UUIDs;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
+import org.thingsboard.rule.engine.api.ScriptEngine;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
-import org.thingsboard.server.common.data.id.PluginId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
-import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.rule.RuleChain;
+import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.security.Authority;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.model.ModelConstants;
-import org.thingsboard.server.exception.ThingsboardException;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.service.script.NashornJsEngine;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+@Slf4j
@RestController
@RequestMapping("/api")
public class RuleChainController extends BaseController {
public static final String RULE_CHAIN_ID = "ruleChainId";
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
@ResponseBody
@@ -53,6 +68,21 @@ public class RuleChainController extends BaseController {
}
}
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ @RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET)
+ @ResponseBody
+ public RuleChainMetaData getRuleChainMetaData(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
+ checkParameter(RULE_CHAIN_ID, strRuleChainId);
+ try {
+ RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
+ checkRuleChain(ruleChainId);
+ return ruleChainService.loadRuleChainMetaData(ruleChainId);
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
@ResponseBody
@@ -62,6 +92,9 @@ public class RuleChainController extends BaseController {
ruleChain.setTenantId(getCurrentUser().getTenantId());
RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain));
+ actorService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(),
+ created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
+
logEntityAction(savedRuleChain.getId(), savedRuleChain,
null,
created ? ActionType.ADDED : ActionType.UPDATED, null);
@@ -76,6 +109,30 @@ public class RuleChainController extends BaseController {
}
}
+ @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
+ @RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST)
+ @ResponseBody
+ public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException {
+ try {
+ RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId());
+ RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(ruleChainMetaData));
+
+ actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
+
+ logEntityAction(ruleChain.getId(), ruleChain,
+ null,
+ ActionType.UPDATED, null, ruleChainMetaData);
+
+ return savedRuleChainMetaData;
+ } catch (Exception e) {
+
+ logEntityAction(emptyId(EntityType.RULE_CHAIN), null,
+ null, ActionType.UPDATED, e, ruleChainMetaData);
+
+ throw handleException(e);
+ }
+ }
+
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/ruleChains", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody
@@ -145,6 +202,8 @@ public class RuleChainController extends BaseController {
RuleChain ruleChain = checkRuleChain(ruleChainId);
ruleChainService.deleteRuleChainById(ruleChainId);
+ actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED);
+
logEntityAction(ruleChainId, ruleChain,
null,
ActionType.DELETED, null, strRuleChainId);
@@ -158,4 +217,78 @@ public class RuleChainController extends BaseController {
}
}
+ @PreAuthorize("hasAuthority('TENANT_ADMIN')")
+ @RequestMapping(value = "/ruleChain/testScript", method = RequestMethod.POST)
+ @ResponseBody
+ public JsonNode testScript(@RequestBody JsonNode inputParams) throws ThingsboardException {
+ try {
+ String script = inputParams.get("script").asText();
+ String scriptType = inputParams.get("scriptType").asText();
+ String functionName = inputParams.get("functionName").asText();
+ JsonNode argNamesJson = inputParams.get("argNames");
+ String[] argNames = objectMapper.treeToValue(argNamesJson, String[].class);
+
+ String data = inputParams.get("msg").asText();
+ JsonNode metadataJson = inputParams.get("metadata");
+ Map metadata = objectMapper.convertValue(metadataJson, new TypeReference