Browse Source

Merge pull request #6699 from volodymyr-babak/bug/edge-find-missing-related-rulechains

[3.4] Fix validation of missing rule chain during assignment to the edge is broken.
pull/6787/head
Andrew Shvayka 4 years ago
committed by GitHub
parent
commit
34db923d4d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  2. 25
      application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java
  3. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  4. 24
      dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java
  5. 60
      dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java

3
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
@ -557,7 +558,7 @@ public class EdgeController extends BaseController {
edgeId = checkNotNull(edgeId); edgeId = checkNotNull(edgeId);
SecurityUser user = getCurrentUser(); SecurityUser user = getCurrentUser();
TenantId tenantId = user.getTenantId(); TenantId tenantId = user.getTenantId();
return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId); return edgeService.findMissingToRelatedRuleChains(tenantId, edgeId, TbRuleChainInputNode.class.getName());
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

25
application/src/main/java/org/thingsboard/server/service/edge/rpc/constructor/RuleChainMsgConstructor.java

@ -21,7 +21,9 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration; import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
@ -49,9 +51,8 @@ import java.util.stream.Collectors;
@TbCoreComponent @TbCoreComponent
public class RuleChainMsgConstructor { public class RuleChainMsgConstructor {
private static final ObjectMapper objectMapper = new ObjectMapper(); private static final String RULE_CHAIN_INPUT_NODE = TbRuleChainInputNode.class.getName();
private static final String RULE_CHAIN_INPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainInputNode"; private static final String TB_RULE_CHAIN_OUTPUT_NODE = TbRuleChainOutputNode.class.getName();
private static final String TB_RULE_CHAIN_OUTPUT_NODE = "org.thingsboard.rule.engine.flow.TbRuleChainOutputNode";
public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) { public RuleChainUpdateMsg constructRuleChainUpdatedMsg(RuleChainId edgeRootRuleChainId, UpdateMsgType msgType, RuleChain ruleChain) {
RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder() RuleChainUpdateMsg.Builder builder = RuleChainUpdateMsg.newBuilder()
@ -210,13 +211,11 @@ public class RuleChainMsgConstructor {
private List<RuleNode> filterNodes_V_3_3_0(List<RuleNode> nodes) { private List<RuleNode> filterNodes_V_3_3_0(List<RuleNode> nodes) {
List<RuleNode> result = new ArrayList<>(); List<RuleNode> result = new ArrayList<>();
for (RuleNode node : nodes) { for (RuleNode node : nodes) {
switch (node.getType()) { if (RULE_CHAIN_INPUT_NODE.equals(node.getType())
case RULE_CHAIN_INPUT_NODE: || TB_RULE_CHAIN_OUTPUT_NODE.equals(node.getType())) {
case TB_RULE_CHAIN_OUTPUT_NODE: log.trace("Skipping not supported rule node {}", node);
log.trace("Skipping not supported rule node {}", node); } else {
break; result.add(node);
default:
result.add(node);
} }
} }
return result; return result;
@ -280,7 +279,7 @@ public class RuleChainMsgConstructor {
.setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits()) .setTargetRuleChainIdMSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getMostSignificantBits())
.setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits()) .setTargetRuleChainIdLSB(ruleChainConnectionInfo.getTargetRuleChainId().getId().getLeastSignificantBits())
.setType(ruleChainConnectionInfo.getType()) .setType(ruleChainConnectionInfo.getType())
.setAdditionalInfo(objectMapper.writeValueAsString(additionalInfo)) .setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(additionalInfo))
.build(); .build();
} }
@ -291,8 +290,8 @@ public class RuleChainMsgConstructor {
.setType(node.getType()) .setType(node.getType())
.setName(node.getName()) .setName(node.getName())
.setDebugMode(node.isDebugMode()) .setDebugMode(node.isDebugMode())
.setConfiguration(objectMapper.writeValueAsString(node.getConfiguration())) .setConfiguration(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getConfiguration()))
.setAdditionalInfo(objectMapper.writeValueAsString(node.getAdditionalInfo())) .setAdditionalInfo(JacksonUtil.OBJECT_MAPPER.writeValueAsString(node.getAdditionalInfo()))
.build(); .build();
} }

2
common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java

@ -84,5 +84,5 @@ public interface EdgeService {
PageData<EdgeId> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId, PageLink pageLink); PageData<EdgeId> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId, PageLink pageLink);
String findMissingToRelatedRuleChains(TenantId tenantId, EdgeId edgeId); String findMissingToRelatedRuleChains(TenantId tenantId, EdgeId edgeId, String tbRuleChainInputNodeClassName);
} }

24
dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.dao.edge; package org.thingsboard.server.dao.edge;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -27,6 +26,7 @@ import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.event.TransactionalEventListener; import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
@ -46,7 +46,7 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainConnectionInfo; import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.relation.RelationService;
@ -62,6 +62,7 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.thingsboard.server.dao.DaoUtil.toUUIDs; import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
@ -78,8 +79,6 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
public static final String INCORRECT_EDGE_ID = "Incorrect edgeId "; public static final String INCORRECT_EDGE_ID = "Incorrect edgeId ";
private static final ObjectMapper mapper = new ObjectMapper();
private static final int DEFAULT_PAGE_SIZE = 1000; private static final int DEFAULT_PAGE_SIZE = 1000;
@Autowired @Autowired
@ -451,16 +450,19 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
} }
@Override @Override
public String findMissingToRelatedRuleChains(TenantId tenantId, EdgeId edgeId) { public String findMissingToRelatedRuleChains(TenantId tenantId, EdgeId edgeId, String tbRuleChainInputNodeClassName) {
List<RuleChain> edgeRuleChains = findEdgeRuleChains(tenantId, edgeId); List<RuleChain> edgeRuleChains = findEdgeRuleChains(tenantId, edgeId);
List<RuleChainId> edgeRuleChainIds = edgeRuleChains.stream().map(IdBased::getId).collect(Collectors.toList()); List<RuleChainId> edgeRuleChainIds = edgeRuleChains.stream().map(IdBased::getId).collect(Collectors.toList());
ObjectNode result = mapper.createObjectNode(); ObjectNode result = JacksonUtil.OBJECT_MAPPER.createObjectNode();
for (RuleChain edgeRuleChain : edgeRuleChains) { for (RuleChain edgeRuleChain : edgeRuleChains) {
List<RuleChainConnectionInfo> connectionInfos = List<RuleNode> ruleNodes =
ruleChainService.loadRuleChainMetaData(edgeRuleChain.getTenantId(), edgeRuleChain.getId()).getRuleChainConnections(); ruleChainService.loadRuleChainMetaData(edgeRuleChain.getTenantId(), edgeRuleChain.getId()).getNodes();
if (connectionInfos != null && !connectionInfos.isEmpty()) { if (ruleNodes != null && !ruleNodes.isEmpty()) {
List<RuleChainId> connectedRuleChains = List<RuleChainId> connectedRuleChains =
connectionInfos.stream().map(RuleChainConnectionInfo::getTargetRuleChainId).collect(Collectors.toList()); ruleNodes.stream()
.filter(rn -> rn.getType().equals(tbRuleChainInputNodeClassName))
.map(rn -> new RuleChainId(UUID.fromString(rn.getConfiguration().get("ruleChainId").asText())))
.collect(Collectors.toList());
List<String> missingRuleChains = new ArrayList<>(); List<String> missingRuleChains = new ArrayList<>();
for (RuleChainId connectedRuleChain : connectedRuleChains) { for (RuleChainId connectedRuleChain : connectedRuleChains) {
if (!edgeRuleChainIds.contains(connectedRuleChain)) { if (!edgeRuleChainIds.contains(connectedRuleChain)) {
@ -469,7 +471,7 @@ public class EdgeServiceImpl extends AbstractCachedEntityService<EdgeCacheKey, E
} }
} }
if (!missingRuleChains.isEmpty()) { if (!missingRuleChains.isEmpty()) {
ArrayNode array = mapper.createArrayNode(); ArrayNode array = JacksonUtil.OBJECT_MAPPER.createArrayNode();
for (String missingRuleChain : missingRuleChains) { for (String missingRuleChain : missingRuleChains) {
array.add(missingRuleChain); array.add(missingRuleChain);
} }

60
dao/src/test/java/org/thingsboard/server/dao/service/BaseEdgeServiceTest.java

@ -16,11 +16,13 @@
package org.thingsboard.server.dao.service; package org.thingsboard.server.dao.service;
import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
@ -29,9 +31,14 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -602,4 +609,55 @@ public abstract class BaseEdgeServiceTest extends AbstractServiceTest {
edgeService.deleteEdge(tenantId, savedEdge.getId()); edgeService.deleteEdge(tenantId, savedEdge.getId());
} }
} @Test
public void testFindMissingToRelatedRuleChains() {
Edge edge = constructEdge("My edge", "default");
Edge savedEdge = edgeService.saveEdge(edge);
RuleChain ruleChain = new RuleChain();
ruleChain.setTenantId(tenantId);
ruleChain.setName("Rule Chain #1");
ruleChain.setType(RuleChainType.EDGE);
RuleChain ruleChain1 = ruleChainService.saveRuleChain(ruleChain);
ruleChain = new RuleChain();
ruleChain.setTenantId(tenantId);
ruleChain.setName("Rule Chain #2");
ruleChain.setType(RuleChainType.EDGE);
RuleChain ruleChain2 = ruleChainService.saveRuleChain(ruleChain);
ruleChain = new RuleChain();
ruleChain.setTenantId(tenantId);
ruleChain.setName("Rule Chain #3");
ruleChain.setType(RuleChainType.EDGE);
RuleChain ruleChain3 = ruleChainService.saveRuleChain(ruleChain);
RuleNode ruleNode1 = new RuleNode();
ruleNode1.setName("Input rule node 1");
ruleNode1.setType("org.thingsboard.rule.engine.flow.TbRuleChainInputNode");
ObjectNode configuration = JacksonUtil.OBJECT_MAPPER.createObjectNode();
configuration.put("ruleChainId", ruleChain1.getUuidId().toString());
ruleNode1.setConfiguration(configuration);
RuleNode ruleNode2 = new RuleNode();
ruleNode2.setName("Input rule node 2");
ruleNode2.setType("org.thingsboard.rule.engine.flow.TbRuleChainInputNode");
configuration = JacksonUtil.OBJECT_MAPPER.createObjectNode();
configuration.put("ruleChainId", ruleChain2.getUuidId().toString());
ruleNode2.setConfiguration(configuration);
RuleChainMetaData ruleChainMetaData3 = new RuleChainMetaData();
ruleChainMetaData3.setNodes(Arrays.asList(ruleNode1, ruleNode2));
ruleChainMetaData3.setFirstNodeIndex(0);
ruleChainMetaData3.setRuleChainId(ruleChain3.getId());
ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData3);
ruleChainService.assignRuleChainToEdge(tenantId, ruleChain3.getId(), savedEdge.getId());
String missingToRelatedRuleChains = edgeService.findMissingToRelatedRuleChains(tenantId,
savedEdge.getId(),
"org.thingsboard.rule.engine.flow.TbRuleChainInputNode");
Assert.assertEquals("{\"Rule Chain #3\":[\"Rule Chain #1\",\"Rule Chain #2\"]}", missingToRelatedRuleChains);
}
}

Loading…
Cancel
Save