diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index 19c75e7b9b..baee88965e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -143,4 +143,30 @@ public class AlarmController extends BaseController { } } + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") + @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) + @ResponseBody + public AlarmSeverity getHighestAlarmSeverity( + @PathVariable("entityType") String strEntityType, + @PathVariable("entityId") String strEntityId, + @RequestParam(required = false) String searchStatus, + @RequestParam(required = false) String status + ) throws ThingsboardException { + checkParameter("EntityId", strEntityId); + checkParameter("EntityType", strEntityType); + EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); + AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus); + AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status); + if (alarmSearchStatus != null && alarmStatus != null) { + throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " + + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); + } + checkEntityId(entityId); + try { + return alarmService.findHighestAlarmSeverity(entityId, alarmSearchStatus, alarmStatus); + } catch (Exception e) { + throw handleException(e); + } + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index 3556d51f09..63fba03a52 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -16,10 +16,8 @@ package org.thingsboard.server.dao.alarm; import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.server.common.data.alarm.Alarm; -import org.thingsboard.server.common.data.alarm.AlarmId; -import org.thingsboard.server.common.data.alarm.AlarmInfo; -import org.thingsboard.server.common.data.alarm.AlarmQuery; +import org.thingsboard.server.common.data.alarm.*; +import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.TimePageData; /** @@ -39,4 +37,7 @@ public interface AlarmService { ListenableFuture> findAlarms(AlarmQuery query); + AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus, + AlarmStatus alarmStatus); + } 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 58f7316a75..06a9b343db 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 @@ -27,6 +27,7 @@ import org.springframework.util.StringUtils; import org.thingsboard.server.common.data.alarm.*; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.page.TimePageData; +import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.entity.AbstractEntityService; @@ -46,6 +47,7 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -242,6 +244,46 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ }); } + @Override + public AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus, + AlarmStatus alarmStatus) { + TimePageLink nextPageLink = new TimePageLink(100); + boolean hasNext = true; + AlarmSeverity highestSeverity = null; + AlarmQuery query; + while (hasNext) { + query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false); + List alarms; + try { + alarms = alarmDao.findAlarms(query).get(); + } catch (ExecutionException | InterruptedException e) { + log.warn("Failed to find highest alarm severity. EntityId: [{}], AlarmSearchStatus: [{}], AlarmStatus: [{}]", + entityId, alarmSearchStatus, alarmStatus); + throw new RuntimeException(e); + } + hasNext = alarms.size() == nextPageLink.getLimit(); + if (hasNext) { + nextPageLink = new TimePageData<>(alarms, nextPageLink).getNextPageLink(); + } + if (alarms.isEmpty()) { + continue; + } else { + List sorted = new ArrayList(alarms); + sorted.sort((p1, p2) -> p1.getSeverity().compareTo(p2.getSeverity())); + AlarmSeverity severity = sorted.get(0).getSeverity(); + if (severity == AlarmSeverity.CRITICAL) { + highestSeverity = severity; + break; + } else if (highestSeverity == null) { + highestSeverity = severity; + } else { + highestSeverity = highestSeverity.compareTo(severity) < 0 ? highestSeverity : severity; + } + } + } + return highestSeverity; + } + private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException { log.debug("Deleting Alarm relation: {}", alarmRelation); relationService.deleteRelation(alarmRelation).get(); diff --git a/ui/src/app/api/alarm.service.js b/ui/src/app/api/alarm.service.js index db4ceadde1..3b7a735be2 100644 --- a/ui/src/app/api/alarm.service.js +++ b/ui/src/app/api/alarm.service.js @@ -48,6 +48,7 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { ackAlarm: ackAlarm, clearAlarm: clearAlarm, getAlarms: getAlarms, + getHighestAlarmSeverity: getHighestAlarmSeverity, pollAlarms: pollAlarms, cancelPollAlarms: cancelPollAlarms, subscribeForAlarms: subscribeForAlarms, @@ -165,6 +166,23 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { return deferred.promise; } + function getHighestAlarmSeverity(entityType, entityId, alarmSearchStatus, alarmStatus, config) { + var deferred = $q.defer(); + var url = '/api/alarm/highestSeverity/' + entityType + '/' + entityId; + + if (alarmSearchStatus) { + url += '?searchStatus=' + alarmSearchStatus; + } else if (alarmStatus) { + url += '?status=' + alarmStatus; + } + $http.get(url, config).then(function success(response) { + deferred.resolve(response.data); + }, function fail() { + deferred.reject(); + }); + return deferred.promise; + } + function fetchAlarms(alarmsQuery, pageLink, deferred, alarmsList) { getAlarms(alarmsQuery.entityType, alarmsQuery.entityId, pageLink, alarmsQuery.alarmSearchStatus, alarmsQuery.alarmStatus,