Commit 87683218b556558fbb81e2faf0898de5e55fb879
1 parent
69a0b74c
TB-63: Find highest alarm severity for specified entity.
Showing
4 changed files
with
91 additions
and
4 deletions
... | ... | @@ -143,4 +143,30 @@ public class AlarmController extends BaseController { |
143 | 143 | } |
144 | 144 | } |
145 | 145 | |
146 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | |
147 | + @RequestMapping(value = "/alarm/highestSeverity/{entityType}/{entityId}", method = RequestMethod.GET) | |
148 | + @ResponseBody | |
149 | + public AlarmSeverity getHighestAlarmSeverity( | |
150 | + @PathVariable("entityType") String strEntityType, | |
151 | + @PathVariable("entityId") String strEntityId, | |
152 | + @RequestParam(required = false) String searchStatus, | |
153 | + @RequestParam(required = false) String status | |
154 | + ) throws ThingsboardException { | |
155 | + checkParameter("EntityId", strEntityId); | |
156 | + checkParameter("EntityType", strEntityType); | |
157 | + EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); | |
158 | + AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus); | |
159 | + AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status); | |
160 | + if (alarmSearchStatus != null && alarmStatus != null) { | |
161 | + throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " + | |
162 | + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | |
163 | + } | |
164 | + checkEntityId(entityId); | |
165 | + try { | |
166 | + return alarmService.findHighestAlarmSeverity(entityId, alarmSearchStatus, alarmStatus); | |
167 | + } catch (Exception e) { | |
168 | + throw handleException(e); | |
169 | + } | |
170 | + } | |
171 | + | |
146 | 172 | } | ... | ... |
... | ... | @@ -16,10 +16,8 @@ |
16 | 16 | package org.thingsboard.server.dao.alarm; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | -import org.thingsboard.server.common.data.alarm.Alarm; | |
20 | -import org.thingsboard.server.common.data.alarm.AlarmId; | |
21 | -import org.thingsboard.server.common.data.alarm.AlarmInfo; | |
22 | -import org.thingsboard.server.common.data.alarm.AlarmQuery; | |
19 | +import org.thingsboard.server.common.data.alarm.*; | |
20 | +import org.thingsboard.server.common.data.id.EntityId; | |
23 | 21 | import org.thingsboard.server.common.data.page.TimePageData; |
24 | 22 | |
25 | 23 | /** |
... | ... | @@ -39,4 +37,7 @@ public interface AlarmService { |
39 | 37 | |
40 | 38 | ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query); |
41 | 39 | |
40 | + AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus, | |
41 | + AlarmStatus alarmStatus); | |
42 | + | |
42 | 43 | } | ... | ... |
... | ... | @@ -27,6 +27,7 @@ import org.springframework.util.StringUtils; |
27 | 27 | import org.thingsboard.server.common.data.alarm.*; |
28 | 28 | import org.thingsboard.server.common.data.id.EntityId; |
29 | 29 | import org.thingsboard.server.common.data.page.TimePageData; |
30 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
30 | 31 | import org.thingsboard.server.common.data.relation.EntityRelation; |
31 | 32 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
32 | 33 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
... | ... | @@ -46,6 +47,7 @@ import javax.annotation.PostConstruct; |
46 | 47 | import javax.annotation.PreDestroy; |
47 | 48 | import java.util.ArrayList; |
48 | 49 | import java.util.List; |
50 | +import java.util.UUID; | |
49 | 51 | import java.util.concurrent.ExecutionException; |
50 | 52 | import java.util.concurrent.ExecutorService; |
51 | 53 | import java.util.concurrent.Executors; |
... | ... | @@ -242,6 +244,46 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
242 | 244 | }); |
243 | 245 | } |
244 | 246 | |
247 | + @Override | |
248 | + public AlarmSeverity findHighestAlarmSeverity(EntityId entityId, AlarmSearchStatus alarmSearchStatus, | |
249 | + AlarmStatus alarmStatus) { | |
250 | + TimePageLink nextPageLink = new TimePageLink(100); | |
251 | + boolean hasNext = true; | |
252 | + AlarmSeverity highestSeverity = null; | |
253 | + AlarmQuery query; | |
254 | + while (hasNext) { | |
255 | + query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false); | |
256 | + List<AlarmInfo> alarms; | |
257 | + try { | |
258 | + alarms = alarmDao.findAlarms(query).get(); | |
259 | + } catch (ExecutionException | InterruptedException e) { | |
260 | + log.warn("Failed to find highest alarm severity. EntityId: [{}], AlarmSearchStatus: [{}], AlarmStatus: [{}]", | |
261 | + entityId, alarmSearchStatus, alarmStatus); | |
262 | + throw new RuntimeException(e); | |
263 | + } | |
264 | + hasNext = alarms.size() == nextPageLink.getLimit(); | |
265 | + if (hasNext) { | |
266 | + nextPageLink = new TimePageData<>(alarms, nextPageLink).getNextPageLink(); | |
267 | + } | |
268 | + if (alarms.isEmpty()) { | |
269 | + continue; | |
270 | + } else { | |
271 | + List<AlarmInfo> sorted = new ArrayList(alarms); | |
272 | + sorted.sort((p1, p2) -> p1.getSeverity().compareTo(p2.getSeverity())); | |
273 | + AlarmSeverity severity = sorted.get(0).getSeverity(); | |
274 | + if (severity == AlarmSeverity.CRITICAL) { | |
275 | + highestSeverity = severity; | |
276 | + break; | |
277 | + } else if (highestSeverity == null) { | |
278 | + highestSeverity = severity; | |
279 | + } else { | |
280 | + highestSeverity = highestSeverity.compareTo(severity) < 0 ? highestSeverity : severity; | |
281 | + } | |
282 | + } | |
283 | + } | |
284 | + return highestSeverity; | |
285 | + } | |
286 | + | |
245 | 287 | private void deleteRelation(EntityRelation alarmRelation) throws ExecutionException, InterruptedException { |
246 | 288 | log.debug("Deleting Alarm relation: {}", alarmRelation); |
247 | 289 | relationService.deleteRelation(alarmRelation).get(); | ... | ... |
... | ... | @@ -48,6 +48,7 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { |
48 | 48 | ackAlarm: ackAlarm, |
49 | 49 | clearAlarm: clearAlarm, |
50 | 50 | getAlarms: getAlarms, |
51 | + getHighestAlarmSeverity: getHighestAlarmSeverity, | |
51 | 52 | pollAlarms: pollAlarms, |
52 | 53 | cancelPollAlarms: cancelPollAlarms, |
53 | 54 | subscribeForAlarms: subscribeForAlarms, |
... | ... | @@ -165,6 +166,23 @@ function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) { |
165 | 166 | return deferred.promise; |
166 | 167 | } |
167 | 168 | |
169 | + function getHighestAlarmSeverity(entityType, entityId, alarmSearchStatus, alarmStatus, config) { | |
170 | + var deferred = $q.defer(); | |
171 | + var url = '/api/alarm/highestSeverity/' + entityType + '/' + entityId; | |
172 | + | |
173 | + if (alarmSearchStatus) { | |
174 | + url += '?searchStatus=' + alarmSearchStatus; | |
175 | + } else if (alarmStatus) { | |
176 | + url += '?status=' + alarmStatus; | |
177 | + } | |
178 | + $http.get(url, config).then(function success(response) { | |
179 | + deferred.resolve(response.data); | |
180 | + }, function fail() { | |
181 | + deferred.reject(); | |
182 | + }); | |
183 | + return deferred.promise; | |
184 | + } | |
185 | + | |
168 | 186 | function fetchAlarms(alarmsQuery, pageLink, deferred, alarmsList) { |
169 | 187 | getAlarms(alarmsQuery.entityType, alarmsQuery.entityId, |
170 | 188 | pageLink, alarmsQuery.alarmSearchStatus, alarmsQuery.alarmStatus, | ... | ... |