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

Rule chains import refactoring
This commit is contained in:
Andrew Shvayka 2021-10-19 15:44:45 +03:00 committed by GitHub
commit 96d20b073b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 41 deletions

View File

@ -25,7 +25,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -450,15 +449,17 @@ public class RuleChainController extends BaseController {
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST) @RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public void importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { public List<RuleChainImportResult> importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException {
try { try {
TenantId tenantId = getCurrentUser().getTenantId(); TenantId tenantId = getCurrentUser().getTenantId();
List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite); List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, overwrite);
if (!CollectionUtils.isEmpty(importResults)) { for (RuleChainImportResult importResult : importResults) {
for (RuleChainImportResult importResult : importResults) { if (importResult.getError() == null) {
tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(), importResult.getLifecycleEvent()); tbClusterService.broadcastEntityStateChangeEvent(importResult.getTenantId(), importResult.getRuleChainId(),
importResult.isUpdated() ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED);
} }
} }
return importResults;
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);
} }

View File

@ -23,7 +23,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
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.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainData; import org.thingsboard.server.common.data.rule.RuleChainData;
@ -71,7 +70,7 @@ public interface RuleChainService {
RuleChainData exportTenantRuleChains(TenantId tenantId, PageLink pageLink) throws ThingsboardException; RuleChainData exportTenantRuleChains(TenantId tenantId, PageLink pageLink) throws ThingsboardException;
List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, RuleChainType type, boolean overwrite); List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite);
RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId); RuleChain assignRuleChainToEdge(TenantId tenantId, RuleChainId ruleChainId, EdgeId edgeId);

View File

@ -15,17 +15,22 @@
*/ */
package org.thingsboard.server.common.data.rule; package org.thingsboard.server.common.data.rule;
import lombok.AllArgsConstructor; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
@Data @Data
@AllArgsConstructor
public class RuleChainImportResult { public class RuleChainImportResult {
@JsonIgnore
private TenantId tenantId; private TenantId tenantId;
private RuleChainId ruleChainId; private RuleChainId ruleChainId;
private ComponentLifecycleEvent lifecycleEvent; private String ruleChainName;
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
private boolean updated;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String error;
} }

View File

@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -38,7 +39,6 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
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.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.rule.NodeConnectionInfo; import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
@ -59,6 +59,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantDao; import org.thingsboard.server.dao.tenant.TenantDao;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@ -416,41 +417,46 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
} }
@Override @Override
public List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, RuleChainType type, boolean overwrite) { public List<RuleChainImportResult> importTenantRuleChains(TenantId tenantId, RuleChainData ruleChainData, boolean overwrite) {
List<RuleChainImportResult> importResults = new ArrayList<>(); List<RuleChainImportResult> importResults = new ArrayList<>();
setRandomRuleChainIds(ruleChainData); setRandomRuleChainIds(ruleChainData);
resetRuleNodeIds(ruleChainData.getMetadata()); resetRuleNodeIds(ruleChainData.getMetadata());
resetRuleChainMetadataTenantIds(tenantId, ruleChainData.getMetadata()); resetRuleChainMetadataTenantIds(tenantId, ruleChainData.getMetadata());
if (overwrite) {
List<RuleChain> persistentRuleChains = findAllTenantRuleChains(tenantId, type); for (RuleChain ruleChain : ruleChainData.getRuleChains()) {
for (RuleChain ruleChain : ruleChainData.getRuleChains()) { RuleChainImportResult importResult = new RuleChainImportResult();
ComponentLifecycleEvent lifecycleEvent;
Optional<RuleChain> persistentRuleChainOpt = persistentRuleChains.stream().filter(rc -> rc.getName().equals(ruleChain.getName())).findFirst(); ruleChain.setTenantId(tenantId);
if (persistentRuleChainOpt.isPresent()) { ruleChain.setRoot(false);
setNewRuleChainId(ruleChain, ruleChainData.getMetadata(), ruleChain.getId(), persistentRuleChainOpt.get().getId());
ruleChain.setRoot(persistentRuleChainOpt.get().isRoot()); if (overwrite) {
lifecycleEvent = ComponentLifecycleEvent.UPDATED; Collection<RuleChain> existingRuleChains = ruleChainDao.findByTenantIdAndTypeAndName(tenantId,
} else { Optional.ofNullable(ruleChain.getType()).orElse(RuleChainType.CORE), ruleChain.getName());
ruleChain.setRoot(false); Optional<RuleChain> existingRuleChain = existingRuleChains.stream().findFirst();
lifecycleEvent = ComponentLifecycleEvent.CREATED; if (existingRuleChain.isPresent()) {
setNewRuleChainId(ruleChain, ruleChainData.getMetadata(), ruleChain.getId(), existingRuleChain.get().getId());
ruleChain.setRoot(existingRuleChain.get().isRoot());
importResult.setUpdated(true);
} }
ruleChain.setTenantId(tenantId);
ruleChainDao.save(tenantId, ruleChain);
importResults.add(new RuleChainImportResult(tenantId, ruleChain.getId(), lifecycleEvent));
} }
} else {
if (!CollectionUtils.isEmpty(ruleChainData.getRuleChains())) { try {
ruleChainData.getRuleChains().forEach(rc -> { ruleChain = saveRuleChain(ruleChain);
rc.setTenantId(tenantId); } catch (Exception e) {
rc.setRoot(false); importResult.setError(ExceptionUtils.getRootCauseMessage(e));
RuleChain savedRc = ruleChainDao.save(tenantId, rc);
importResults.add(new RuleChainImportResult(tenantId, savedRc.getId(), ComponentLifecycleEvent.CREATED));
});
} }
importResult.setTenantId(tenantId);
importResult.setRuleChainId(ruleChain.getId());
importResult.setRuleChainName(ruleChain.getName());
importResults.add(importResult);
} }
if (!CollectionUtils.isEmpty(ruleChainData.getMetadata())) {
if (CollectionUtils.isNotEmpty(ruleChainData.getMetadata())) {
ruleChainData.getMetadata().forEach(md -> saveRuleChainMetaData(tenantId, md)); ruleChainData.getMetadata().forEach(md -> saveRuleChainMetaData(tenantId, md));
} }
return importResults; return importResults;
} }
@ -475,7 +481,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
} }
if (isTenantId) { if (isTenantId) {
ObjectNode objNode = (ObjectNode) node; ObjectNode objNode = (ObjectNode) node;
objNode.put("id", tenantId.getId().toString()); if (objNode.has("id")) {
objNode.put("id", tenantId.getId().toString());
}
} else { } else {
for (JsonNode jsonNode : node) { for (JsonNode jsonNode : node) {
searchTenantIdRecursive(tenantId, jsonNode); searchTenantIdRecursive(tenantId, jsonNode);
@ -723,4 +731,5 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
checkRuleNodesAndDelete(tenantId, entity.getId()); checkRuleNodesAndDelete(tenantId, entity.getId());
} }
}; };
} }

View File

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.dao.rule; package org.thingsboard.server.dao.rule;
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.RuleChain;
@ -22,6 +23,7 @@ import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.dao.Dao; import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.TenantEntityDao; import org.thingsboard.server.dao.TenantEntityDao;
import java.util.Collection;
import java.util.UUID; import java.util.UUID;
/** /**
@ -74,4 +76,7 @@ public interface RuleChainDao extends Dao<RuleChain>, TenantEntityDao {
* @return the list of rule chain objects * @return the list of rule chain objects
*/ */
PageData<RuleChain> findAutoAssignToEdgeRuleChainsByTenantId(UUID tenantId, PageLink pageLink); PageData<RuleChain> findAutoAssignToEdgeRuleChainsByTenantId(UUID tenantId, PageLink pageLink);
Collection<RuleChain> findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name);
} }

View File

@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.RuleChainEntity;
import org.thingsboard.server.dao.rule.RuleChainDao; import org.thingsboard.server.dao.rule.RuleChainDao;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao; import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.Collection;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@ -97,8 +98,14 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R
DaoUtil.toPageable(pageLink))); DaoUtil.toPageable(pageLink)));
} }
@Override
public Collection<RuleChain> findByTenantIdAndTypeAndName(TenantId tenantId, RuleChainType type, String name) {
return DaoUtil.convertDataList(ruleChainRepository.findByTenantIdAndTypeAndName(tenantId.getId(), type, name));
}
@Override @Override
public Long countByTenantId(TenantId tenantId) { public Long countByTenantId(TenantId tenantId) {
return ruleChainRepository.countByTenantId(tenantId.getId()); return ruleChainRepository.countByTenantId(tenantId.getId());
} }
} }

View File

@ -23,6 +23,7 @@ import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainType;
import org.thingsboard.server.dao.model.sql.RuleChainEntity; import org.thingsboard.server.dao.model.sql.RuleChainEntity;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface RuleChainRepository extends PagingAndSortingRepository<RuleChainEntity, UUID> { public interface RuleChainRepository extends PagingAndSortingRepository<RuleChainEntity, UUID> {
@ -55,10 +56,13 @@ public interface RuleChainRepository extends PagingAndSortingRepository<RuleChai
"AND re.relationType = 'Contains' AND re.fromId = :tenantId AND re.fromType = 'TENANT' " + "AND re.relationType = 'Contains' AND re.fromId = :tenantId AND re.fromType = 'TENANT' " +
"AND LOWER(rc.searchText) LIKE LOWER(CONCAT(:searchText, '%'))") "AND LOWER(rc.searchText) LIKE LOWER(CONCAT(:searchText, '%'))")
Page<RuleChainEntity> findAutoAssignByTenantId(@Param("tenantId") UUID tenantId, Page<RuleChainEntity> findAutoAssignByTenantId(@Param("tenantId") UUID tenantId,
@Param("searchText") String searchText, @Param("searchText") String searchText,
Pageable pageable); Pageable pageable);
RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType); RuleChainEntity findByTenantIdAndTypeAndRootIsTrue(UUID tenantId, RuleChainType ruleChainType);
Long countByTenantId(UUID tenantId); Long countByTenantId(UUID tenantId);
List<RuleChainEntity> findByTenantIdAndTypeAndName(UUID tenantId, RuleChainType type, String name);
} }