From 792452a3b55e7a52d6bcc3086c687f1163534ca2 Mon Sep 17 00:00:00 2001 From: Yuriy Lytvynchuk Date: Fri, 20 Jan 2023 16:24:43 +0200 Subject: [PATCH 1/5] new nodes: 1. "asset type switch" 2. "device type switch" --- .../filter/TbAbstractTypeSwitchNode.java | 49 +++++++ .../engine/filter/TbAssetTypeSwitchNode.java | 47 +++++++ .../engine/filter/TbDeviceTypeSwitchNode.java | 47 +++++++ .../filter/TbOriginatorTypeFilterNode.java | 4 +- .../filter/TbOriginatorTypeSwitchNode.java | 4 +- .../filter/TbAssetTypeSwitchNodeTest.java | 122 ++++++++++++++++++ .../filter/TbDeviceTypeSwitchNodeTest.java | 122 ++++++++++++++++++ 7 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java create mode 100644 rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java new file mode 100644 index 0000000000..7fa1b12db4 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java @@ -0,0 +1,49 @@ +/** + * Copyright © 2016-2022 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.filter; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.msg.TbMsg; + +@Slf4j +public abstract class TbAbstractTypeSwitchNode implements TbNode { + + protected EmptyNodeConfiguration config; + + @Override + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { + this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class); + } + + @Override + public void onMsg(TbContext ctx, TbMsg msg) { + ctx.tellNext(msg, getRelationType(ctx, msg.getOriginator())); + } + + @Override + public void destroy() { + } + + protected abstract String getRelationType(TbContext ctx, EntityId originator); + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java new file mode 100644 index 0000000000..95d4918449 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java @@ -0,0 +1,47 @@ +/** + * Copyright © 2016-2022 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.filter; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.plugin.ComponentType; + +@Slf4j +@RuleNode( + type = ComponentType.FILTER, + name = "asset type switch", + customRelations = true, + relationTypes = {}, + configClazz = EmptyNodeConfiguration.class, + nodeDescription = "Route incoming messages by Asset Type", + nodeDetails = "Routes messages to chain according to the asset type", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbNodeEmptyConfig") +public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode { + + protected String getRelationType(TbContext ctx, EntityId originator) { + if (!EntityType.ASSET.equals(originator.getEntityType())) { + throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"); + } + return ctx.getAssetProfileCache().get(ctx.getTenantId(), (AssetId) originator).getName(); + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java new file mode 100644 index 0000000000..5998b777a6 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java @@ -0,0 +1,47 @@ +/** + * Copyright © 2016-2022 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.filter; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.plugin.ComponentType; + +@Slf4j +@RuleNode( + type = ComponentType.FILTER, + name = "device type switch", + customRelations = true, + relationTypes = {}, + configClazz = EmptyNodeConfiguration.class, + nodeDescription = "Route incoming messages by Device Type", + nodeDetails = "Routes messages to chain according to the device type", + uiResources = {"static/rulenode/rulenode-core-config.js"}, + configDirective = "tbNodeEmptyConfig") +public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode { + + protected String getRelationType(TbContext ctx, EntityId originator) { + if (!EntityType.DEVICE.equals(originator.getEntityType())) { + throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"); + } + return ctx.getDeviceProfileCache().get(ctx.getTenantId(), (DeviceId) originator).getName(); + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java index 10ccc77dc1..ef15b0abe6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeFilterNode.java @@ -29,11 +29,11 @@ import org.thingsboard.server.common.msg.TbMsg; @Slf4j @RuleNode( type = ComponentType.FILTER, - name = "originator type", + name = "entity type", configClazz = TbOriginatorTypeFilterNodeConfiguration.class, relationTypes = {"True", "False"}, nodeDescription = "Filter incoming messages by message Originator Type", - nodeDetails = "If Originator Type of incoming message is expected - send Message via True chain, otherwise False chain is used.", + nodeDetails = "If the entity type of the incoming message originator is expected - send Message via True chain, otherwise False chain is used.", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbFilterNodeOriginatorTypeConfig") public class TbOriginatorTypeFilterNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java index e5c06c3878..eb444b097a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java @@ -30,11 +30,11 @@ import org.thingsboard.server.common.msg.TbMsg; @Slf4j @RuleNode( type = ComponentType.FILTER, - name = "originator type switch", + name = "entity type switch", configClazz = EmptyNodeConfiguration.class, relationTypes = {"Device", "Asset", "Alarm", "Entity View", "Tenant", "Customer", "User", "Dashboard", "Rule chain", "Rule node"}, nodeDescription = "Route incoming messages by Message Originator Type", - nodeDetails = "Routes messages to chain according to the originator type ('Device', 'Asset', etc.).", + nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbOriginatorTypeSwitchNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java new file mode 100644 index 0000000000..779d34b437 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -0,0 +1,122 @@ +/** + * Copyright © 2016-2022 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.filter; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleEngineAssetProfileCache; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.asset.AssetProfile; +import org.thingsboard.server.common.data.id.AssetId; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class TbAssetTypeSwitchNodeTest { + + TenantId tenantId; + AssetId assetId; + AssetProfile assetProfile; + TbContext ctx; + TbAssetTypeSwitchNode node; + EmptyNodeConfiguration config; + TbMsgCallback callback; + RuleEngineAssetProfileCache assetProfileCache; + + @BeforeEach + void setUp() throws TbNodeException { + tenantId = new TenantId(UUID.randomUUID()); + assetId = new AssetId(UUID.randomUUID()); + + assetProfile = new AssetProfile(); + assetProfile.setTenantId(tenantId); + assetProfile.setName("TestAssetProfile"); + + //node + config = new EmptyNodeConfiguration(); + node = spy(new TbAssetTypeSwitchNode()); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + //init mock + ctx = mock(TbContext.class); + assetProfileCache = mock(RuleEngineAssetProfileCache.class); + callback = mock(TbMsgCallback.class); + + when(ctx.getTenantId()).thenReturn(tenantId); + when(ctx.getAssetProfileCache()).thenReturn(assetProfileCache); + + doReturn(assetProfile).when(assetProfileCache).get(tenantId, assetId); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenMsg_whenOnMsg_then_Fail() { + CustomerId customerId = new CustomerId(UUID.randomUUID()); + assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId, "{}"))).isInstanceOf(RuntimeException.class); + } + + @Test + void givenMsg_whenOnMsg_then_Success() { + TbMsg msg = getTbMsg(assetId, "{}"); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq("TestAssetProfile")); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + private TbMsg getTbMsg(EntityId entityId, String data) { + final Map mdMap = Map.of( + "TestKey_1", "Test", + "country", "US", + "voltageDataValue", "220", + "city", "NY" + ); + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + } +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java new file mode 100644 index 0000000000..20e0750cf2 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java @@ -0,0 +1,122 @@ +/** + * Copyright © 2016-2022 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.filter; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; +import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; + +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class TbDeviceTypeSwitchNodeTest { + + TenantId tenantId; + DeviceId deviceId; + DeviceProfile deviceProfile; + TbContext ctx; + TbDeviceTypeSwitchNode node; + EmptyNodeConfiguration config; + TbMsgCallback callback; + RuleEngineDeviceProfileCache deviceProfileCache; + + @BeforeEach + void setUp() throws TbNodeException { + tenantId = new TenantId(UUID.randomUUID()); + deviceId = new DeviceId(UUID.randomUUID()); + + deviceProfile = new DeviceProfile(); + deviceProfile.setTenantId(tenantId); + deviceProfile.setName("TestDeviceProfile"); + + //node + config = new EmptyNodeConfiguration(); + node = spy(new TbDeviceTypeSwitchNode()); + node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); + + //init mock + ctx = mock(TbContext.class); + deviceProfileCache = mock(RuleEngineDeviceProfileCache.class); + callback = mock(TbMsgCallback.class); + + when(ctx.getTenantId()).thenReturn(tenantId); + when(ctx.getDeviceProfileCache()).thenReturn(deviceProfileCache); + + doReturn(deviceProfile).when(deviceProfileCache).get(tenantId, deviceId); + } + + @AfterEach + void tearDown() { + node.destroy(); + } + + @Test + void givenMsg_whenOnMsg_then_Fail() { + CustomerId customerId = new CustomerId(UUID.randomUUID()); + assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId, "{}"))).isInstanceOf(RuntimeException.class); + } + + @Test + void givenMsg_whenOnMsg_then_Success() { + TbMsg msg = getTbMsg(deviceId, "{}"); + node.onMsg(ctx, msg); + + ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, times(1)).tellNext(newMsgCaptor.capture(), eq("TestDeviceProfile")); + verify(ctx, never()).tellFailure(any(), any()); + + TbMsg newMsg = newMsgCaptor.getValue(); + assertThat(newMsg).isNotNull(); + assertThat(newMsg).isSameAs(msg); + } + + private TbMsg getTbMsg(EntityId entityId, String data) { + final Map mdMap = Map.of( + "TestKey_1", "Test", + "country", "US", + "voltageDataValue", "220", + "city", "NY" + ); + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + } +} From b7dd23157dcea78c5a2be5164d209ead101ee221 Mon Sep 17 00:00:00 2001 From: Yuriy Lytvynchuk Date: Mon, 23 Jan 2023 12:24:48 +0200 Subject: [PATCH 2/5] code rewiev --- .../filter/TbAbstractTypeSwitchNode.java | 2 +- .../engine/filter/TbAssetTypeSwitchNode.java | 7 ++++- .../engine/filter/TbDeviceTypeSwitchNode.java | 7 ++++- .../filter/TbAssetTypeSwitchNodeTest.java | 26 +++++++++---------- .../filter/TbDeviceTypeSwitchNodeTest.java | 25 +++++++++--------- 5 files changed, 39 insertions(+), 28 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java index 7fa1b12db4..af5f4884ba 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java @@ -28,7 +28,7 @@ import org.thingsboard.server.common.msg.TbMsg; @Slf4j public abstract class TbAbstractTypeSwitchNode implements TbNode { - protected EmptyNodeConfiguration config; + private EmptyNodeConfiguration config; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java index 95d4918449..3460c3e70f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java @@ -20,6 +20,7 @@ import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; @@ -41,7 +42,11 @@ public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode { if (!EntityType.ASSET.equals(originator.getEntityType())) { throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"); } - return ctx.getAssetProfileCache().get(ctx.getTenantId(), (AssetId) originator).getName(); + AssetProfile assetProfile = ctx.getAssetProfileCache().get(ctx.getTenantId(), (AssetId) originator); + if (assetProfile == null) { + throw new RuntimeException("Asset profile with entity id: " + originator.getId() + " doesn't not found!"); + } + return assetProfile.getName(); } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java index 5998b777a6..b63f98e85f 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; @@ -41,7 +42,11 @@ public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode { if (!EntityType.DEVICE.equals(originator.getEntityType())) { throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"); } - return ctx.getDeviceProfileCache().get(ctx.getTenantId(), (DeviceId) originator).getName(); + DeviceProfile deviceProfile = ctx.getDeviceProfileCache().get(ctx.getTenantId(), (DeviceId) originator); + if (deviceProfile == null) { + throw new RuntimeException("Device profile with entity id: " + originator.getId() + " doesn't not found!"); + } + return deviceProfile.getName(); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java index 779d34b437..d234d77ec4 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; -import java.util.Map; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -44,7 +43,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,6 +51,7 @@ class TbAssetTypeSwitchNodeTest { TenantId tenantId; AssetId assetId; + AssetId assetIdDeleted; AssetProfile assetProfile; TbContext ctx; TbAssetTypeSwitchNode node; @@ -64,6 +63,7 @@ class TbAssetTypeSwitchNodeTest { void setUp() throws TbNodeException { tenantId = new TenantId(UUID.randomUUID()); assetId = new AssetId(UUID.randomUUID()); + assetIdDeleted = new AssetId(UUID.randomUUID()); assetProfile = new AssetProfile(); assetProfile.setTenantId(tenantId); @@ -71,7 +71,7 @@ class TbAssetTypeSwitchNodeTest { //node config = new EmptyNodeConfiguration(); - node = spy(new TbAssetTypeSwitchNode()); + node = new TbAssetTypeSwitchNode(); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); //init mock @@ -83,6 +83,7 @@ class TbAssetTypeSwitchNodeTest { when(ctx.getAssetProfileCache()).thenReturn(assetProfileCache); doReturn(assetProfile).when(assetProfileCache).get(tenantId, assetId); + doReturn(null).when(assetProfileCache).get(tenantId, assetIdDeleted); } @AfterEach @@ -93,12 +94,17 @@ class TbAssetTypeSwitchNodeTest { @Test void givenMsg_whenOnMsg_then_Fail() { CustomerId customerId = new CustomerId(UUID.randomUUID()); - assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId, "{}"))).isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId))).isInstanceOf(RuntimeException.class); + } + + @Test + void givenMsg_whenOnMsg_EntityIdDeleted_then_Fail() { + assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(assetIdDeleted))).isInstanceOf(RuntimeException.class); } @Test void givenMsg_whenOnMsg_then_Success() { - TbMsg msg = getTbMsg(assetId, "{}"); + TbMsg msg = getTbMsg(assetId); node.onMsg(ctx, msg); ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); @@ -110,13 +116,7 @@ class TbAssetTypeSwitchNodeTest { assertThat(newMsg).isSameAs(msg); } - private TbMsg getTbMsg(EntityId entityId, String data) { - final Map mdMap = Map.of( - "TestKey_1", "Test", - "country", "US", - "voltageDataValue", "220", - "city", "NY" - ); - return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + private TbMsg getTbMsg(EntityId entityId) { + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(), "{}", callback); } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java index 20e0750cf2..a7696f903e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java @@ -44,7 +44,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,6 +52,7 @@ class TbDeviceTypeSwitchNodeTest { TenantId tenantId; DeviceId deviceId; + DeviceId deviceIdDeleted; DeviceProfile deviceProfile; TbContext ctx; TbDeviceTypeSwitchNode node; @@ -64,6 +64,7 @@ class TbDeviceTypeSwitchNodeTest { void setUp() throws TbNodeException { tenantId = new TenantId(UUID.randomUUID()); deviceId = new DeviceId(UUID.randomUUID()); + deviceIdDeleted = new DeviceId(UUID.randomUUID()); deviceProfile = new DeviceProfile(); deviceProfile.setTenantId(tenantId); @@ -71,7 +72,7 @@ class TbDeviceTypeSwitchNodeTest { //node config = new EmptyNodeConfiguration(); - node = spy(new TbDeviceTypeSwitchNode()); + node = new TbDeviceTypeSwitchNode(); node.init(ctx, new TbNodeConfiguration(JacksonUtil.valueToTree(config))); //init mock @@ -83,6 +84,7 @@ class TbDeviceTypeSwitchNodeTest { when(ctx.getDeviceProfileCache()).thenReturn(deviceProfileCache); doReturn(deviceProfile).when(deviceProfileCache).get(tenantId, deviceId); + doReturn(null).when(deviceProfileCache).get(tenantId, deviceIdDeleted); } @AfterEach @@ -93,12 +95,17 @@ class TbDeviceTypeSwitchNodeTest { @Test void givenMsg_whenOnMsg_then_Fail() { CustomerId customerId = new CustomerId(UUID.randomUUID()); - assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId, "{}"))).isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId))).isInstanceOf(RuntimeException.class); + } + + @Test + void givenMsg_whenOnMsg_EntityIdDeleted_then_Fail() { + assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(deviceIdDeleted))).isInstanceOf(RuntimeException.class); } @Test void givenMsg_whenOnMsg_then_Success() { - TbMsg msg = getTbMsg(deviceId, "{}"); + TbMsg msg = getTbMsg(deviceId); node.onMsg(ctx, msg); ArgumentCaptor newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class); @@ -110,13 +117,7 @@ class TbDeviceTypeSwitchNodeTest { assertThat(newMsg).isSameAs(msg); } - private TbMsg getTbMsg(EntityId entityId, String data) { - final Map mdMap = Map.of( - "TestKey_1", "Test", - "country", "US", - "voltageDataValue", "220", - "city", "NY" - ); - return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(mdMap), data, callback); + private TbMsg getTbMsg(EntityId entityId) { + return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, new TbMsgMetaData(), "{}", callback); } } From 892cc1a907513ddd56d46372194fc9fece2e8edc Mon Sep 17 00:00:00 2001 From: Yuriy Lytvynchuk Date: Mon, 23 Jan 2023 12:30:48 +0200 Subject: [PATCH 3/5] delete public void destroy --- .../rule/engine/filter/TbAbstractTypeSwitchNode.java | 4 ---- .../thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java | 2 +- .../rule/engine/filter/TbDeviceTypeSwitchNode.java | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java index af5f4884ba..ebc06d8848 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java @@ -40,10 +40,6 @@ public abstract class TbAbstractTypeSwitchNode implements TbNode { ctx.tellNext(msg, getRelationType(ctx, msg.getOriginator())); } - @Override - public void destroy() { - } - protected abstract String getRelationType(TbContext ctx, EntityId originator); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java index 3460c3e70f..e36df41d09 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java @@ -44,7 +44,7 @@ public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode { } AssetProfile assetProfile = ctx.getAssetProfileCache().get(ctx.getTenantId(), (AssetId) originator); if (assetProfile == null) { - throw new RuntimeException("Asset profile with entity id: " + originator.getId() + " doesn't not found!"); + throw new RuntimeException("Asset profile with entity id: " + originator.getId() + " wasn't found!"); } return assetProfile.getName(); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java index b63f98e85f..2adb247a06 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java @@ -44,7 +44,7 @@ public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode { } DeviceProfile deviceProfile = ctx.getDeviceProfileCache().get(ctx.getTenantId(), (DeviceId) originator); if (deviceProfile == null) { - throw new RuntimeException("Device profile with entity id: " + originator.getId() + " doesn't not found!"); + throw new RuntimeException("Device profile with entity id: " + originator.getId() + " wasn't found!"); } return deviceProfile.getName(); } From 0a57fc78dda6621fb8f3e287081fa8804cfa5b1a Mon Sep 17 00:00:00 2001 From: Yuriy Lytvynchuk Date: Mon, 23 Jan 2023 12:36:30 +0200 Subject: [PATCH 4/5] change exception texts --- .../thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java | 4 ++-- .../rule/engine/filter/TbDeviceTypeSwitchNode.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java index e36df41d09..8a9f4ba7eb 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java @@ -40,11 +40,11 @@ public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode { protected String getRelationType(TbContext ctx, EntityId originator) { if (!EntityType.ASSET.equals(originator.getEntityType())) { - throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"); + throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'ASSET' type is allowed."); } AssetProfile assetProfile = ctx.getAssetProfileCache().get(ctx.getTenantId(), (AssetId) originator); if (assetProfile == null) { - throw new RuntimeException("Asset profile with entity id: " + originator.getId() + " wasn't found!"); + throw new RuntimeException("Asset profile for entity id: " + originator.getId() + " wasn't found!"); } return assetProfile.getName(); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java index 2adb247a06..8e15a6b4a2 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java @@ -40,11 +40,11 @@ public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode { protected String getRelationType(TbContext ctx, EntityId originator) { if (!EntityType.DEVICE.equals(originator.getEntityType())) { - throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"); + throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'DEVICE' type is allowed."); } DeviceProfile deviceProfile = ctx.getDeviceProfileCache().get(ctx.getTenantId(), (DeviceId) originator); if (deviceProfile == null) { - throw new RuntimeException("Device profile with entity id: " + originator.getId() + " wasn't found!"); + throw new RuntimeException("Device profile for entity id: " + originator.getId() + " wasn't found!"); } return deviceProfile.getName(); } From 9b05f7adf123f6f23fb5ab9127e878839a751862 Mon Sep 17 00:00:00 2001 From: Yuriy Lytvynchuk Date: Mon, 23 Jan 2023 15:48:21 +0200 Subject: [PATCH 5/5] code review #2 --- .../filter/TbAbstractTypeSwitchNode.java | 4 ++-- .../engine/filter/TbAssetTypeSwitchNode.java | 12 ++++++----- .../engine/filter/TbDeviceTypeSwitchNode.java | 14 +++++++------ .../filter/TbOriginatorTypeSwitchNode.java | 20 +++++-------------- .../filter/TbAssetTypeSwitchNodeTest.java | 10 +++++++--- .../filter/TbDeviceTypeSwitchNodeTest.java | 11 ++++++---- 6 files changed, 36 insertions(+), 35 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java index ebc06d8848..a745b04c99 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAbstractTypeSwitchNode.java @@ -36,10 +36,10 @@ public abstract class TbAbstractTypeSwitchNode implements TbNode { } @Override - public void onMsg(TbContext ctx, TbMsg msg) { + public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { ctx.tellNext(msg, getRelationType(ctx, msg.getOriginator())); } - protected abstract String getRelationType(TbContext ctx, EntityId originator); + protected abstract String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java index 8a9f4ba7eb..1243c9b28e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNode.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.id.AssetId; @@ -32,19 +33,20 @@ import org.thingsboard.server.common.data.plugin.ComponentType; customRelations = true, relationTypes = {}, configClazz = EmptyNodeConfiguration.class, - nodeDescription = "Route incoming messages by Asset Type", - nodeDetails = "Routes messages to chain according to the asset type", + nodeDescription = "Route incoming messages based on the name of the asset profile", + nodeDetails = "Route incoming messages based on the name of the asset profile. The asset profile name is case-sensitive", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbAssetTypeSwitchNode extends TbAbstractTypeSwitchNode { - protected String getRelationType(TbContext ctx, EntityId originator) { + @Override + protected String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException { if (!EntityType.ASSET.equals(originator.getEntityType())) { - throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'ASSET' type is allowed."); + throw new TbNodeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'ASSET' type is allowed."); } AssetProfile assetProfile = ctx.getAssetProfileCache().get(ctx.getTenantId(), (AssetId) originator); if (assetProfile == null) { - throw new RuntimeException("Asset profile for entity id: " + originator.getId() + " wasn't found!"); + throw new TbNodeException("Asset profile for entity id: " + originator.getId() + " wasn't found!"); } return assetProfile.getName(); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java index 8e15a6b4a2..9a2d04d0e3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNode.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; @@ -30,21 +31,22 @@ import org.thingsboard.server.common.data.plugin.ComponentType; type = ComponentType.FILTER, name = "device type switch", customRelations = true, - relationTypes = {}, + relationTypes = {"default"}, configClazz = EmptyNodeConfiguration.class, - nodeDescription = "Route incoming messages by Device Type", - nodeDetails = "Routes messages to chain according to the device type", + nodeDescription = "Route incoming messages based on the name of the device profile", + nodeDetails = "Route incoming messages based on the name of the device profile. The device profile name is case-sensitive", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") public class TbDeviceTypeSwitchNode extends TbAbstractTypeSwitchNode { - protected String getRelationType(TbContext ctx, EntityId originator) { + @Override + protected String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException { if (!EntityType.DEVICE.equals(originator.getEntityType())) { - throw new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'DEVICE' type is allowed."); + throw new TbNodeException("Unsupported originator type: " + originator.getEntityType() + "! Only 'DEVICE' type is allowed."); } DeviceProfile deviceProfile = ctx.getDeviceProfileCache().get(ctx.getTenantId(), (DeviceId) originator); if (deviceProfile == null) { - throw new RuntimeException("Device profile for entity id: " + originator.getId() + " wasn't found!"); + throw new TbNodeException("Device profile for entity id: " + originator.getId() + " wasn't found!"); } return deviceProfile.getName(); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java index eb444b097a..2d1e92f179 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java @@ -19,13 +19,10 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.plugin.ComponentType; -import org.thingsboard.server.common.msg.TbMsg; @Slf4j @RuleNode( @@ -37,19 +34,12 @@ import org.thingsboard.server.common.msg.TbMsg; nodeDetails = "Routes messages to chain according to the entity type ('Device', 'Asset', etc.).", uiResources = {"static/rulenode/rulenode-core-config.js"}, configDirective = "tbNodeEmptyConfig") -public class TbOriginatorTypeSwitchNode implements TbNode { - - EmptyNodeConfiguration config; +public class TbOriginatorTypeSwitchNode extends TbAbstractTypeSwitchNode { @Override - public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { - this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class); - } - - @Override - public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { + protected String getRelationType(TbContext ctx, EntityId originator) throws TbNodeException { String relationType; - EntityType originatorType = msg.getOriginator().getEntityType(); + EntityType originatorType = originator.getEntityType(); switch (originatorType) { case TENANT: relationType = "Tenant"; @@ -87,7 +77,7 @@ public class TbOriginatorTypeSwitchNode implements TbNode { default: throw new TbNodeException("Unsupported originator type: " + originatorType); } - ctx.tellNext(msg, relationType); + return relationType; } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java index d234d77ec4..4747a3c18c 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbAssetTypeSwitchNodeTest.java @@ -94,16 +94,20 @@ class TbAssetTypeSwitchNodeTest { @Test void givenMsg_whenOnMsg_then_Fail() { CustomerId customerId = new CustomerId(UUID.randomUUID()); - assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId))).isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> { + node.onMsg(ctx, getTbMsg(customerId)); + }).isInstanceOf(TbNodeException.class).hasMessageContaining("Unsupported originator type"); } @Test void givenMsg_whenOnMsg_EntityIdDeleted_then_Fail() { - assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(assetIdDeleted))).isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> { + node.onMsg(ctx, getTbMsg(assetIdDeleted)); + }).isInstanceOf(TbNodeException.class).hasMessageContaining("Asset profile for entity id"); } @Test - void givenMsg_whenOnMsg_then_Success() { + void givenMsg_whenOnMsg_then_Success() throws TbNodeException { TbMsg msg = getTbMsg(assetId); node.onMsg(ctx, msg); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java index a7696f903e..ed07a332ca 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/filter/TbDeviceTypeSwitchNodeTest.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.TbMsgCallback; -import java.util.Map; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -95,16 +94,20 @@ class TbDeviceTypeSwitchNodeTest { @Test void givenMsg_whenOnMsg_then_Fail() { CustomerId customerId = new CustomerId(UUID.randomUUID()); - assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(customerId))).isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> { + node.onMsg(ctx, getTbMsg(customerId)); + }).isInstanceOf(TbNodeException.class).hasMessageContaining("Unsupported originator type"); } @Test void givenMsg_whenOnMsg_EntityIdDeleted_then_Fail() { - assertThatThrownBy(() -> node.onMsg(ctx, getTbMsg(deviceIdDeleted))).isInstanceOf(RuntimeException.class); + assertThatThrownBy(() -> { + node.onMsg(ctx, getTbMsg(deviceIdDeleted)); + }).isInstanceOf(TbNodeException.class).hasMessageContaining("Device profile for entity id"); } @Test - void givenMsg_whenOnMsg_then_Success() { + void givenMsg_whenOnMsg_then_Success() throws TbNodeException { TbMsg msg = getTbMsg(deviceId); node.onMsg(ctx, msg);