diff --git a/application/pom.xml b/application/pom.xml index 95322fa3a2..6da40a9143 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -57,6 +57,10 @@ 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..ab6884659d 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,6 +86,7 @@ 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, 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..2bed6ad9da 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,6 @@ 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 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 68d55475af..bbe7771e61 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -1,12 +1,12 @@ /** * 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 - * + *

+ * 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. @@ -28,12 +28,14 @@ import lombok.Setter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; 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; @@ -50,6 +52,7 @@ 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; @@ -57,6 +60,7 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService; import java.io.PrintWriter; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; import java.util.Optional; @Component @@ -65,107 +69,154 @@ public class ActorSystemContext { 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 RuleChainService ruleChainService; + @Getter + private RuleService ruleService; @Autowired - @Getter private PluginService pluginService; + @Getter + private RuleChainService ruleChainService; @Autowired - @Getter private TimeseriesService tsService; + @Getter + private PluginService pluginService; @Autowired - @Getter private AttributesService attributesService; + @Getter + private TimeseriesService tsService; @Autowired - @Getter private EventService eventService; + @Getter + private AttributesService attributesService; @Autowired - @Getter private AlarmService alarmService; + @Getter + private EventService eventService; @Autowired - @Getter private RelationService relationService; + @Getter + private AlarmService alarmService; @Autowired - @Getter private AuditLogService auditLogService; + @Getter + private RelationService relationService; @Autowired - @Getter @Setter private PluginWebSocketMsgEndpoint wsMsgEndpoint; + @Getter + private AuditLogService auditLogService; + + @Autowired + @Getter + @Setter + private PluginWebSocketMsgEndpoint wsMsgEndpoint; @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; + @Getter + private long ruleChainErrorPersistFrequency; @Value("${actors.rule.node.error_persist_frequency}") - @Getter private long ruleNodeErrorPersistFrequency; + @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()); @@ -197,7 +248,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(); @@ -217,4 +268,64 @@ 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) { + Event event = new Event(); + event.setTenantId(tenantId); + event.setEntityId(entityId); + event.setType(DataConstants.DEBUG); + + 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()); + + ObjectNode mdNode = node.putObject("metadata"); + tbMsg.getMetaData().getData().forEach(mdNode::put); + + switch (tbMsg.getDataType()) { + case BINARY: + node.put("data", Base64Utils.encodeUrlSafe(tbMsg.getData())); + break; + default: + node.put("data", new String(tbMsg.getData(), StandardCharsets.UTF_8)); + break; + } + + if (error != null) { + node = node.put("error", toString(error)); + } + + event.setBody(node); + eventService.save(event); + } + + 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 5e05a60a14..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 @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. @@ -88,7 +88,7 @@ public class AppActor extends RuleChainManagerActor { } @Override - protected void process(TbActorMsg msg) { + protected boolean process(TbActorMsg msg) { switch (msg.getMsgType()) { case COMPONENT_LIFE_CYCLE_MSG: onComponentLifecycleMsg((ComponentLifecycleMsg) msg); @@ -96,7 +96,10 @@ public class AppActor extends RuleChainManagerActor { case SERVICE_TO_RULE_ENGINE_MSG: onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); break; + default: + return false; } + return true; } private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { 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= 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/CompoundRuleActorChain.java b/application/src/main/java/org/thingsboard/server/actors/rule/CompoundRuleActorChain.java deleted file mode 100644 index b2eb53fe3f..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/rule/CompoundRuleActorChain.java +++ /dev/null @@ -1,20 +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 CompoundRuleActorChain { - -} 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 236fca7e0f..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(ActorContext context) 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(ActorContext context) 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/RuleContextAwareMsgProcessor.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleContextAwareMsgProcessor.java deleted file mode 100644 index c0d0705c4d..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleContextAwareMsgProcessor.java +++ /dev/null @@ -1,33 +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.shared.AbstractContextAwareMsgProcessor; -import org.thingsboard.server.common.data.id.RuleId; - -import akka.event.LoggingAdapter; - -public class RuleContextAwareMsgProcessor extends AbstractContextAwareMsgProcessor { - - private final RuleId ruleId; - - protected RuleContextAwareMsgProcessor(ActorSystemContext systemContext, LoggingAdapter logger, RuleId ruleId) { - super(systemContext, logger); - this.ruleId = ruleId; - } - -} 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/rule/RuleProcessingMsg.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingMsg.java deleted file mode 100644 index 291a9a7cef..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleProcessingMsg.java +++ /dev/null @@ -1,31 +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 RuleProcessingMsg { - - private final ChainProcessingContext ctx; - - public RuleProcessingMsg(ChainProcessingContext ctx) { - super(); - this.ctx = ctx; - } - - public ChainProcessingContext getCtx() { - return ctx; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleTerminationMsg.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleTerminationMsg.java deleted file mode 100644 index 4458e5217c..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleTerminationMsg.java +++ /dev/null @@ -1,30 +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.shared.ActorTerminationMsg; -import org.thingsboard.server.common.data.id.PluginId; -import org.thingsboard.server.common.data.id.RuleId; - -/** - * @author Andrew Shvayka - */ -public class RuleTerminationMsg extends ActorTerminationMsg { - - public RuleTerminationMsg(RuleId id) { - super(id); - } -} diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleToPluginTimeoutMsg.java b/application/src/main/java/org/thingsboard/server/actors/rule/RuleToPluginTimeoutMsg.java deleted file mode 100644 index 0258bce130..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleToPluginTimeoutMsg.java +++ /dev/null @@ -1,36 +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.io.Serializable; -import java.util.UUID; - -public class RuleToPluginTimeoutMsg implements Serializable { - - private static final long serialVersionUID = 1L; - - private final UUID msgId; - - public RuleToPluginTimeoutMsg(UUID msgId) { - super(); - this.msgId = msgId; - } - - public UUID getMsgId() { - return msgId; - } - -} diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/SimpleRuleActorChain.java b/application/src/main/java/org/thingsboard/server/actors/rule/SimpleRuleActorChain.java deleted file mode 100644 index 70a26e4430..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/rule/SimpleRuleActorChain.java +++ /dev/null @@ -1,39 +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.ArrayList; -import java.util.List; -import java.util.Set; - -public class SimpleRuleActorChain implements RuleActorChain { - - private final List rules; - - public SimpleRuleActorChain(Set ruleSet) { - rules = new ArrayList<>(ruleSet); - rules.sort(RuleActorMetaData.RULE_ACTOR_MD_COMPARATOR); - } - - public int size() { - return rules.size(); - } - - public RuleActorMetaData getRuleActorMd(int index) { - return rules.get(index); - } - -} 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 index 0cd7601653..a1344aa8d4 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -1,10 +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 org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.server.actors.ActorSystemContext; 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; /** * Created by ashvayka on 19.03.18. @@ -26,27 +50,30 @@ class DefaultTbContext implements TbContext { @Override public void tellNext(TbMsg msg, String relationType) { - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelfId(), relationType, msg), nodeCtx.getSelf()); + 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) { - + throw new RuntimeException("Not Implemented!"); } @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 @@ -54,8 +81,61 @@ class DefaultTbContext implements TbContext { } + @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 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 RelationService getRelationService() { + return mainCtx.getRelationService(); + } } 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 index 20ea05deb4..9c8de22376 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleChainActor.java @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. @@ -33,7 +33,7 @@ public class RuleChainActor extends ComponentActor { @@ -69,4 +72,6 @@ public class RuleChainActor extends ComponentActor ruleNodeList = service.getRuleChainNodes(entityId); // Creating and starting the actors; @@ -74,8 +79,8 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor 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); - pushMstToNode(targetRuleNode, envelope.getMsg()); + pushMstToNode(targetRuleNode, msg); break; case RULE_CHAIN: // TODO: implement @@ -137,7 +154,13 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor { private static final long serialVersionUID = 1L; @@ -69,4 +89,6 @@ public class RuleNodeActor extends ComponentActor componentClazz = Class.forName(ruleNode.getType()); + TbNode tbNode = (TbNode) (componentClazz.newInstance()); + tbNode.init(new TbNodeConfiguration(ruleNode.getConfiguration()), new TbNodeState()); + 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 index dd25f8bc85..90c67c2a06 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeCtx.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeCtx.java @@ -1,15 +1,33 @@ +/** + * 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.Data; import org.thingsboard.server.common.data.id.RuleNodeId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.rule.RuleNode; /** * Created by ashvayka on 19.03.18. */ @Data final class RuleNodeCtx { + private final TenantId tenantId; private final ActorRef chainActor; - private final ActorRef self; - private final RuleNodeId selfId; + private final ActorRef selfActor; + private final RuleNode self; } diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeRelation.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeRelation.java index bd2d544eb3..7861e5473c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeRelation.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeRelation.java @@ -1,3 +1,18 @@ +/** + * 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; 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 index 95b362591d..054284dc59 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToRuleChainTellNextMsg.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToRuleChainTellNextMsg.java @@ -1,3 +1,18 @@ +/** + * 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; diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RulesProcessedMsg.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java similarity index 54% rename from application/src/main/java/org/thingsboard/server/actors/rule/RulesProcessedMsg.java rename to application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java index 82b6a6784e..4fc03ac671 100644 --- a/application/src/main/java/org/thingsboard/server/actors/rule/RulesProcessedMsg.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeToSelfErrorMsg.java @@ -13,22 +13,26 @@ * 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 RulesProcessedMsg { - private final ChainProcessingContext ctx; +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; - public RulesProcessedMsg(ChainProcessingContext ctx) { - super(); - this.ctx = ctx; - } +/** + * Created by ashvayka on 19.03.18. + */ +@Data +final class RuleNodeToSelfErrorMsg implements TbActorMsg { - public ChainProcessingContext getCtx() { - return ctx; - } + private final TbMsg msg; + private final Throwable error; @Override - public String toString() { - return "RulesProcessedMsg [ctx=" + ctx + "]"; + public MsgType getMsgType() { + return MsgType.RULE_TO_SELF_ERROR_MSG; } + } 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 d0260dd974..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 @@ -141,7 +141,6 @@ public abstract class ComponentActor + * * 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 - *

+ * + * 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. diff --git a/application/src/main/java/org/thingsboard/server/actors/session/SessionActor.java b/application/src/main/java/org/thingsboard/server/actors/session/SessionActor.java index 37827d61fb..9d324c5b94 100644 --- a/application/src/main/java/org/thingsboard/server/actors/session/SessionActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/session/SessionActor.java @@ -23,6 +23,7 @@ import org.thingsboard.server.actors.service.ContextAwareActor; import org.thingsboard.server.actors.service.ContextBasedCreator; import org.thingsboard.server.actors.shared.SessionTimeoutMsg; import org.thingsboard.server.common.data.id.SessionId; +import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; import org.thingsboard.server.common.msg.core.ToDeviceSessionActorMsg; import org.thingsboard.server.common.msg.session.ToDeviceActorSessionMsg; @@ -60,6 +61,12 @@ public class SessionActor 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 { logger.debug("[{}] Processing: {}.", sessionId, msg); diff --git a/application/src/main/java/org/thingsboard/server/actors/session/SessionManagerActor.java b/application/src/main/java/org/thingsboard/server/actors/session/SessionManagerActor.java index 9d67dabeb8..b5b17917b9 100644 --- a/application/src/main/java/org/thingsboard/server/actors/session/SessionManagerActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/session/SessionManagerActor.java @@ -26,6 +26,7 @@ import org.thingsboard.server.actors.service.ContextBasedCreator; import org.thingsboard.server.actors.service.DefaultActorService; import org.thingsboard.server.actors.shared.SessionTimeoutMsg; import org.thingsboard.server.common.data.id.SessionId; +import org.thingsboard.server.common.msg.TbActorMsg; import org.thingsboard.server.common.msg.aware.SessionAwareMsg; import akka.event.Logging; @@ -48,6 +49,12 @@ public class SessionManagerActor extends ContextAwareActor { this.sessionActors = new HashMap<>(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/EntityActorsManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java index 917a6452c4..d4a1f34006 100644 --- a/application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java +++ b/application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java @@ -1,3 +1,18 @@ +/** + * 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; 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 5142de2c15..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 @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. 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/rule/SystemRuleManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/rule/SystemRuleManager.java deleted file mode 100644 index d10731caed..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/shared/rule/SystemRuleManager.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.shared.rule; - -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.dao.model.ModelConstants; - -public class SystemRuleManager extends RuleManager { - - public SystemRuleManager(ActorSystemContext systemContext) { - super(systemContext, new TenantId(ModelConstants.NULL_UUID)); - } - - @Override - FetchFunction getFetchRulesFunction() { - return ruleService::findSystemRules; - } - - @Override - 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/rule/TenantRuleManager.java deleted file mode 100644 index e4d023ca90..0000000000 --- a/application/src/main/java/org/thingsboard/server/actors/shared/rule/TenantRuleManager.java +++ /dev/null @@ -1,48 +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 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; - -public class TenantRuleManager extends RuleManager { - - public TenantRuleManager(ActorSystemContext systemContext, TenantId tenantId) { - super(systemContext, tenantId); - } - - @Override - public void init(ActorContext context) { - if (systemContext.isTenantComponentsInitEnabled()) { - super.init(context); - } - } - - @Override - FetchFunction getFetchRulesFunction() { - return link -> ruleService.findTenantRules(tenantId, link); - } - - @Override - String getDispatcherName() { - return DefaultActorService.TENANT_RULE_DISPATCHER_NAME; - } - -} 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 index 97acb6cbfb..ff0c52ef45 100644 --- 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 @@ -1,3 +1,18 @@ +/** + * 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; diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java index aa2a63104a..731d8d8e6c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java +++ b/application/src/main/java/org/thingsboard/server/actors/shared/rulechain/TenantRuleChainManager.java @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. @@ -18,12 +18,9 @@ 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.actors.shared.rule.RuleManager; 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.rule.RuleChain; -import org.thingsboard.server.common.data.rule.RuleMetaData; public class TenantRuleChainManager extends RuleChainManager { 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 a51e7a2187..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 @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. @@ -62,7 +62,7 @@ public class TenantActor extends RuleChainManagerActor { } @Override - protected void process(TbActorMsg msg) { + protected boolean process(TbActorMsg msg) { switch (msg.getMsgType()) { case COMPONENT_LIFE_CYCLE_MSG: onComponentLifecycleMsg((ComponentLifecycleMsg) msg); @@ -70,7 +70,10 @@ public class TenantActor extends RuleChainManagerActor { case SERVICE_TO_RULE_ENGINE_MSG: onServiceToRuleEngineMsg((ServiceToRuleEngineMsg) msg); break; + default: + return false; } + return true; } private void onServiceToRuleEngineMsg(ServiceToRuleEngineMsg msg) { 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 93891ac53a..c6befdd8ca 100644 --- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java +++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java @@ -78,7 +78,7 @@ public class RuleChainController extends BaseController { ruleChain.setTenantId(getCurrentUser().getTenantId()); RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); - actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), + actorService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); logEntityAction(savedRuleChain.getId(), savedRuleChain, diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index 0a6081d8da..910b45954a 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -26,6 +26,10 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen import org.springframework.core.env.Environment; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.stereotype.Service; +import org.thingsboard.rule.engine.api.ActionNode; +import org.thingsboard.rule.engine.api.EnrichmentNode; +import org.thingsboard.rule.engine.api.FilterNode; +import org.thingsboard.rule.engine.api.TransformationNode; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.dao.component.ComponentDescriptorService; @@ -79,8 +83,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe private List persist(Set filterDefs, ComponentType type) { List result = new ArrayList<>(); for (BeanDefinition def : filterDefs) { - ComponentDescriptor scannedComponent = scanAndPersistComponent(def, type); - result.add(scannedComponent); + result.add(scanAndPersistComponent(def, type)); } return result; } @@ -93,24 +96,36 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe Class clazz = Class.forName(clazzName); String descriptorResourceName; switch (type) { + case ENRICHMENT: + EnrichmentNode enrichmentAnnotation = clazz.getAnnotation(EnrichmentNode.class); + scannedComponent.setName(enrichmentAnnotation.name()); + scannedComponent.setScope(enrichmentAnnotation.scope()); + descriptorResourceName = enrichmentAnnotation.descriptor(); + break; case FILTER: - Filter filterAnnotation = clazz.getAnnotation(Filter.class); + FilterNode filterAnnotation = clazz.getAnnotation(FilterNode.class); scannedComponent.setName(filterAnnotation.name()); scannedComponent.setScope(filterAnnotation.scope()); descriptorResourceName = filterAnnotation.descriptor(); break; - case PROCESSOR: - Processor processorAnnotation = clazz.getAnnotation(Processor.class); - scannedComponent.setName(processorAnnotation.name()); - scannedComponent.setScope(processorAnnotation.scope()); - descriptorResourceName = processorAnnotation.descriptor(); + case TRANSFORMATION: + TransformationNode trAnnotation = clazz.getAnnotation(TransformationNode.class); + scannedComponent.setName(trAnnotation.name()); + scannedComponent.setScope(trAnnotation.scope()); + descriptorResourceName = trAnnotation.descriptor(); break; case ACTION: - Action actionAnnotation = clazz.getAnnotation(Action.class); + ActionNode actionAnnotation = clazz.getAnnotation(ActionNode.class); scannedComponent.setName(actionAnnotation.name()); scannedComponent.setScope(actionAnnotation.scope()); descriptorResourceName = actionAnnotation.descriptor(); break; + case OLD_ACTION: + Action oldActionAnnotation = clazz.getAnnotation(Action.class); + scannedComponent.setName(oldActionAnnotation.name()); + scannedComponent.setScope(oldActionAnnotation.scope()); + descriptorResourceName = oldActionAnnotation.descriptor(); + break; case PLUGIN: Plugin pluginAnnotation = clazz.getAnnotation(Plugin.class); scannedComponent.setName(pluginAnnotation.name()); @@ -122,12 +137,12 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe log.error("Can't initialize plugin {}, due to missing action {}!", def.getBeanClassName(), actionClazz.getName()); return new ClassNotFoundException("Action: " + actionClazz.getName() + "is missing!"); }); - if (actionComponent.getType() != ComponentType.ACTION) { + if (actionComponent.getType() != ComponentType.OLD_ACTION) { log.error("Plugin {} action {} has wrong component type!", def.getBeanClassName(), actionClazz.getName(), actionComponent.getType()); throw new RuntimeException("Plugin " + def.getBeanClassName() + "action " + actionClazz.getName() + " has wrong component type!"); } } - scannedComponent.setActions(Arrays.stream(pluginAnnotation.actions()).map(action -> action.getName()).collect(Collectors.joining(","))); + scannedComponent.setActions(Arrays.stream(pluginAnnotation.actions()).map(Class::getName).collect(Collectors.joining(","))); break; default: throw new RuntimeException(type + " is not supported yet!"); @@ -168,11 +183,15 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @Override public void discoverComponents() { - registerComponents(ComponentType.FILTER, Filter.class); + registerComponents(ComponentType.ENRICHMENT, EnrichmentNode.class); + + registerComponents(ComponentType.FILTER, FilterNode.class); + + registerComponents(ComponentType.TRANSFORMATION, TransformationNode.class); - registerComponents(ComponentType.PROCESSOR, Processor.class); + registerComponents(ComponentType.ACTION, ActionNode.class); - registerComponents(ComponentType.ACTION, Action.class); + registerComponents(ComponentType.OLD_ACTION, Action.class); registerComponents(ComponentType.PLUGIN, Plugin.class); @@ -199,7 +218,7 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe } List result = new ArrayList<>(); for (String action : plugin.getActions().split(",")) { - getComponent(action).ifPresent(v -> result.add(v)); + getComponent(action).ifPresent(result::add); } return result; } else { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 778c2a3ffb..27585212db 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -62,7 +62,7 @@ cluster: # Plugins configuration parameters plugins: # Comma seperated package list used during classpath scanning for plugins - scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions}" + scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions,org.thingsboard.rule.engine}" # JWT Token parameters security.jwt: @@ -215,12 +215,12 @@ actors: termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}" # Errors for particular actor are persisted once per specified amount of milliseconds error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}" - chain: - # Errors for particular actor are persisted once per specified amount of milliseconds - error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" - node: - # Errors for particular actor are persisted once per specified amount of milliseconds - error_persist_frequency: "${ACTORS_RULE_NODE_ERROR_FREQUENCY:3000}" + chain: + # Errors for particular actor are persisted once per specified amount of milliseconds + error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" + node: + # Errors for particular actor are persisted once per specified amount of milliseconds + error_persist_frequency: "${ACTORS_RULE_NODE_ERROR_FREQUENCY:3000}" statistics: # Enable/disable actor statistics enabled: "${ACTORS_STATISTICS_ENABLED:true}" diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java index b92e464a6e..3ec4dc815b 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java @@ -96,6 +96,8 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC @Slf4j public abstract class AbstractControllerTest { + protected ObjectMapper mapper = new ObjectMapper(); + protected static final String TEST_TENANT_NAME = "TEST TENANT"; protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org"; diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java new file mode 100644 index 0000000000..9aa75745cf --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java @@ -0,0 +1,41 @@ +package org.thingsboard.server.controller; + +import com.fasterxml.jackson.core.type.TypeReference; +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.RuleChainId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainMetaData; + +/** + * Created by ashvayka on 20.03.18. + */ +public class AbstractRuleEngineControllerTest extends AbstractControllerTest{ + + protected RuleChain saveRuleChain(RuleChain ruleChain) throws Exception { + return doPost("/api/ruleChain", ruleChain, RuleChain.class); + } + + protected RuleChain getRuleChain(RuleChainId ruleChainId) throws Exception { + return doGet("/api/ruleChain/" + ruleChainId.getId().toString(), RuleChain.class); + } + + protected RuleChainMetaData saveRuleChainMetaData(RuleChainMetaData ruleChainMD) throws Exception { + return doPost("/api/ruleChain/metadata", ruleChainMD, RuleChainMetaData.class); + } + + protected RuleChainMetaData getRuleChainMetaData(RuleChainId ruleChainId) throws Exception { + return doGet("/api/ruleChain/metadata/" + ruleChainId.getId().toString(), RuleChainMetaData.class); + } + + protected TimePageData getDebugEvents(TenantId tenantId, EntityId entityId, int limit) throws Exception { + TimePageLink pageLink = new TimePageLink(limit); + return doGetTypedWithTimePageLink("/api/events/{entityType}/{entityId}/{eventType}?tenantId={tenantId}&", + new TypeReference>() { + }, pageLink, entityId.getEntityType(), entityId.getId(), DataConstants.DEBUG, tenantId.getId()); + } +} diff --git a/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java new file mode 100644 index 0000000000..136f76b496 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java @@ -0,0 +1,35 @@ +/** + * 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.rules; + +import org.junit.ClassRule; +import org.junit.extensions.cpsuite.ClasspathSuite; +import org.junit.runner.RunWith; +import org.thingsboard.server.dao.CustomSqlUnit; + +import java.util.Arrays; + +@RunWith(ClasspathSuite.class) +@ClasspathSuite.ClassnameFilters({ + "org.thingsboard.server.rules.flow.*Test", "org.thingsboard.server.rules.lifecycle.*Test"}) +public class RuleEngineSqlTestSuite { + + @ClassRule + public static CustomSqlUnit sqlUnit = new CustomSqlUnit( + Arrays.asList("sql/schema.sql", "sql/system-data.sql"), + "sql/drop-all-tables.sql", + "sql-test.properties"); +} diff --git a/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java new file mode 100644 index 0000000000..1f2f70997c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/rules/flow/AbstractRuleEngineFlowIntegrationTest.java @@ -0,0 +1,156 @@ +/** + * 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.rules.flow; + +import com.datastax.driver.core.utils.UUIDs; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; +import org.thingsboard.server.actors.service.ActorService; +import org.thingsboard.server.common.data.*; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleChainMetaData; +import org.thingsboard.server.common.data.rule.RuleNode; +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.common.msg.system.ServiceToRuleEngineMsg; +import org.thingsboard.server.controller.AbstractRuleEngineControllerTest; +import org.thingsboard.server.dao.attributes.AttributesService; + +import java.util.Collections; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author Valerii Sosliuk + */ +@Slf4j +public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRuleEngineControllerTest { + + private static final String MQTT_URL = "tcp://localhost:1883"; + private static final Long TIME_TO_HANDLE_REQUEST = 500L; + + private Tenant savedTenant; + private User tenantAdmin; + + @Autowired + private ActorService actorService; + + @Autowired + private AttributesService attributesService; + + @Before + public void beforeTest() throws Exception { + loginSysAdmin(); + + Tenant tenant = new Tenant(); + tenant.setTitle("My tenant"); + savedTenant = doPost("/api/tenant", tenant, Tenant.class); + Assert.assertNotNull(savedTenant); + + tenantAdmin = new User(); + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); + tenantAdmin.setTenantId(savedTenant.getId()); + tenantAdmin.setEmail("tenant2@thingsboard.org"); + tenantAdmin.setFirstName("Joe"); + tenantAdmin.setLastName("Downs"); + + createUserAndLogin(tenantAdmin, "testPassword1"); + } + + @After + public void afterTest() throws Exception { + loginSysAdmin(); + if (savedTenant != null) { + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk()); + } + } + + @Test + public void testSimpleRuleChainCreation() throws Exception { + // Creating Rule Chain + RuleChain ruleChain = new RuleChain(); + ruleChain.setName("Simple Rule Chain"); + ruleChain.setTenantId(savedTenant.getId()); + ruleChain.setRoot(true); + ruleChain.setDebugMode(true); + ruleChain = saveRuleChain(ruleChain); + Assert.assertNull(ruleChain.getFirstRuleNodeId()); + + RuleChainMetaData metaData = new RuleChainMetaData(); + metaData.setRuleChainId(ruleChain.getId()); + + RuleNode ruleNode = new RuleNode(); + ruleNode.setName("Simple Rule Node"); + ruleNode.setType(org.thingsboard.rule.engine.metadata.TbGetAttributesNode.class.getName()); + ruleNode.setDebugMode(true); + TbGetAttributesNodeConfiguration configuration = new TbGetAttributesNodeConfiguration(); + configuration.setServerAttributeNames(Collections.singletonList("serverAttributeKey")); + ruleNode.setConfiguration(mapper.valueToTree(configuration)); + + metaData.setNodes(Collections.singletonList(ruleNode)); + metaData.setFirstNodeIndex(0); + + metaData = saveRuleChainMetaData(metaData); + Assert.assertNotNull(metaData); + + ruleChain = getRuleChain(ruleChain.getId()); + Assert.assertNotNull(ruleChain.getFirstRuleNodeId()); + + // Saving the device + Device device = new Device(); + device.setName("My device"); + device.setType("default"); + device = doPost("/api/device", device, Device.class); + + attributesService.save(device.getId(), DataConstants.SERVER_SCOPE, + Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey", "serverAttributeValue"), System.currentTimeMillis()))); + + // Pushing Message to the system + TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), + "CUSTOM", + device.getId(), + new TbMsgMetaData(), + new byte[]{}); + actorService.onMsg(new ServiceToRuleEngineMsg(savedTenant.getId(), tbMsg)); + + Thread.sleep(3000); + + TimePageData events = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); + + Assert.assertEquals(2, events.getData().size()); + + Event inEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.IN)).findFirst().get(); + Assert.assertEquals(ruleChain.getFirstRuleNodeId(), inEvent.getEntityId()); + Assert.assertEquals(device.getId().getId().toString(), inEvent.getBody().get("entityId").asText()); + + Event outEvent = events.getData().stream().filter(e -> e.getBody().get("type").asText().equals(DataConstants.OUT)).findFirst().get(); + Assert.assertEquals(ruleChain.getFirstRuleNodeId(), outEvent.getEntityId()); + Assert.assertEquals(device.getId().getId().toString(), outEvent.getBody().get("entityId").asText()); + + Assert.assertEquals("serverAttributeValue", outEvent.getBody().get("metadata").get("ss.serverAttributeKey").asText()); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorChain.java b/application/src/test/java/org/thingsboard/server/rules/flow/RuleEngineFlowSqlIntegrationTest.java similarity index 64% rename from application/src/main/java/org/thingsboard/server/actors/rule/RuleActorChain.java rename to application/src/test/java/org/thingsboard/server/rules/flow/RuleEngineFlowSqlIntegrationTest.java index 3f3bd36f65..18a164ef33 100644 --- a/application/src/main/java/org/thingsboard/server/actors/rule/RuleActorChain.java +++ b/application/src/test/java/org/thingsboard/server/rules/flow/RuleEngineFlowSqlIntegrationTest.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.actors.rule; +package org.thingsboard.server.rules.flow; -public interface RuleActorChain { - - int size(); - - RuleActorMetaData getRuleActorMd(int index); +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcIntegrationTest; +/** + * Created by Valerii Sosliuk on 8/22/2017. + */ +@DaoSqlTest +public class RuleEngineFlowSqlIntegrationTest extends AbstractRuleEngineFlowIntegrationTest { } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java index 5624ed801f..659a242882 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java @@ -37,9 +37,12 @@ public class DataConstants { public static final String ERROR = "ERROR"; public static final String LC_EVENT = "LC_EVENT"; public static final String STATS = "STATS"; - public static final String RULE_CHAIN_DEBUG = "DEBUG_RULE_CHAIN"; - public static final String RULE_NODE_DEBUG = "DEBUG_RULE_NODE"; + public static final String DEBUG = "DEBUG"; public static final String ONEWAY = "ONEWAY"; public static final String TWOWAY = "TWOWAY"; + + public static final String IN = "IN"; + public static final String OUT = "OUT"; + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java index ab6accaf11..a1030640cb 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentType.java @@ -20,6 +20,6 @@ package org.thingsboard.server.common.data.plugin; */ public enum ComponentType { - ENRICHMENT, FILTER, PROCESSOR, TRANSFORMATION, ACTION, PLUGIN + ENRICHMENT, FILTER, TRANSFORMATION, ACTION, OLD_ACTION, PLUGIN } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java index f2ba0cc66e..218061adb1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java @@ -38,6 +38,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo im private String name; private RuleNodeId firstRuleNodeId; private boolean root; + private boolean debugMode; private transient JsonNode configuration; @JsonIgnore private byte[] configurationBytes; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java index d044000117..fbc1103dee 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleNode.java @@ -34,6 +34,7 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo impl private String type; private String name; + private boolean debugMode; private transient JsonNode configuration; @JsonIgnore private byte[] configurationBytes; diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java index 22fc4285a9..7c00ee64ab 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/MsgType.java @@ -1,3 +1,18 @@ +/** + * 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.common.msg; /** @@ -34,4 +49,9 @@ public enum MsgType { */ RULE_TO_RULE_CHAIN_TELL_NEXT_MSG, + /** + * Message that is sent by RuleActor implementation to RuleActor itself to log the error. + */ + RULE_TO_SELF_ERROR_MSG, + } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbActorMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbActorMsg.java index e7668ff227..c361c11c0e 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbActorMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbActorMsg.java @@ -1,3 +1,18 @@ +/** + * 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.common.msg; /** diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java index c689b24fe8..524cc5fe60 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsg.java @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. @@ -17,6 +17,7 @@ package org.thingsboard.server.common.msg; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import lombok.AllArgsConstructor; import lombok.Data; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -30,6 +31,7 @@ import java.util.UUID; * Created by ashvayka on 13.01.18. */ @Data +@AllArgsConstructor public final class TbMsg implements Serializable { private final UUID id; @@ -39,6 +41,15 @@ public final class TbMsg implements Serializable { private final TbMsgDataType dataType; private final byte[] data; + public TbMsg(UUID id, String type, EntityId originator, TbMsgMetaData metaData, byte[] data) { + this.id = id; + this.type = type; + this.originator = originator; + this.metaData = metaData; + this.dataType = TbMsgDataType.JSON; + this.data = data; + } + public static ByteBuffer toBytes(TbMsg msg) { MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder(); builder.setId(msg.getId().toString()); @@ -61,9 +72,7 @@ public final class TbMsg implements Serializable { public static TbMsg fromBytes(ByteBuffer buffer) { try { MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(buffer.array()); - TbMsgMetaData metaData = new TbMsgMetaData(); - metaData.setData(proto.getMetaData().getDataMap()); - + TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); EntityId entityId = EntityIdFactory.getByTypeAndId(proto.getEntityType(), proto.getEntityId()); TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, dataType, proto.getData().toByteArray()); @@ -71,4 +80,11 @@ public final class TbMsg implements Serializable { throw new IllegalStateException("Could not parse protobuf for TbMsg", e); } } + + public TbMsg copy() { + int dataSize = data.length; + byte[] dataCopy = new byte[dataSize]; + System.arraycopy( data, 0, dataCopy, 0, data.length ); + return new TbMsg(id, type, originator, metaData.copy(), dataType, dataCopy); + } } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgDataType.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgDataType.java index b6e2d5a5c5..2e367e9536 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgDataType.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgDataType.java @@ -1,3 +1,18 @@ +/** + * 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.common.msg; /** diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java index 1bbc7929e2..74a2d3f9c7 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/TbMsgMetaData.java @@ -1,12 +1,12 @@ /** * 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 - * + *

+ * 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. @@ -15,9 +15,12 @@ */ package org.thingsboard.server.common.msg; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -25,10 +28,15 @@ import java.util.concurrent.ConcurrentHashMap; * Created by ashvayka on 13.01.18. */ @Data +@NoArgsConstructor public final class TbMsgMetaData implements Serializable { private Map data = new ConcurrentHashMap<>(); + TbMsgMetaData(Map data) { + this.data = data; + } + public String getValue(String key) { return data.get(key); } @@ -37,4 +45,7 @@ public final class TbMsgMetaData implements Serializable { data.put(key, value); } + public TbMsgMetaData copy() { + return new TbMsgMetaData(new ConcurrentHashMap<>(data)); + } } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java index 315eb86f6c..c104281ffe 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java @@ -1,12 +1,12 @@ /** * 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 - *

+ * + * 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. diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/system/ServiceToRuleEngineMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/system/ServiceToRuleEngineMsg.java index 3d82033b31..0792b63c28 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/system/ServiceToRuleEngineMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/system/ServiceToRuleEngineMsg.java @@ -1,3 +1,18 @@ +/** + * 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.common.msg.system; import lombok.Data; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index a159b9e6ec..8c34cd3540 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -332,6 +332,8 @@ public class ModelConstants { public static final String EVENT_BY_TYPE_AND_ID_VIEW_NAME = "event_by_type_and_id"; public static final String EVENT_BY_ID_VIEW_NAME = "event_by_id"; + public static final String DEBUG_MODE = "debug_mode"; + /** * Cassandra rule chain constants. */ diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleChainEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleChainEntity.java index 34659a83df..bfec3900a7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleChainEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleChainEntity.java @@ -1,12 +1,12 @@ /** * 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 - * + *

+ * 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. @@ -22,6 +22,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey; import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.databind.JsonNode; import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; import lombok.ToString; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; @@ -54,6 +56,10 @@ public class RuleChainEntity implements SearchTextEntity { private UUID firstRuleNodeId; @Column(name = RULE_CHAIN_ROOT_PROPERTY) private boolean root; + @Getter + @Setter + @Column(name = DEBUG_MODE) + private boolean debugMode; @Column(name = RULE_CHAIN_CONFIGURATION_PROPERTY, codec = JsonCodec.class) private JsonNode configuration; @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) @@ -71,6 +77,7 @@ public class RuleChainEntity implements SearchTextEntity { this.searchText = ruleChain.getName(); this.firstRuleNodeId = DaoUtil.getId(ruleChain.getFirstRuleNodeId()); this.root = ruleChain.isRoot(); + this.debugMode = ruleChain.isDebugMode(); this.configuration = ruleChain.getConfiguration(); this.additionalInfo = ruleChain.getAdditionalInfo(); } @@ -157,6 +164,7 @@ public class RuleChainEntity implements SearchTextEntity { ruleChain.setFirstRuleNodeId(new RuleNodeId(this.firstRuleNodeId)); } ruleChain.setRoot(this.root); + ruleChain.setDebugMode(this.debugMode); ruleChain.setConfiguration(this.configuration); ruleChain.setAdditionalInfo(this.additionalInfo); return ruleChain; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleNodeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleNodeEntity.java index ba96e4b98e..8d3f3c3eaf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleNodeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/RuleNodeEntity.java @@ -21,6 +21,8 @@ import com.datastax.driver.mapping.annotations.PartitionKey; import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.databind.JsonNode; import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; import lombok.ToString; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.rule.RuleNode; @@ -49,6 +51,11 @@ public class RuleNodeEntity implements SearchTextEntity { private JsonNode configuration; @Column(name = ADDITIONAL_INFO_PROPERTY, codec = JsonCodec.class) private JsonNode additionalInfo; + @Getter + @Setter + @Column(name = DEBUG_MODE) + private boolean debugMode; + public RuleNodeEntity() { } @@ -59,6 +66,7 @@ public class RuleNodeEntity implements SearchTextEntity { } this.type = ruleNode.getType(); this.name = ruleNode.getName(); + this.debugMode = ruleNode.isDebugMode(); this.searchText = ruleNode.getName(); this.configuration = ruleNode.getConfiguration(); this.additionalInfo = ruleNode.getAdditionalInfo(); @@ -126,6 +134,7 @@ public class RuleNodeEntity implements SearchTextEntity { ruleNode.setCreatedTime(UUIDs.unixTimestamp(id)); ruleNode.setType(this.type); ruleNode.setName(this.name); + ruleNode.setDebugMode(this.debugMode); ruleNode.setConfiguration(this.configuration); ruleNode.setAdditionalInfo(this.additionalInfo); return ruleNode; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java index 471ec7b06b..a48421a96a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainEntity.java @@ -58,6 +58,9 @@ public class RuleChainEntity extends BaseSqlEntity implements SearchT @Column(name = ModelConstants.RULE_CHAIN_ROOT_PROPERTY) private boolean root; + @Column(name = ModelConstants.DEBUG_MODE) + private boolean debugMode; + @Type(type = "json") @Column(name = ModelConstants.RULE_CHAIN_CONFIGURATION_PROPERTY) private JsonNode configuration; @@ -80,6 +83,7 @@ public class RuleChainEntity extends BaseSqlEntity implements SearchT this.firstRuleNodeId = UUIDConverter.fromTimeUUID(ruleChain.getFirstRuleNodeId().getId()); } this.root = ruleChain.isRoot(); + this.debugMode = ruleChain.isDebugMode(); this.configuration = ruleChain.getConfiguration(); this.additionalInfo = ruleChain.getAdditionalInfo(); } @@ -104,6 +108,7 @@ public class RuleChainEntity extends BaseSqlEntity implements SearchT ruleChain.setFirstRuleNodeId(new RuleNodeId(UUIDConverter.fromString(firstRuleNodeId))); } ruleChain.setRoot(root); + ruleChain.setDebugMode(debugMode); ruleChain.setConfiguration(configuration); ruleChain.setAdditionalInfo(additionalInfo); return ruleChain; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java index d96048756c..6a888c2d72 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeEntity.java @@ -56,6 +56,9 @@ public class RuleNodeEntity extends BaseSqlEntity implements SearchTex @Column(name = ModelConstants.ADDITIONAL_INFO_PROPERTY) private JsonNode additionalInfo; + @Column(name = ModelConstants.DEBUG_MODE) + private boolean debugMode; + public RuleNodeEntity() { } @@ -65,6 +68,7 @@ public class RuleNodeEntity extends BaseSqlEntity implements SearchTex } this.type = ruleNode.getType(); this.name = ruleNode.getName(); + this.debugMode = ruleNode.isDebugMode(); this.searchText = ruleNode.getName(); this.configuration = ruleNode.getConfiguration(); this.additionalInfo = ruleNode.getAdditionalInfo(); @@ -86,6 +90,7 @@ public class RuleNodeEntity extends BaseSqlEntity implements SearchTex ruleNode.setCreatedTime(UUIDs.unixTimestamp(getId())); ruleNode.setType(type); ruleNode.setName(name); + ruleNode.setDebugMode(debugMode); ruleNode.setConfiguration(configuration); ruleNode.setAdditionalInfo(additionalInfo); return ruleNode; diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/QueueBenchmark.java b/dao/src/main/java/org/thingsboard/server/dao/queue/QueueBenchmark.java index da991fa97d..bb76b97b18 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/QueueBenchmark.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/QueueBenchmark.java @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import javax.annotation.Nullable; @@ -125,7 +126,7 @@ public class QueueBenchmark implements CommandLineRunner { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("key", "value"); String dataStr = "someContent"; - return new TbMsg(UUIDs.timeBased(), "type", null, metaData, dataStr.getBytes()); + return new TbMsg(UUIDs.timeBased(), "type", null, metaData, TbMsgDataType.JSON, dataStr.getBytes()); } @Bean diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 04207ec2f5..3daed33045 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -219,6 +219,12 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return ruleChainDao.findById(ruleChainId.getId()); } + @Override + public RuleNode findRuleNodeById(RuleNodeId ruleNodeId) { + Validator.validateId(ruleNodeId, "Incorrect rule node id for search request."); + return ruleNodeDao.findById(ruleNodeId.getId()); + } + @Override public ListenableFuture findRuleChainByIdAsync(RuleChainId ruleChainId) { Validator.validateId(ruleChainId, "Incorrect rule chain id for search request."); @@ -325,7 +331,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } if (ruleChain.isRoot()) { RuleChain rootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId()); - if (ruleChain.getId() == null || !ruleChain.getId().equals(rootRuleChain.getId())) { + if (rootRuleChain != null && !rootRuleChain.getId().equals(ruleChain.getId())) { throw new DataValidationException("Another root rule chain is present in scope of current tenant!"); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index e5f2840b8b..da7833d696 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -42,6 +42,8 @@ public interface RuleChainService { RuleChain findRuleChainById(RuleChainId ruleChainId); + RuleNode findRuleNodeById(RuleNodeId ruleNodeId); + ListenableFuture findRuleChainByIdAsync(RuleChainId ruleChainId); RuleChain getRootTenantRuleChain(TenantId tenantId); diff --git a/dao/src/main/resources/cassandra/schema.cql b/dao/src/main/resources/cassandra/schema.cql index 42c13f3ee6..d0e62b2827 100644 --- a/dao/src/main/resources/cassandra/schema.cql +++ b/dao/src/main/resources/cassandra/schema.cql @@ -669,6 +669,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) @@ -685,6 +686,7 @@ 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, diff --git a/dao/src/main/resources/sql/schema.sql b/dao/src/main/resources/sql/schema.sql index 106204ab64..d7a0978140 100644 --- a/dao/src/main/resources/sql/schema.sql +++ b/dao/src/main/resources/sql/schema.sql @@ -263,6 +263,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) ); @@ -273,5 +274,6 @@ CREATE TABLE IF NOT EXISTS rule_node ( configuration varchar(10000000), type varchar(255), name varchar(255), + debug_mode boolean, search_text varchar(255) ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java index d083a90262..44a1a0927b 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AbstractServiceTest.java @@ -217,10 +217,10 @@ public abstract class AbstractServiceTest { ruleMetaData.setWeight(weight); ruleMetaData.setPluginToken(pluginToken); - ruleMetaData.setAction(createNode(ComponentScope.TENANT, ComponentType.ACTION, + ruleMetaData.setAction(createNode(ComponentScope.TENANT, ComponentType.OLD_ACTION, "org.thingsboard.component.ActionTest", "TestJsonDescriptor.json", "TestJsonData.json")); - ruleMetaData.setProcessor(createNode(ComponentScope.TENANT, ComponentType.PROCESSOR, - "org.thingsboard.component.ProcessorTest", "TestJsonDescriptor.json", "TestJsonData.json")); +// ruleMetaData.setProcessor(createNode(ComponentScope.TENANT, ComponentType.PROCESSOR, +// "org.thingsboard.component.ProcessorTest", "TestJsonDescriptor.json", "TestJsonData.json")); ruleMetaData.setFilters(mapper.createArrayNode().add( createNode(ComponentScope.TENANT, ComponentType.FILTER, "org.thingsboard.component.FilterTest", "TestJsonDescriptor.json", "TestJsonData.json") diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/UnprocessedMsgFilterTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/UnprocessedMsgFilterTest.java index 6302e63f89..3935c9b92e 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/UnprocessedMsgFilterTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/UnprocessedMsgFilterTest.java @@ -33,8 +33,8 @@ public class UnprocessedMsgFilterTest { public void acknowledgedMsgsAreFilteredOut() { UUID id1 = UUID.randomUUID(); UUID id2 = UUID.randomUUID(); - TbMsg msg1 = new TbMsg(id1, "T", null, null, null); - TbMsg msg2 = new TbMsg(id2, "T", null, null, null); + TbMsg msg1 = new TbMsg(id1, "T", null, null, null, null); + TbMsg msg2 = new TbMsg(id2, "T", null, null, null, null); List msgs = Lists.newArrayList(msg1, msg2); List acks = Lists.newArrayList(new MsgAck(id2, UUID.randomUUID(), 1L, 1L)); Collection actual = msgFilter.filter(msgs, acks); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/repository/impl/CassandraMsgRepositoryTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/repository/impl/CassandraMsgRepositoryTest.java index d17e1f2819..99c6a91f84 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/repository/impl/CassandraMsgRepositoryTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/queue/cassandra/repository/impl/CassandraMsgRepositoryTest.java @@ -24,6 +24,7 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.dao.service.AbstractServiceTest; import org.thingsboard.server.dao.service.DaoNoSqlTest; @@ -44,7 +45,7 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest { @Test public void msgCanBeSavedAndRead() throws ExecutionException, InterruptedException { - TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, new byte[4]); + TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, new byte[4]); UUID nodeId = UUIDs.timeBased(); ListenableFuture future = msgRepository.save(msg, nodeId, 1L, 1L, 1L); future.get(); @@ -54,7 +55,7 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest { @Test public void expiredMsgsAreNotReturned() throws ExecutionException, InterruptedException { - TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, new byte[4]); + TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), null, TbMsgDataType.JSON, new byte[4]); UUID nodeId = UUIDs.timeBased(); ListenableFuture future = msgRepository.save(msg, nodeId, 2L, 2L, 2L); future.get(); @@ -67,7 +68,7 @@ public class CassandraMsgRepositoryTest extends AbstractServiceTest { TbMsgMetaData metaData = new TbMsgMetaData(); metaData.putValue("key", "value"); String dataStr = "someContent"; - TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), metaData, dataStr.getBytes()); + TbMsg msg = new TbMsg(UUIDs.timeBased(), "type", new DeviceId(UUIDs.timeBased()), metaData, TbMsgDataType.JSON, dataStr.getBytes()); UUID nodeId = UUIDs.timeBased(); ListenableFuture future = msgRepository.save(msg, nodeId, 1L, 1L, 1L); future.get(); diff --git a/pom.xml b/pom.xml index f331e32fb2..f0c915a5b0 100755 --- a/pom.xml +++ b/pom.xml @@ -378,6 +378,11 @@ rule-engine-api ${project.version} + + org.thingsboard.rule-engine + rule-engine-components + ${project.version} + org.thingsboard.common message diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java new file mode 100644 index 0000000000..64e28f1bf2 --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java @@ -0,0 +1,43 @@ +/** + * 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.rule.engine.api; + +import org.thingsboard.server.common.data.plugin.ComponentScope; +import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Andrew Shvayka + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ActionNode { + + String name(); + + ComponentScope scope() default ComponentScope.TENANT; + + String descriptor() default "EmptyNodeDescriptor.json"; + + String[] relationTypes() default {"Success","Failure"}; + + boolean customRelations() default false; + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java new file mode 100644 index 0000000000..2267bdae67 --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java @@ -0,0 +1,42 @@ +/** + * 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.rule.engine.api; + +import org.thingsboard.server.common.data.plugin.ComponentScope; +import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Andrew Shvayka + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface EnrichmentNode { + + String name(); + + ComponentScope scope() default ComponentScope.TENANT; + + String descriptor() default "EmptyNodeDescriptor.json"; + + String[] relationTypes() default {"Success","Failure"}; + + boolean customRelations() default false; +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/FilterNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/FilterNode.java new file mode 100644 index 0000000000..5247e397dd --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/FilterNode.java @@ -0,0 +1,43 @@ +/** + * 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.rule.engine.api; + +import org.thingsboard.server.common.data.plugin.ComponentScope; +import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Andrew Shvayka + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FilterNode { + + String name(); + + ComponentScope scope() default ComponentScope.TENANT; + + String descriptor() default "EmptyNodeDescriptor.json"; + + String[] relationTypes() default {"Success","Failure"}; + + boolean customRelations() default false; + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index ede076be4a..a105d20ada 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -58,8 +58,6 @@ public interface TbContext { UserService getUserService(); - RuleService getRuleService(); - PluginService getPluginService(); AssetService getAssetService(); diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java index d06c0d277b..64053cd61c 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeConfiguration.java @@ -22,8 +22,8 @@ import lombok.Data; * Created by ashvayka on 19.01.18. */ @Data -public class TbNodeConfiguration { +public final class TbNodeConfiguration { - private JsonNode data; + private final JsonNode data; } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java index c48b11d387..2c77a69ba3 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbNodeState.java @@ -18,5 +18,5 @@ package org.thingsboard.rule.engine.api; /** * Created by ashvayka on 19.01.18. */ -public class TbNodeState { +public final class TbNodeState { } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java new file mode 100644 index 0000000000..bfe1dcaeda --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java @@ -0,0 +1,43 @@ +/** + * 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.rule.engine.api; + +import org.thingsboard.server.common.data.plugin.ComponentScope; +import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Andrew Shvayka + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface TransformationNode { + + String name(); + + ComponentScope scope() default ComponentScope.TENANT; + + String descriptor() default "EmptyNodeDescriptor.json"; + + String[] relationTypes() default {"Success","Failure"}; + + boolean customRelations() default false; + +} diff --git a/rule-engine/rule-engine-api/src/main/resources/EmptyNodeDescriptor.json b/rule-engine/rule-engine-api/src/main/resources/EmptyNodeDescriptor.json new file mode 100644 index 0000000000..7a73a41bfd --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/resources/EmptyNodeDescriptor.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index 9b903b1b00..a97493bdd7 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -88,11 +88,6 @@ mockito-all test - - org.junit.jupiter - junit-jupiter-api - RELEASE - diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 4d41921740..ac12f95eab 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -1,12 +1,12 @@ /** * 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 - * + *

+ * 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. @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.base.Function; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -33,6 +34,7 @@ import static org.thingsboard.server.common.data.DataConstants.*; * Created by ashvayka on 19.01.18. */ @Slf4j +@EnrichmentNode(name = "Get Attributes Node") public class TbGetAttributesNode implements TbNode { private TbGetAttributesNodeConfiguration config; @@ -52,14 +54,20 @@ public class TbGetAttributesNode implements TbNode { withCallback(future, i -> ctx.tellNext(msg), t -> ctx.tellError(msg, t)); } - private ListenableFuture putAttributesAsync(TbMsg msg, List attributes, String prefix) { - attributes.forEach(r -> msg.getMetaData().putValue(prefix + r.getKey(), r.getValueAsString())); - return Futures.immediateFuture(null); + private Void putAttributesAsync(TbMsg msg, List attributes, String prefix) { + if (attributes != null) { + attributes.forEach(r -> msg.getMetaData().putValue(prefix + r.getKey(), r.getValueAsString())); + } + return null; } private ListenableFuture putAttrAsync(TbContext ctx, TbMsg msg, String scope, List attributes, String prefix) { - return Futures.transform(ctx.getAttributesService().find(msg.getOriginator(), scope, attributes), - (AsyncFunction, Void>) i -> putAttributesAsync(msg, i, prefix)); + if (attributes != null) { + return Futures.transform(ctx.getAttributesService().find(msg.getOriginator(), scope, attributes), + (Function, Void>) i -> putAttributesAsync(msg, i, prefix)); + } else { + return Futures.immediateFuture(null); + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index 57f9b79e7b..2e3d6172fa 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -18,11 +18,13 @@ package org.thingsboard.rule.engine.metadata; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.rule.engine.api.EnrichmentNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.id.*; +@EnrichmentNode(name="Get Customer Attributes Node") public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode { @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index 5823c181de..83aa4e2c17 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -20,10 +20,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.apache.commons.collections.CollectionUtils; import org.thingsboard.rule.engine.TbNodeUtils; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbNodeState; +import org.thingsboard.rule.engine.api.*; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntitySearchDirection; @@ -33,6 +30,7 @@ import java.util.List; import static org.thingsboard.server.common.data.relation.RelationTypeGroup.COMMON; +@EnrichmentNode(name="Get Related Entity Attributes Node") public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode { private TbGetRelatedAttrNodeConfiguration config; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index 2cf9a97d20..a1b05162dc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EnrichmentNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.HasTenantId; @@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.alarm.AlarmId; import org.thingsboard.server.common.data.id.*; @Slf4j +@EnrichmentNode(name="Get Tenant Attributes Node") public class TbGetTenantAttributeNode extends TbEntityGetAttrNode { @Override @@ -38,8 +40,6 @@ public class TbGetTenantAttributeNode extends TbEntityGetAttrNode { return getTenantAsync(ctx.getCustomerService().findCustomerByIdAsync((CustomerId) originator)); case USER: return getTenantAsync(ctx.getUserService().findUserByIdAsync((UserId) originator)); - case RULE: - return getTenantAsync(ctx.getRuleService().findRuleByIdAsync((RuleId) originator)); case PLUGIN: return getTenantAsync(ctx.getPluginService().findPluginByIdAsync((PluginId) originator)); case ASSET: diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java index 8e5ddb8069..ad40f03006 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNodeTest.java @@ -85,8 +85,7 @@ public class TbGetCustomerAttributeNodeTest { config.setAttrMapping(attrMapping); config.setTelemetry(false); ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(); - nodeConfiguration.setData(mapper.valueToTree(config)); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); node = new TbGetCustomerAttributeNode(); node.init(nodeConfiguration, null); @@ -224,8 +223,7 @@ public class TbGetCustomerAttributeNodeTest { config.setAttrMapping(attrMapping); config.setTelemetry(true); ObjectMapper mapper = new ObjectMapper(); - TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(); - nodeConfiguration.setData(mapper.valueToTree(config)); + TbNodeConfiguration nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config)); node = new TbGetCustomerAttributeNode(); node.init(nodeConfiguration, null);