diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java index 68ca728823..4732ef6be7 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java @@ -270,9 +270,16 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { case "2.4.1": log.info("Updating schema ..."); String updateAssetTableStmt = "alter table asset add label text"; + String updateAlarmTableStmt = "alter table alarm add propagate_relation_types text"; try { + log.info("Updating assets ..."); cluster.getSession().execute(updateAssetTableStmt); Thread.sleep(2500); + log.info("Assets updated."); + log.info("Updating alarms ..."); + cluster.getSession().execute(updateAlarmTableStmt); + Thread.sleep(2500); + log.info("Alarms updated."); } catch (InvalidQueryException e) {} log.info("Schema updated."); break; diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index 3210742388..1ded097e52 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -193,6 +193,9 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { try { conn.createStatement().execute("ALTER TABLE asset ADD CONSTRAINT asset_name_unq_key UNIQUE (tenant_id, name)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script } catch (Exception e) {} + try { + conn.createStatement().execute("ALTER TABLE alarm ADD COLUMN propagate_relation_types varchar"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script + } catch (Exception e) {} log.info("Schema updated."); } break; 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 065321ff91..b96f86b715 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 @@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.HasTenantId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import java.util.List; + /** * Created by ashvayka on 11.05.17. */ @@ -45,6 +47,7 @@ public class Alarm extends BaseData implements HasName, HasTenantId { private long clearTs; private transient JsonNode details; private boolean propagate; + private List propagateRelationTypes; public Alarm() { super(); @@ -68,6 +71,7 @@ public class Alarm extends BaseData implements HasName, HasTenantId { this.clearTs = alarm.getClearTs(); this.details = alarm.getDetails(); this.propagate = alarm.isPropagate(); + this.propagateRelationTypes = alarm.getPropagateRelationTypes(); } @Override 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 8a4279fe7f..fa5ce6d4b4 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 @@ -23,8 +23,8 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmId; @@ -52,6 +52,7 @@ import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; @@ -59,6 +60,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -154,8 +156,16 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private List getParentEntities(Alarm alarm) throws InterruptedException, ExecutionException { EntityRelationsQuery query = new EntityRelationsQuery(); - query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE, false)); - return relationService.findByQuery(alarm.getTenantId(), query).get().stream().map(EntityRelation::getFrom).collect(Collectors.toList()); + RelationsSearchParameters parameters = new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE, false); + query.setParameters(parameters); + List propagateRelationTypes = alarm.getPropagateRelationTypes(); + if (!CollectionUtils.isEmpty(propagateRelationTypes)) { + return relationService.findByQuery(alarm.getTenantId(), query).get().stream() + .filter(entityRelation -> propagateRelationTypes.contains(entityRelation.getType())) + .map(EntityRelation::getFrom).collect(Collectors.toList()); + } else { + return relationService.findByQuery(alarm.getTenantId(), query).get().stream().map(EntityRelation::getFrom).collect(Collectors.toList()); + } } private ListenableFuture updateAlarm(Alarm update) { @@ -360,13 +370,28 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ existing.setSeverity(alarm.getSeverity()); existing.setDetails(alarm.getDetails()); existing.setPropagate(existing.isPropagate() || alarm.isPropagate()); + List existingPropagateRelationTypes = existing.getPropagateRelationTypes(); + List newRelationTypes = alarm.getPropagateRelationTypes(); + if (!CollectionUtils.isEmpty(existingPropagateRelationTypes) && !CollectionUtils.isEmpty(newRelationTypes)) { + existing.setPropagateRelationTypes(Stream.concat(existingPropagateRelationTypes.stream(), newRelationTypes.stream()) + .distinct() + .collect(Collectors.toList())); + } else { + existing.setPropagateRelationTypes(Collections.emptyList()); + } return existing; } private void updateRelations(Alarm alarm, AlarmStatus oldStatus, AlarmStatus newStatus) { try { List relations = relationService.findByToAsync(alarm.getTenantId(), alarm.getId(), RelationTypeGroup.ALARM).get(); - Set parents = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); + Set parents; + List propagateRelationTypes = alarm.getPropagateRelationTypes(); + if (!CollectionUtils.isEmpty(propagateRelationTypes)) { + parents = relations.stream().filter(entityRelation -> propagateRelationTypes.contains(entityRelation.getType())).map(EntityRelation::getFrom).collect(Collectors.toSet()); + } else { + parents = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet()); + } for (EntityId parentId : parents) { updateAlarmRelation(alarm.getTenantId(), parentId, alarm.getId(), oldStatus, newStatus); } 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 c466c034fc..4605b405ca 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 @@ -231,6 +231,7 @@ public class ModelConstants { public static final String ALARM_ACK_TS_PROPERTY = "ack_ts"; public static final String ALARM_CLEAR_TS_PROPERTY = "clear_ts"; public static final String ALARM_PROPAGATE_PROPERTY = "propagate"; + public static final String ALARM_PROPAGATE_RELATION_TYPES = "propagate_relation_types"; public static final String ALARM_BY_ID_VIEW_NAME = "alarm_by_id"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java index 807a73fe38..e274ca3348 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/nosql/AlarmEntity.java @@ -23,6 +23,8 @@ import com.datastax.driver.mapping.annotations.Table; import com.fasterxml.jackson.databind.JsonNode; import lombok.EqualsAndHashCode; import lombok.ToString; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmId; @@ -36,6 +38,7 @@ import org.thingsboard.server.dao.model.type.AlarmStatusCodec; import org.thingsboard.server.dao.model.type.EntityTypeCodec; import org.thingsboard.server.dao.model.type.JsonCodec; +import java.util.Arrays; import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ACK_TS_PROPERTY; @@ -46,6 +49,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ALARM_END_TS_PROPE import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_RELATION_TYPES; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_SEVERITY_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_START_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_STATUS_PROPERTY; @@ -102,6 +106,9 @@ public final class AlarmEntity implements BaseEntity { @Column(name = ALARM_PROPAGATE_PROPERTY) private Boolean propagate; + @Column(name = ALARM_PROPAGATE_RELATION_TYPES) + private String propagateRelationTypes; + public AlarmEntity() { super(); } @@ -125,6 +132,12 @@ public final class AlarmEntity implements BaseEntity { this.ackTs = alarm.getAckTs(); this.clearTs = alarm.getClearTs(); this.details = alarm.getDetails(); + this.details = alarm.getDetails(); + if (!CollectionUtils.isEmpty(alarm.getPropagateRelationTypes())) { + this.propagateRelationTypes = String.join(",", alarm.getPropagateRelationTypes()); + } else { + this.propagateRelationTypes = null; + } } public UUID getId() { @@ -231,6 +244,10 @@ public final class AlarmEntity implements BaseEntity { this.propagate = propagate; } + public String getPropagateRelationTypes() { return propagateRelationTypes; } + + public void setPropagateRelationTypes(String propagateRelationTypes) { this.propagateRelationTypes = propagateRelationTypes; } + @Override public Alarm toData() { Alarm alarm = new Alarm(new AlarmId(id)); @@ -248,6 +265,9 @@ public final class AlarmEntity implements BaseEntity { alarm.setAckTs(ackTs); alarm.setClearTs(clearTs); alarm.setDetails(details); + if(!StringUtils.isEmpty(propagateRelationTypes)) { + alarm.setPropagateRelationTypes(Arrays.asList(propagateRelationTypes.split(","))); + } return alarm; } 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 f6cfb7189c..03b6218be9 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 @@ -21,6 +21,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.UUIDConverter; import org.thingsboard.server.common.data.alarm.Alarm; @@ -40,6 +42,8 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.Table; +import java.util.Arrays; + 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_COLUMN_FAMILY_NAME; @@ -47,6 +51,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.ALARM_END_TS_PROPE import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_PROPERTY; +import static org.thingsboard.server.dao.model.ModelConstants.ALARM_PROPAGATE_RELATION_TYPES; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_SEVERITY_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_START_TS_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_STATUS_PROPERTY; @@ -99,6 +104,9 @@ public final class AlarmEntity extends BaseSqlEntity implements BaseEntit @Column(name = ALARM_PROPAGATE_PROPERTY) private Boolean propagate; + @Column(name = ALARM_PROPAGATE_RELATION_TYPES) + private String propagateRelationTypes; + public AlarmEntity() { super(); } @@ -122,6 +130,12 @@ public final class AlarmEntity extends BaseSqlEntity implements BaseEntit this.ackTs = alarm.getAckTs(); this.clearTs = alarm.getClearTs(); this.details = alarm.getDetails(); + if (!CollectionUtils.isEmpty(alarm.getPropagateRelationTypes())) { + this.propagateRelationTypes = String.join(",", alarm.getPropagateRelationTypes()); + } else { + this.propagateRelationTypes = null; + } + } @Override @@ -141,6 +155,9 @@ public final class AlarmEntity extends BaseSqlEntity implements BaseEntit alarm.setAckTs(ackTs); alarm.setClearTs(clearTs); alarm.setDetails(details); + if(!StringUtils.isEmpty(propagateRelationTypes)) { + alarm.setPropagateRelationTypes(Arrays.asList(propagateRelationTypes.split(","))); + } return alarm; } diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql index a07e27cbe1..5a07c4f2ad 100644 --- a/dao/src/main/resources/cassandra/schema-entities.cql +++ b/dao/src/main/resources/cassandra/schema-entities.cql @@ -306,6 +306,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.alarm ( clear_ts bigint, details text, propagate boolean, + propagate_relation_types text, PRIMARY KEY ((tenant_id, originator_id, originator_type), type, id) ) WITH CLUSTERING ORDER BY ( type ASC, id DESC); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 4b21d851a5..087240ec33 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS alarm ( start_ts bigint, status varchar(255), tenant_id varchar(31), + propagate_relation_types varchar, type varchar(255) ); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java index d6f6236311..e17b65be72 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateAlarmNode.java @@ -21,11 +21,11 @@ import com.google.common.base.Function; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbNodeConfiguration; import org.thingsboard.rule.engine.api.TbNodeException; +import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.id.TenantId; @@ -33,6 +33,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import java.io.IOException; +import java.util.Collections; +import java.util.List; @Slf4j @RuleNode( @@ -56,7 +58,11 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode relationTypes = this.config.getRelationTypes(); + if (relationTypes == null) { + relationTypes = Collections.emptyList(); + } return Alarm.builder() .tenantId(tenantId) .originator(msg.getOriginator()) @@ -145,6 +165,7 @@ public class TbCreateAlarmNode extends TbAbstractAlarmNode { @@ -26,18 +29,21 @@ public class TbCreateAlarmNodeConfiguration extends TbAbstractAlarmNodeConfigura private boolean propagate; private boolean useMessageAlarmData; + private List relationTypes; + @Override public TbCreateAlarmNodeConfiguration defaultConfiguration() { TbCreateAlarmNodeConfiguration configuration = new TbCreateAlarmNodeConfiguration(); configuration.setAlarmDetailsBuildJs("var details = {};\n" + "if (metadata.prevAlarmDetails) {\n" + " details = JSON.parse(metadata.prevAlarmDetails);\n" + - "}\n"+ + "}\n" + "return details;"); configuration.setAlarmType("General Alarm"); configuration.setSeverity(AlarmSeverity.CRITICAL); configuration.setPropagate(false); configuration.setUseMessageAlarmData(false); + configuration.setRelationTypes(Collections.emptyList()); return configuration; } }