Browse Source

Versioning for rule chain metadata

pull/11496/head
ViacheslavKlimov 2 years ago
parent
commit
a63ed4fa6c
  1. 43
      application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java
  2. 6
      common/data/src/main/java/org/thingsboard/server/common/data/exception/EntityVersionMismatchException.java
  3. 6
      common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java
  4. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java
  5. 4
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  6. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java

43
application/src/test/java/org/thingsboard/server/controller/RuleChainControllerTest.java

@ -30,6 +30,8 @@ import org.springframework.test.context.ContextConfiguration;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.action.TbCreateAlarmNode;
import org.thingsboard.rule.engine.action.TbCreateAlarmNodeConfiguration;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNode;
import org.thingsboard.rule.engine.debug.TbMsgGeneratorNodeConfiguration;
import org.thingsboard.rule.engine.metadata.TbGetRelatedAttributeNode;
import org.thingsboard.rule.engine.metadata.TbGetRelatedDataNodeConfiguration;
import org.thingsboard.server.common.data.StringUtils;
@ -356,6 +358,47 @@ public class RuleChainControllerTest extends AbstractControllerTest {
assertThat(error).contains("alarmType is malformed");
}
@Test
public void testSaveRuleChainWithOutdatedVersion() throws Exception {
RuleChain ruleChain = createRuleChain("Rule chain with invalid nodes");
RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
ruleChainMetaData.setRuleChainId(ruleChain.getId());
RuleNode ruleNode = new RuleNode();
ruleNode.setName("Test");
ruleNode.setType(TbMsgGeneratorNode.class.getName());
TbMsgGeneratorNodeConfiguration config = new TbMsgGeneratorNodeConfiguration();
ruleNode.setConfiguration(JacksonUtil.valueToTree(config));
List<RuleNode> ruleNodes = new ArrayList<>();
ruleNodes.add(ruleNode);
ruleChainMetaData.setFirstNodeIndex(0);
ruleChainMetaData.setNodes(ruleNodes);
ruleChainMetaData = doPost("/api/ruleChain/metadata", ruleChainMetaData, RuleChainMetaData.class);
assertThat(ruleChainMetaData.getVersion()).isEqualTo(2); // in this case when saving metadata, rule chain will also be updated
ruleChain = doGet("/api/ruleChain/" + ruleChain.getId(), RuleChain.class);
assertThat(ruleChain.getVersion()).isEqualTo(2);
ruleChain.setName("Updated");
ruleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class);
assertThat(ruleChain.getVersion()).isEqualTo(3);
ruleChain.setVersion(1L);
doPost("/api/ruleChain", ruleChain)
.andExpect(status().isConflict());
ruleChainMetaData.setVersion(1L);
doPost("/api/ruleChain/metadata", ruleChainMetaData)
.andExpect(status().isConflict());
ruleChainMetaData.setVersion(3L);
doPost("/api/ruleChain/metadata", ruleChainMetaData)
.andExpect(status().isOk());
ruleChain.setVersion(3L);
doPost("/api/ruleChain", ruleChain)
.andExpect(status().isOk());
}
private RuleChain createRuleChain(String name) {
RuleChain ruleChain = new RuleChain();
ruleChain.setName(name);

6
common/data/src/main/java/org/thingsboard/server/common/data/exception/EntityVersionMismatchException.java

@ -15,10 +15,16 @@
*/
package org.thingsboard.server.common.data.exception;
import org.thingsboard.server.common.data.EntityType;
public class EntityVersionMismatchException extends RuntimeException {
public EntityVersionMismatchException(String message, Throwable cause) {
super(message, cause);
}
public EntityVersionMismatchException(EntityType entityType, Throwable cause) {
this((entityType != null ? entityType.getNormalName() : "Entity") + " was already changed by someone else", cause);
}
}

6
common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java

@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.rule;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.thingsboard.server.common.data.HasVersion;
import org.thingsboard.server.common.data.id.RuleChainId;
import java.util.ArrayList;
@ -27,11 +28,14 @@ import java.util.List;
*/
@Schema
@Data
public class RuleChainMetaData {
public class RuleChainMetaData implements HasVersion {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "JSON object with Rule Chain Id.", accessMode = Schema.AccessMode.READ_ONLY)
private RuleChainId ruleChainId;
@Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "Version of the Rule Chain")
private Long version;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "Index of the first rule node in the 'nodes' list")
private Integer firstNodeIndex;

2
common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/RuleChainExportData.java

@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
public class RuleChainExportData extends EntityExportData<RuleChain> {
@JsonProperty(index = 3)
@JsonIgnoreProperties("ruleChainId")
@JsonIgnoreProperties({"ruleChainId", "version"})
private RuleChainMetaData metaData;
}

4
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.exception.EntityVersionMismatchException;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
@ -174,6 +175,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
RuleChain ruleChain = findRuleChainById(tenantId, ruleChainMetaData.getRuleChainId());
if (ruleChain == null) {
return RuleChainUpdateResult.failed();
} else if (ruleChainMetaData.getVersion() != null && !ruleChainMetaData.getVersion().equals(ruleChain.getVersion())) {
throw new EntityVersionMismatchException(EntityType.RULE_CHAIN, null);
}
RuleChainDataValidator.validateMetaDataFieldsAndConnections(ruleChainMetaData);
@ -298,6 +301,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
}
RuleChainMetaData ruleChainMetaData = new RuleChainMetaData();
ruleChainMetaData.setRuleChainId(ruleChainId);
ruleChainMetaData.setVersion(ruleChain.getVersion());
List<RuleNode> ruleNodes = getRuleChainNodes(tenantId, ruleChainId);
Collections.sort(ruleNodes, Comparator.comparingLong(RuleNode::getCreatedTime).thenComparing(RuleNode::getId, Comparator.comparing(RuleNodeId::getId)));
Map<RuleNodeId, Integer> ruleNodeIndexMap = new HashMap<>();

2
dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java

@ -79,7 +79,7 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
try {
entity = doSave(entity, isNew, flush);
} catch (OptimisticLockException e) {
throw new EntityVersionMismatchException((getEntityType() != null ? getEntityType().getNormalName() : "Entity") + " was already changed by someone else", e);
throw new EntityVersionMismatchException(getEntityType(), e);
}
return DaoUtil.getData(entity);
}

Loading…
Cancel
Save