Commit 96d20b073b29e0d46733a2dde52cb24449a8e2fb

Authored by Andrew Shvayka
Committed by GitHub
2 parents c88a4426 2d4ac40e

Merge pull request #5351 from ViacheslavKlimov/fix/rule-chains-import

Rule chains import refactoring
@@ -25,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -25,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.beans.factory.annotation.Value; 25 import org.springframework.beans.factory.annotation.Value;
26 import org.springframework.http.HttpStatus; 26 import org.springframework.http.HttpStatus;
27 import org.springframework.security.access.prepost.PreAuthorize; 27 import org.springframework.security.access.prepost.PreAuthorize;
28 -import org.springframework.util.CollectionUtils;  
29 import org.springframework.util.StringUtils; 28 import org.springframework.util.StringUtils;
30 import org.springframework.web.bind.annotation.PathVariable; 29 import org.springframework.web.bind.annotation.PathVariable;
31 import org.springframework.web.bind.annotation.RequestBody; 30 import org.springframework.web.bind.annotation.RequestBody;
@@ -450,15 +449,17 @@ public class RuleChainController extends BaseController { @@ -450,15 +449,17 @@ public class RuleChainController extends BaseController {
450 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 449 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
451 @RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST) 450 @RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST)
452 @ResponseBody 451 @ResponseBody
453 - public void importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { 452 + public List<RuleChainImportResult> importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException {
454 try { 453 try {
455 TenantId tenantId = getCurrentUser().getTenantId(); 454 TenantId tenantId = getCurrentUser().getTenantId();
456 - List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite);  
457 - if (!CollectionUtils.isEmpty(importResults)) {  
458 - for (RuleChainImportResult importResult : importResults) {  
459 - tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(), importResult.getLifecycleEvent()); 455 + List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite);
  456 + for (RuleChainImportResult importResult : importResults) {
  457 + if (importResult.getError() == null) {
  458 + tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(),
  459 + importResult.isUpdated() ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED);
460 } 460 }
461 } 461 }
  462 + return importResults;
462 } catch (Exception e) { 463 } catch (Exception e) {
463 throw handleException(e); 464 throw handleException(e);
464 } 465 }
@@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId; @@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
23 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.page.PageData; 24 import org.thingsboard.server.common.data.page.PageData;
25 import org.thingsboard.server.common.data.page.PageLink; 25 import org.thingsboard.server.common.data.page.PageLink;
26 -import org.thingsboard.server.common.data.page.TimePageLink;  
27 import org.thingsboard.server.common.data.relation.EntityRelation; 26 import org.thingsboard.server.common.data.relation.EntityRelation;
28 import org.thingsboard.server.common.data.rule.RuleChain; 27 import org.thingsboard.server.common.data.rule.RuleChain;
29 import org.thingsboard.server.common.data.rule.RuleChainData; 28 import org.thingsboard.server.common.data.rule.RuleChainData;
@@ -71,7 +70,7 @@ public interface RuleChainService { @@ -71,7 +70,7 @@ public interface RuleChainService {
71 70
72 RuleChainData exportTenantRuleChains(TenantId tenantId, PageLink pageLink) throws ThingsboardException; 71 RuleChainData exportTenantRuleChains(TenantId tenantId, PageLink pageLink) throws ThingsboardException;
73 72
74 - List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, RuleChainType type, boolean overwrite); 73 + List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite);
75 74
76 RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId); 75 RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId);
77 76
@@ -15,17 +15,22 @@ @@ -15,17 +15,22 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.rule; 16 package org.thingsboard.server.common.data.rule;
17 17
18 -import lombok.AllArgsConstructor; 18 +import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import com.fasterxml.jackson.annotation.JsonInclude;
19 import lombok.Data; 20 import lombok.Data;
20 import org.thingsboard.server.common.data.id.RuleChainId; 21 import org.thingsboard.server.common.data.id.RuleChainId;
21 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
22 -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;  
23 23
24 @Data 24 @Data
25 -@AllArgsConstructor  
26 public class RuleChainImportResult { 25 public class RuleChainImportResult {
27 26
  27 + @JsonIgnore
28 private TenantId tenantId; 28 private TenantId tenantId;
29 private RuleChainId ruleChainId; 29 private RuleChainId ruleChainId;
30 - private ComponentLifecycleEvent lifecycleEvent; 30 + private String ruleChainName;
  31 + @JsonInclude(JsonInclude.Include.NON_DEFAULT)
  32 + private boolean updated;
  33 + @JsonInclude(JsonInclude.Include.NON_NULL)
  34 + private String error;
  35 +
31 } 36 }
@@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture; @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture;
22 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
23 import org.apache.commons.collections.CollectionUtils; 23 import org.apache.commons.collections.CollectionUtils;
24 import org.apache.commons.lang3.StringUtils; 24 import org.apache.commons.lang3.StringUtils;
  25 +import org.apache.commons.lang3.exception.ExceptionUtils;
25 import org.hibernate.exception.ConstraintViolationException; 26 import org.hibernate.exception.ConstraintViolationException;
26 import org.springframework.beans.factory.annotation.Autowired; 27 import org.springframework.beans.factory.annotation.Autowired;
27 import org.springframework.context.annotation.Lazy; 28 import org.springframework.context.annotation.Lazy;
@@ -38,7 +39,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId; @@ -38,7 +39,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
38 import org.thingsboard.server.common.data.id.TenantId; 39 import org.thingsboard.server.common.data.id.TenantId;
39 import org.thingsboard.server.common.data.page.PageData; 40 import org.thingsboard.server.common.data.page.PageData;
40 import org.thingsboard.server.common.data.page.PageLink; 41 import org.thingsboard.server.common.data.page.PageLink;
41 -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;  
42 import org.thingsboard.server.common.data.relation.EntityRelation; 42 import org.thingsboard.server.common.data.relation.EntityRelation;
43 import org.thingsboard.server.common.data.relation.RelationTypeGroup; 43 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
44 import org.thingsboard.server.common.data.rule.NodeConnectionInfo; 44 import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
@@ -59,6 +59,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; @@ -59,6 +59,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
59 import org.thingsboard.server.dao.tenant.TenantDao; 59 import org.thingsboard.server.dao.tenant.TenantDao;
60 60
61 import java.util.ArrayList; 61 import java.util.ArrayList;
  62 +import java.util.Collection;
62 import java.util.HashMap; 63 import java.util.HashMap;
63 import java.util.HashSet; 64 import java.util.HashSet;
64 import java.util.Iterator; 65 import java.util.Iterator;
@@ -416,41 +417,46 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @@ -416,41 +417,46 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
416 } 417 }
417 418
418 @Override 419 @Override
419 - public List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, RuleChainType type, boolean overwrite) { 420 + public List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite) {
420 List<RuleChainImportResult> importResults = new ArrayList<>(); 421 List<RuleChainImportResult> importResults = new ArrayList<>();
  422 +
421 setRandomRuleChainIds(ruleChainData); 423 setRandomRuleChainIds(ruleChainData);
422 resetRuleNodeIds(ruleChainData.getMetadata()); 424 resetRuleNodeIds(ruleChainData.getMetadata());
423 resetRuleChainMetadataTenantIds(tenantId, ruleChainData.getMetadata()); 425 resetRuleChainMetadataTenantIds(tenantId, ruleChainData.getMetadata());
424 - if (overwrite) {  
425 - List<RuleChain> persistentRuleChains = findAllTenantRuleChains(tenantId, type);  
426 - for (RuleChain ruleChain : ruleChainData.getRuleChains()) {  
427 - ComponentLifecycleEvent lifecycleEvent;  
428 - Optional<RuleChain> persistentRuleChainOpt = persistentRuleChains.stream().filter(rc -> rc.getName().equals(ruleChain.getName())).findFirst();  
429 - if (persistentRuleChainOpt.isPresent()) {  
430 - setNewRuleChainId(ruleChain, ruleChainData.getMetadata(), ruleChain.getId(), persistentRuleChainOpt.get().getId());  
431 - ruleChain.setRoot(persistentRuleChainOpt.get().isRoot());  
432 - lifecycleEvent = ComponentLifecycleEvent.UPDATED;  
433 - } else {  
434 - ruleChain.setRoot(false);  
435 - lifecycleEvent = ComponentLifecycleEvent.CREATED; 426 +
  427 + for (RuleChain ruleChain : ruleChainData.getRuleChains()) {
  428 + RuleChainImportResult importResult = new RuleChainImportResult();
  429 +
  430 + ruleChain.setTenantId(tenantId);
  431 + ruleChain.setRoot(false);
  432 +
  433 + if (overwrite) {
  434 + Collection<RuleChain> existingRuleChains = ruleChainDao.findByTenantIdAndTypeAndName(tenantId,
  435 + Optional.ofNullable(ruleChain.getType()).orElse(RuleChainType.CORE), ruleChain.getName());
  436 + Optional<RuleChain> existingRuleChain = existingRuleChains.stream().findFirst();
  437 + if (existingRuleChain.isPresent()) {
  438 + setNewRuleChainId(ruleChain, ruleChainData.getMetadata(), ruleChain.getId(), existingRuleChain.get().getId());
  439 + ruleChain.setRoot(existingRuleChain.get().isRoot());
  440 + importResult.setUpdated(true);
436 } 441 }
437 - ruleChain.setTenantId(tenantId);  
438 - ruleChainDao.save(tenantId, ruleChain);  
439 - importResults.add(new RuleChainImportResult(tenantId, ruleChain.getId(), lifecycleEvent));  
440 } 442 }
441 - } else {  
442 - if (!CollectionUtils.isEmpty(ruleChainData.getRuleChains())) {  
443 - ruleChainData.getRuleChains().forEach(rc -> {  
444 - rc.setTenantId(tenantId);  
445 - rc.setRoot(false);  
446 - RuleChain savedRc = ruleChainDao.save(tenantId, rc);  
447 - importResults.add(new RuleChainImportResult(tenantId, savedRc.getId(), ComponentLifecycleEvent.CREATED));  
448 - }); 443 +
  444 + try {
  445 + ruleChain = saveRuleChain(ruleChain);
  446 + } catch (Exception e) {
  447 + importResult.setError(ExceptionUtils.getRootCauseMessage(e));
449 } 448 }
  449 +
  450 + importResult.setTenantId(tenantId);
  451 + importResult.setRuleChainId(ruleChain.getId());
  452 + importResult.setRuleChainName(ruleChain.getName());
  453 + importResults.add(importResult);
450 } 454 }
451 - if (!CollectionUtils.isEmpty(ruleChainData.getMetadata())) { 455 +
  456 + if (CollectionUtils.isNotEmpty(ruleChainData.getMetadata())) {
452 ruleChainData.getMetadata().forEach(md -> saveRuleChainMetaData(tenantId, md)); 457 ruleChainData.getMetadata().forEach(md -> saveRuleChainMetaData(tenantId, md));
453 } 458 }
  459 +
454 return importResults; 460 return importResults;
455 } 461 }
456 462
@@ -475,7 +481,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @@ -475,7 +481,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
475 } 481 }
476 if (isTenantId) { 482 if (isTenantId) {
477 ObjectNode objNode = (ObjectNode) node; 483 ObjectNode objNode = (ObjectNode) node;
478 - objNode.put("id", tenantId.getId().toString()); 484 + if (objNode.has("id")) {
  485 + objNode.put("id", tenantId.getId().toString());
  486 + }
479 } else { 487 } else {
480 for (JsonNode jsonNode : node) { 488 for (JsonNode jsonNode : node) {
481 searchTenantIdRecursive(tenantId, jsonNode); 489 searchTenantIdRecursive(tenantId, jsonNode);
@@ -723,4 +731,5 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @@ -723,4 +731,5 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
723 checkRuleNodesAndDelete(tenantId, entity.getId()); 731 checkRuleNodesAndDelete(tenantId, entity.getId());
724 } 732 }
725 }; 733 };
  734 +
726 } 735 }
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.dao.rule; 16 package org.thingsboard.server.dao.rule;
17 17
  18 +import org.thingsboard.server.common.data.id.TenantId;
18 import org.thingsboard.server.common.data.page.PageData; 19 import org.thingsboard.server.common.data.page.PageData;
19 import org.thingsboard.server.common.data.page.PageLink; 20 import org.thingsboard.server.common.data.page.PageLink;
20 import org.thingsboard.server.common.data.rule.RuleChain; 21 import org.thingsboard.server.common.data.rule.RuleChain;
@@ -22,6 +23,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType; @@ -22,6 +23,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
22 import org.thingsboard.server.dao.Dao; 23 import org.thingsboard.server.dao.Dao;
23 import org.thingsboard.server.dao.TenantEntityDao; 24 import org.thingsboard.server.dao.TenantEntityDao;
24 25
  26 +import java.util.Collection;
25 import java.util.UUID; 27 import java.util.UUID;
26 28
27 /** 29 /**
@@ -74,4 +76,7 @@ public interface RuleChainDao extends Dao<RuleChain>, TenantEntityDao { @@ -74,4 +76,7 @@ public interface RuleChainDao extends Dao<RuleChain>, TenantEntityDao {
74 * @return the list of rule chain objects 76 * @return the list of rule chain objects
75 */ 77 */
76 PageData<RuleChain> findAutoAssignToEdgeRuleChainsByTenantId(UUID tenantId, PageLink pageLink); 78 PageData<RuleChain> findAutoAssignToEdgeRuleChainsByTenantId(UUID tenantId, PageLink pageLink);
  79 +
  80 + Collection<RuleChain> findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name);
  81 +
77 } 82 }
@@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.RuleChainEntity; @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.RuleChainEntity;
29 import org.thingsboard.server.dao.rule.RuleChainDao; 29 import org.thingsboard.server.dao.rule.RuleChainDao;
30 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; 30 import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
31 31
  32 +import java.util.Collection;
32 import java.util.Objects; 33 import java.util.Objects;
33 import java.util.UUID; 34 import java.util.UUID;
34 35
@@ -98,7 +99,13 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R @@ -98,7 +99,13 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R
98 } 99 }
99 100
100 @Override 101 @Override
  102 + public Collection<RuleChain> findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name) {
  103 + return DaoUtil.convertDataList(ruleChainRepository.findByTenantIdAndTypeAndName(tenantId.getId(), type, name));
  104 + }
  105 +
  106 + @Override
101 public Long countByTenantId(TenantId tenantId) { 107 public Long countByTenantId(TenantId tenantId) {
102 return ruleChainRepository.countByTenantId(tenantId.getId()); 108 return ruleChainRepository.countByTenantId(tenantId.getId());
103 } 109 }
  110 +
104 } 111 }
@@ -23,6 +23,7 @@ import org.springframework.data.repository.query.Param; @@ -23,6 +23,7 @@ import org.springframework.data.repository.query.Param;
23 import org.thingsboard.server.common.data.rule.RuleChainType; 23 import org.thingsboard.server.common.data.rule.RuleChainType;
24 import org.thingsboard.server.dao.model.sql.RuleChainEntity; 24 import org.thingsboard.server.dao.model.sql.RuleChainEntity;
25 25
  26 +import java.util.List;
26 import java.util.UUID; 27 import java.util.UUID;
27 28
28 public interface RuleChainRepository extends PagingAndSortingRepository<RuleChainEntity, UUID> { 29 public interface RuleChainRepository extends PagingAndSortingRepository<RuleChainEntity, UUID> {
@@ -55,10 +56,13 @@ public interface RuleChainRepository extends PagingAndSortingRepository<RuleChai @@ -55,10 +56,13 @@ public interface RuleChainRepository extends PagingAndSortingRepository<RuleChai
55 "AND re.relationType = 'Contains' AND re.fromId = :tenantId AND re.fromType = 'TENANT' " + 56 "AND re.relationType = 'Contains' AND re.fromId = :tenantId AND re.fromType = 'TENANT' " +
56 "AND LOWER(rc.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") 57 "AND LOWER(rc.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
57 Page<RuleChainEntity> findAutoAssignByTenantId(@Param("tenantId") UUID tenantId, 58 Page<RuleChainEntity> findAutoAssignByTenantId(@Param("tenantId") UUID tenantId,
58 - @Param("searchText") String searchText,  
59 - Pageable pageable); 59 + @Param("searchText") String searchText,
  60 + Pageable pageable);
60 61
61 RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType); 62 RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType);
62 63
63 Long countByTenantId(UUID tenantId); 64 Long countByTenantId(UUID tenantId);
  65 +
  66 + List<RuleChainEntity> findByTenantIdAndTypeAndName(UUID tenantId, RuleChainType type, String name);
  67 +
64 } 68 }