diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 56c90a2dab..744fb368a9 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -123,6 +123,10 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 2.4.1 to 2.4.2 ..."); databaseUpgradeService.upgradeDatabase("2.4.1"); + case "2.4.2.1": + log.info("Upgrading ThingsBoard from version 2.4.2.1 to 2.4.3 ..."); + + databaseUpgradeService.upgradeDatabase("2.4.2.1"); log.info("Updating system data..."); 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..7d0b22db67 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 @@ -271,8 +271,21 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService { log.info("Updating schema ..."); String updateAssetTableStmt = "alter table asset add label text"; try { + log.info("Updating assets ..."); cluster.getSession().execute(updateAssetTableStmt); Thread.sleep(2500); + log.info("Assets updated."); + } catch (InvalidQueryException e) {} + log.info("Schema updated."); + break; + case "2.4.2.1": + log.info("Updating schema ..."); + String updateAlarmTableStmt = "alter table alarm add propagate_relation_types text"; + try { + 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..d686b172cf 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 @@ -196,6 +196,15 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService { log.info("Schema updated."); } break; + case "2.4.2.1": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + 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; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } 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 d46445778d..ca052a1329 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,9 +23,9 @@ 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.common.util.ThingsBoardThreadFactory; -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; @@ -53,6 +53,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; @@ -60,6 +61,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; @@ -155,8 +157,14 @@ 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(); + Stream relations = relationService.findByQuery(alarm.getTenantId(), query).get().stream(); + if (!CollectionUtils.isEmpty(propagateRelationTypes)) { + relations = relations.filter(entityRelation -> propagateRelationTypes.contains(entityRelation.getType())); + } + return relations.map(EntityRelation::getFrom).collect(Collectors.toList()); } private ListenableFuture updateAlarm(Alarm update) { @@ -361,13 +369,30 @@ 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(newRelationTypes)) { + if (!CollectionUtils.isEmpty(existingPropagateRelationTypes)) { + existing.setPropagateRelationTypes(Stream.concat(existingPropagateRelationTypes.stream(), newRelationTypes.stream()) + .distinct() + .collect(Collectors.toList())); + } else { + existing.setPropagateRelationTypes(newRelationTypes); + } + } 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()); + + List propagateRelationTypes = alarm.getPropagateRelationTypes(); + Stream relationStream = relations.stream(); + if (!CollectionUtils.isEmpty(propagateRelationTypes)) { + relationStream = relationStream.filter(entityRelation -> propagateRelationTypes.contains(entityRelation.getType())); + } + Set parents = relationStream.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..55a6b920ba 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,8 @@ 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.Collections; import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.ALARM_ACK_TS_PROPERTY; @@ -46,6 +50,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 +107,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 +133,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 +245,14 @@ 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 +270,11 @@ 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(","))); + } else { + alarm.setPropagateRelationTypes(Collections.emptyList()); + } 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..d56392e497 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,9 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.Table; +import java.util.Arrays; +import java.util.Collections; + 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 +52,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 +105,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 +131,11 @@ 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,11 @@ 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(","))); + } else { + alarm.setPropagateRelationTypes(Collections.emptyList()); + } 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..06352d9241 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,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import java.io.IOException; +import java.util.List; @Slf4j @RuleNode( @@ -53,10 +54,13 @@ import java.io.IOException; public class TbCreateAlarmNode extends TbAbstractAlarmNode { private static ObjectMapper mapper = new ObjectMapper(); + private List relationTypes; @Override protected TbCreateAlarmNodeConfiguration loadAlarmNodeConfig(TbNodeConfiguration configuration) throws TbNodeException { - return TbNodeUtils.convert(configuration, TbCreateAlarmNodeConfiguration.class); + TbCreateAlarmNodeConfiguration nodeConfiguration = TbNodeUtils.convert(configuration, TbCreateAlarmNodeConfiguration.class); + relationTypes = nodeConfiguration.getRelationTypes(); + return nodeConfiguration; } @Override @@ -125,9 +129,11 @@ 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; } }