diff --git a/application/src/main/data/upgrade/3.2.2/schema_update.sql b/application/src/main/data/upgrade/3.2.2/schema_update.sql index 4bb63f3b9f..4df24b4edf 100644 --- a/application/src/main/data/upgrade/3.2.2/schema_update.sql +++ b/application/src/main/data/upgrade/3.2.2/schema_update.sql @@ -90,6 +90,11 @@ ALTER TABLE device ADD COLUMN IF NOT EXISTS firmware_id uuid, ADD COLUMN IF NOT EXISTS software_id uuid; +ALTER TABLE alarm + ADD COLUMN IF NOT EXISTS customer_id uuid; + +DELETE FROM relation WHERE from_type = 'TENANT' AND relation_type_group = 'RULE_CHAIN'; + DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_firmware_device_profile') THEN diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 3f93aef41a..b91c46417c 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -27,6 +27,9 @@ import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; @@ -34,9 +37,13 @@ import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.alarm.AlarmDao; +import org.thingsboard.server.dao.alarm.AlarmService; +import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; @@ -72,6 +79,15 @@ public class DefaultDataUpdateService implements DataUpdateService { @Autowired private TimeseriesService tsService; + @Autowired + private AlarmService alarmService; + + @Autowired + private EntityService entityService; + + @Autowired + private AlarmDao alarmDao; + @Override public void updateData(String fromVersion) throws Exception { switch (fromVersion) { @@ -90,14 +106,25 @@ public class DefaultDataUpdateService implements DataUpdateService { case "3.2.2": log.info("Updating data from version 3.2.2 to 3.3.0 ..."); tenantsDefaultEdgeRuleChainUpdater.updateEntities(null); + tenantsAlarmsCustomerUpdater.updateEntities(null); break; default: throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion); } } - private PaginatedUpdater tenantsDefaultRuleChainUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsDefaultRuleChainUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants default rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -117,8 +144,18 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsDefaultEdgeRuleChainUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants default edge rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -138,8 +175,18 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private PaginatedUpdater tenantsRootRuleChainUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsRootRuleChainUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants root rule chain updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -192,8 +239,18 @@ public class DefaultDataUpdateService implements DataUpdateService { } }; - private PaginatedUpdater tenantsEntityViewsUpdater = - new PaginatedUpdater() { + private final PaginatedUpdater tenantsEntityViewsUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants entity views updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } @Override protected PageData findEntities(String region, PageLink pageLink) { @@ -261,4 +318,48 @@ public class DefaultDataUpdateService implements DataUpdateService { }, MoreExecutors.directExecutor()); } + private final PaginatedUpdater tenantsAlarmsCustomerUpdater = + new PaginatedUpdater<>() { + + @Override + protected String getName() { + return "Tenants alarms customer updater"; + } + + @Override + protected boolean forceReportTotal() { + return true; + } + + @Override + protected PageData findEntities(String region, PageLink pageLink) { + return tenantService.findTenants(pageLink); + } + + @Override + protected void updateEntity(Tenant tenant) { + updateTenantAlarmsCustomer(tenant.getId()); + } + }; + + private void updateTenantAlarmsCustomer(TenantId tenantId) { + AlarmQuery alarmQuery = new AlarmQuery(null, new TimePageLink(100), null, null, false); + PageData alarms = alarmDao.findAlarms(tenantId, alarmQuery); + boolean hasNext = true; + while (hasNext) { + for (Alarm alarm : alarms.getData()) { + if (alarm.getCustomerId() == null && alarm.getOriginator() != null) { + alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator())); + alarmDao.save(tenantId, alarm); + } + } + if (alarms.hasNext()) { + alarmQuery.setPageLink(alarmQuery.getPageLink().nextPageLink()); + alarms = alarmDao.findAlarms(tenantId, alarmQuery); + } else { + hasNext = false; + } + } + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java b/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java index e766bb0daa..4bfe744863 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/PaginatedUpdater.java @@ -15,16 +15,20 @@ */ package org.thingsboard.server.service.install.update; +import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +@Slf4j public abstract class PaginatedUpdater> { private static final int DEFAULT_LIMIT = 100; + private int updated = 0; public void updateEntities(I id) { + updated = 0; PageLink pageLink = new PageLink(DEFAULT_LIMIT); boolean hasNext = true; while (hasNext) { @@ -32,13 +36,25 @@ public abstract class PaginatedUpdater DEFAULT_LIMIT || forceReportTotal()) { + log.info("{}: {} total entities updated.", getName(), updated); + } } } } + protected boolean forceReportTotal() { + return false; + } + + protected abstract String getName(); + protected abstract PageData findEntities(I id, PageLink pageLink); protected abstract void updateEntity(D entity); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index 09c05e3c0c..e6a9538e54 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -28,6 +28,8 @@ public interface EntityService { ListenableFuture fetchEntityNameAsync(TenantId tenantId, EntityId entityId); + CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId); + void deleteEntityRelations(TenantId tenantId, EntityId entityId); long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java index 32d0a516eb..54f7ab72f5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/Alarm.java @@ -21,9 +21,11 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -35,9 +37,10 @@ import java.util.List; @Data @Builder @AllArgsConstructor -public class Alarm extends BaseData implements HasName, HasTenantId { +public class Alarm extends BaseData implements HasName, HasTenantId, HasCustomerId { private TenantId tenantId; + private CustomerId customerId; private String type; private EntityId originator; private AlarmSeverity severity; @@ -62,6 +65,7 @@ public class Alarm extends BaseData implements HasName, HasTenantId { super(alarm.getId()); this.createdTime = alarm.getCreatedTime(); this.tenantId = alarm.getTenantId(); + this.customerId = alarm.getCustomerId(); this.type = alarm.getType(); this.originator = alarm.getOriginator(); this.severity = alarm.getSeverity(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 472cbb588f..b40993b76b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -110,6 +110,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getEndTs() == 0L) { alarm.setEndTs(alarm.getStartTs()); } + alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator())); if (alarm.getId() == null) { Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get(); if (existing == null || existing.getStatus().isCleared()) { @@ -355,6 +356,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ existing.setStatus(alarm.getStatus()); existing.setSeverity(alarm.getSeverity()); existing.setDetails(alarm.getDetails()); + existing.setCustomerId(alarm.getCustomerId()); existing.setPropagate(existing.isPropagate() || alarm.isPropagate()); List existingPropagateRelationTypes = existing.getPropagateRelationTypes(); List newRelationTypes = alarm.getPropagateRelationTypes(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index 7e0218740a..73cebc0797 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -22,6 +22,7 @@ import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AssetId; @@ -54,6 +55,7 @@ import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.user.UserService; +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.service.Validator.validateId; /** @@ -175,6 +177,50 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return entityName; } + @Override + public CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { + log.trace("Executing fetchEntityCustomerId [{}]", entityId); + HasCustomerId hasCustomerId = null; + switch (entityId.getEntityType()) { + case TENANT: + case RULE_CHAIN: + case RULE_NODE: + case DASHBOARD: + case WIDGETS_BUNDLE: + case WIDGET_TYPE: + case TENANT_PROFILE: + case DEVICE_PROFILE: + case API_USAGE_STATE: + case TB_RESOURCE: + case FIRMWARE: + break; + case CUSTOMER: + hasCustomerId = () -> new CustomerId(entityId.getId()); + break; + case USER: + hasCustomerId = userService.findUserById(tenantId, new UserId(entityId.getId())); + break; + case ASSET: + hasCustomerId = assetService.findAssetById(tenantId, new AssetId(entityId.getId())); + break; + case DEVICE: + hasCustomerId = deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId())); + break; + case ALARM: + try { + hasCustomerId = alarmService.findAlarmByIdAsync(tenantId, new AlarmId(entityId.getId())).get(); + } catch (Exception e) {} + break; + case ENTITY_VIEW: + hasCustomerId = entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId())); + break; + case EDGE: + hasCustomerId = edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId())); + break; + } + return hasCustomerId != null ? hasCustomerId.getCustomerId() : new CustomerId(NULL_UUID); + } + private static void validateEntityCountQuery(EntityCountQuery query) { if (query == null) { throw new IncorrectParameterException("Query must be specified."); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index 5b4ea874ee..ee0d837ea0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -258,6 +258,7 @@ public class ModelConstants { */ public static final String ALARM_COLUMN_FAMILY_NAME = "alarm"; public static final String ALARM_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY; + public static final String ALARM_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY; public static final String ALARM_TYPE_PROPERTY = "type"; public static final String ALARM_DETAILS_PROPERTY = "details"; public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java index 297fa39e62..8ade2b78d5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractAlarmEntity.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.AlarmId; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseEntity; @@ -44,6 +45,7 @@ import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ACK_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_CLEAR_TS_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_CUSTOMER_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_END_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY; @@ -64,6 +66,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity @Column(name = ALARM_TENANT_ID_PROPERTY) private UUID tenantId; + @Column(name = ALARM_CUSTOMER_ID_PROPERTY) + private UUID customerId; + @Column(name = ALARM_ORIGINATOR_ID_PROPERTY) private UUID originatorId; @@ -115,6 +120,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity if (alarm.getTenantId() != null) { this.tenantId = alarm.getTenantId().getId(); } + if (alarm.getCustomerId() != null) { + this.customerId = alarm.getCustomerId().getId(); + } this.type = alarm.getType(); this.originatorId = alarm.getOriginator().getId(); this.originatorType = alarm.getOriginator().getEntityType(); @@ -138,6 +146,7 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity this.setId(alarmEntity.getId()); this.setCreatedTime(alarmEntity.getCreatedTime()); this.tenantId = alarmEntity.getTenantId(); + this.customerId = alarmEntity.getCustomerId(); this.type = alarmEntity.getType(); this.originatorId = alarmEntity.getOriginatorId(); this.originatorType = alarmEntity.getOriginatorType(); @@ -159,6 +168,9 @@ public abstract class AbstractAlarmEntity extends BaseSqlEntity if (tenantId != null) { alarm.setTenantId(new TenantId(tenantId)); } + if (customerId != null) { + alarm.setCustomerId(new CustomerId(customerId)); + } alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId)); alarm.setType(type); alarm.setSeverity(severity); diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java index 73b181a170..5848ffa572 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AlarmEntity.java @@ -19,6 +19,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.dao.util.mapping.JsonStringType; import javax.persistence.Entity; @@ -37,6 +38,10 @@ public final class AlarmEntity extends AbstractAlarmEntity { super(); } + public AlarmEntity(AlarmInfo alarmInfo) { + super(alarmInfo); + } + public AlarmEntity(Alarm alarm) { super(alarm); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 786d86d8dd..b61e18e08a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -100,12 +100,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Transactional public RuleChain saveRuleChain(RuleChain ruleChain) { ruleChainValidator.validate(ruleChain, RuleChain::getTenantId); - RuleChain savedRuleChain = ruleChainDao.save(ruleChain.getTenantId(), ruleChain); - if (ruleChain.isRoot() && ruleChain.getId() == null) { - createRelation(ruleChain.getTenantId(), new EntityRelation(savedRuleChain.getTenantId(), savedRuleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); - } - return savedRuleChain; + return ruleChainDao.save(ruleChain.getTenantId(), ruleChain); } @Override @@ -114,29 +109,20 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC RuleChain ruleChain = ruleChainDao.findById(tenantId, ruleChainId.getId()); if (!ruleChain.isRoot()) { RuleChain previousRootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId()); - try { - if (previousRootRuleChain == null) { - setRootAndSave(tenantId, ruleChain); - return true; - } else if (!previousRootRuleChain.getId().equals(ruleChain.getId())) { - deleteRelation(tenantId, new EntityRelation(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); - previousRootRuleChain.setRoot(false); - ruleChainDao.save(tenantId, previousRootRuleChain); - setRootAndSave(tenantId, ruleChain); - return true; - } - } catch (ExecutionException | InterruptedException e) { - log.warn("[{}] Failed to set root rule chain, ruleChainId: [{}]", ruleChainId); - throw new RuntimeException(e); + if (previousRootRuleChain == null) { + setRootAndSave(tenantId, ruleChain); + return true; + } else if (!previousRootRuleChain.getId().equals(ruleChain.getId())) { + previousRootRuleChain.setRoot(false); + ruleChainDao.save(tenantId, previousRootRuleChain); + setRootAndSave(tenantId, ruleChain); + return true; } } return false; } - private void setRootAndSave(TenantId tenantId, RuleChain ruleChain) throws ExecutionException, InterruptedException { - createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); + private void setRootAndSave(TenantId tenantId, RuleChain ruleChain) { ruleChain.setRoot(true); ruleChainDao.save(tenantId, ruleChain); } @@ -179,41 +165,45 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC toDelete.add(existingNode); } } - for (RuleNode node : toAddOrUpdate) { - node.setRuleChainId(ruleChain.getId()); - RuleNode savedNode = ruleNodeDao.save(tenantId, node); - createRelation(tenantId, new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); - int index = nodes.indexOf(node); - nodes.set(index, savedNode); - ruleNodeIndexMap.put(savedNode.getId(), index); + if (nodes != null) { + for (RuleNode node : toAddOrUpdate) { + node.setRuleChainId(ruleChain.getId()); + RuleNode savedNode = ruleNodeDao.save(tenantId, node); + createRelation(tenantId, new EntityRelation(ruleChainMetaData.getRuleChainId(), savedNode.getId(), + EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); + int index = nodes.indexOf(node); + nodes.set(index, savedNode); + ruleNodeIndexMap.put(savedNode.getId(), index); + } } for (RuleNode node : toDelete) { deleteRuleNode(tenantId, node.getId()); } RuleNodeId firstRuleNodeId = null; - if (ruleChainMetaData.getFirstNodeIndex() != null) { - firstRuleNodeId = nodes.get(ruleChainMetaData.getFirstNodeIndex()).getId(); - } - if ((ruleChain.getFirstRuleNodeId() != null && !ruleChain.getFirstRuleNodeId().equals(firstRuleNodeId)) - || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) { - ruleChain.setFirstRuleNodeId(firstRuleNodeId); - ruleChainDao.save(tenantId, ruleChain); - } - if (ruleChainMetaData.getConnections() != null) { - for (NodeConnectionInfo nodeConnection : ruleChainMetaData.getConnections()) { - EntityId from = nodes.get(nodeConnection.getFromIndex()).getId(); - EntityId to = nodes.get(nodeConnection.getToIndex()).getId(); - String type = nodeConnection.getType(); - createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE)); + if (nodes != null) { + if (ruleChainMetaData.getFirstNodeIndex() != null) { + firstRuleNodeId = nodes.get(ruleChainMetaData.getFirstNodeIndex()).getId(); } - } - if (ruleChainMetaData.getRuleChainConnections() != null) { - for (RuleChainConnectionInfo nodeToRuleChainConnection : ruleChainMetaData.getRuleChainConnections()) { - EntityId from = nodes.get(nodeToRuleChainConnection.getFromIndex()).getId(); - EntityId to = nodeToRuleChainConnection.getTargetRuleChainId(); - String type = nodeToRuleChainConnection.getType(); - createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE, nodeToRuleChainConnection.getAdditionalInfo())); + if ((ruleChain.getFirstRuleNodeId() != null && !ruleChain.getFirstRuleNodeId().equals(firstRuleNodeId)) + || (ruleChain.getFirstRuleNodeId() == null && firstRuleNodeId != null)) { + ruleChain.setFirstRuleNodeId(firstRuleNodeId); + ruleChainDao.save(tenantId, ruleChain); + } + if (ruleChainMetaData.getConnections() != null) { + for (NodeConnectionInfo nodeConnection : ruleChainMetaData.getConnections()) { + EntityId from = nodes.get(nodeConnection.getFromIndex()).getId(); + EntityId to = nodes.get(nodeConnection.getToIndex()).getId(); + String type = nodeConnection.getType(); + createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE)); + } + } + if (ruleChainMetaData.getRuleChainConnections() != null) { + for (RuleChainConnectionInfo nodeToRuleChainConnection : ruleChainMetaData.getRuleChainConnections()) { + EntityId from = nodes.get(nodeToRuleChainConnection.getFromIndex()).getId(); + EntityId to = nodeToRuleChainConnection.getTargetRuleChainId(); + String type = nodeToRuleChainConnection.getType(); + createRelation(tenantId, new EntityRelation(from, to, type, RelationTypeGroup.RULE_NODE, nodeToRuleChainConnection.getAdditionalInfo())); + } } } @@ -307,24 +297,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Override public RuleChain getRootTenantRuleChain(TenantId tenantId) { - return getRootRuleChainByType(tenantId, RuleChainType.CORE); - } - - private RuleChain getRootRuleChainByType(TenantId tenantId, RuleChainType type) { Validator.validateId(tenantId, "Incorrect tenant id for search request."); - List relations = relationService.findByFrom(tenantId, tenantId, RelationTypeGroup.RULE_CHAIN); - if (relations != null && !relations.isEmpty()) { - for (EntityRelation relation : relations) { - RuleChainId ruleChainId = new RuleChainId(relation.getTo().getId()); - RuleChain ruleChainById = findRuleChainById(tenantId, ruleChainId); - if (type.equals(ruleChainById.getType())) { - return ruleChainById; - } - } - return null; - } else { - return null; - } + return ruleChainDao.findRootRuleChainByTenantIdAndType(tenantId.getId(), RuleChainType.CORE); } @Override @@ -366,7 +340,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC boolean valid = true; EntityType toType = relation.getTo().getEntityType(); if (toType == EntityType.RULE_NODE || toType == EntityType.RULE_CHAIN) { - BaseData entity; + BaseData entity; if (relation.getTo().getEntityType() == EntityType.RULE_NODE) { entity = ruleNodeDao.findById(tenantId, relation.getTo().getId()); } else { @@ -501,9 +475,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC ObjectNode objNode = (ObjectNode) node; objNode.put("id", tenantId.getId().toString()); } else { - Iterator childIter = node.iterator(); - while (childIter.hasNext()) { - searchTenantIdRecursive(tenantId, childIter.next()); + for (JsonNode jsonNode : node) { + searchTenantIdRecursive(tenantId, jsonNode); } } } @@ -608,7 +581,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC @Override public RuleChain getEdgeTemplateRootRuleChain(TenantId tenantId) { - return getRootRuleChainByType(tenantId, RuleChainType.EDGE); + Validator.validateId(tenantId, "Incorrect tenant id for search request."); + return ruleChainDao.findRootRuleChainByTenantIdAndType(tenantId.getId(), RuleChainType.EDGE); } @Override @@ -618,13 +592,9 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC if (previousEdgeTemplateRootRuleChain == null || !previousEdgeTemplateRootRuleChain.getId().equals(ruleChain.getId())) { try { if (previousEdgeTemplateRootRuleChain != null) { - deleteRelation(tenantId, new EntityRelation(previousEdgeTemplateRootRuleChain.getTenantId(), previousEdgeTemplateRootRuleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); previousEdgeTemplateRootRuleChain.setRoot(false); ruleChainDao.save(tenantId, previousEdgeTemplateRootRuleChain); } - createRelation(tenantId, new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(), - EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN)); ruleChain.setRoot(true); ruleChainDao.save(tenantId, ruleChain); return true; @@ -699,8 +669,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC ruleNodeDao.removeById(tenantId, entityId.getId()); } - private DataValidator ruleChainValidator = - new DataValidator() { + private final DataValidator ruleChainValidator = + new DataValidator<>() { @Override protected void validateCreate(TenantId tenantId, RuleChain data) { DefaultTenantProfileConfiguration profileConfiguration = @@ -739,8 +709,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC } }; - private PaginatedRemover tenantRuleChainsRemover = - new PaginatedRemover() { + private final PaginatedRemover tenantRuleChainsRemover = + new PaginatedRemover<>() { @Override protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java index 4baa3bd576..2aaaa934d7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java @@ -50,6 +50,15 @@ public interface RuleChainDao extends Dao, TenantEntityDao { */ PageData findRuleChainsByTenantIdAndType(UUID tenantId, RuleChainType type, PageLink pageLink); + /** + * Find root rule chain by tenantId and type + * + * @param tenantId the tenantId + * @param type the type + * @return the rule chain object + */ + RuleChain findRootRuleChainByTenantIdAndType(UUID tenantId, RuleChainType type); + /** * Find rule chains by tenantId, edgeId and page link. * diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java index 028eda1583..b4c0ac09c6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java @@ -120,13 +120,7 @@ public interface AlarmRepository extends CrudRepository { Pageable pageable); @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " + - "WHERE a.tenantId = :tenantId " + - "AND (" + - "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " + - "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " + - "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " + - "OR a.originatorId = :customerId" + - ") " + + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + @@ -137,13 +131,7 @@ public interface AlarmRepository extends CrudRepository { countQuery = "" + "SELECT count(a) " + "FROM AlarmEntity a " + - "WHERE a.tenantId = :tenantId " + - "AND (" + - "a.originatorId IN (SELECT d.id from DeviceEntity d WHERE d.customerId = :customerId) " + - "OR a.originatorId IN (SELECT asset.id from AssetEntity asset WHERE asset.customerId = :customerId) " + - "OR a.originatorId IN (SELECT u.id from UserEntity u WHERE u.customerId = :customerId) " + - "OR a.originatorId = :customerId" + - ") " + + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java index 760d9e7aeb..0dbe22571e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java @@ -82,6 +82,12 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao findRuleChainsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, PageLink pageLink) { log.debug("Try to find rule chains by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java index 3c3c5ff3b4..1251234fa1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java @@ -50,5 +50,8 @@ public interface RuleChainRepository extends PagingAndSortingRepository