Commit 351684a6cdefc028213ace04234b49e6dc13661d
1 parent
2cb71c15
TB-63: Update Alarms search query with AlarmSearchStatus parameter.
Showing
14 changed files
with
230 additions
and
43 deletions
@@ -22,10 +22,7 @@ import org.springframework.security.access.prepost.PreAuthorize; | @@ -22,10 +22,7 @@ import org.springframework.security.access.prepost.PreAuthorize; | ||
22 | import org.springframework.web.bind.annotation.*; | 22 | import org.springframework.web.bind.annotation.*; |
23 | import org.thingsboard.server.common.data.Customer; | 23 | import org.thingsboard.server.common.data.Customer; |
24 | import org.thingsboard.server.common.data.Event; | 24 | import org.thingsboard.server.common.data.Event; |
25 | -import org.thingsboard.server.common.data.alarm.Alarm; | ||
26 | -import org.thingsboard.server.common.data.alarm.AlarmId; | ||
27 | -import org.thingsboard.server.common.data.alarm.AlarmQuery; | ||
28 | -import org.thingsboard.server.common.data.alarm.AlarmStatus; | 25 | +import org.thingsboard.server.common.data.alarm.*; |
29 | import org.thingsboard.server.common.data.asset.Asset; | 26 | import org.thingsboard.server.common.data.asset.Asset; |
30 | import org.thingsboard.server.common.data.id.*; | 27 | import org.thingsboard.server.common.data.id.*; |
31 | import org.thingsboard.server.common.data.page.TextPageData; | 28 | import org.thingsboard.server.common.data.page.TextPageData; |
@@ -103,24 +100,31 @@ public class AlarmController extends BaseController { | @@ -103,24 +100,31 @@ public class AlarmController extends BaseController { | ||
103 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | 100 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
104 | @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET) | 101 | @RequestMapping(value = "/alarm/{entityType}/{entityId}", method = RequestMethod.GET) |
105 | @ResponseBody | 102 | @ResponseBody |
106 | - public TimePageData<Alarm> getAlarms( | 103 | + public TimePageData<AlarmInfo> getAlarms( |
107 | @PathVariable("entityType") String strEntityType, | 104 | @PathVariable("entityType") String strEntityType, |
108 | @PathVariable("entityId") String strEntityId, | 105 | @PathVariable("entityId") String strEntityId, |
106 | + @RequestParam(required = false) String searchStatus, | ||
109 | @RequestParam(required = false) String status, | 107 | @RequestParam(required = false) String status, |
110 | @RequestParam int limit, | 108 | @RequestParam int limit, |
111 | @RequestParam(required = false) Long startTime, | 109 | @RequestParam(required = false) Long startTime, |
112 | @RequestParam(required = false) Long endTime, | 110 | @RequestParam(required = false) Long endTime, |
113 | @RequestParam(required = false, defaultValue = "false") boolean ascOrder, | 111 | @RequestParam(required = false, defaultValue = "false") boolean ascOrder, |
114 | - @RequestParam(required = false) String offset | 112 | + @RequestParam(required = false) String offset, |
113 | + @RequestParam(required = false) Boolean fetchOriginator | ||
115 | ) throws ThingsboardException { | 114 | ) throws ThingsboardException { |
116 | checkParameter("EntityId", strEntityId); | 115 | checkParameter("EntityId", strEntityId); |
117 | checkParameter("EntityType", strEntityType); | 116 | checkParameter("EntityType", strEntityType); |
118 | EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); | 117 | EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId); |
118 | + AlarmSearchStatus alarmSearchStatus = StringUtils.isEmpty(searchStatus) ? null : AlarmSearchStatus.valueOf(searchStatus); | ||
119 | AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status); | 119 | AlarmStatus alarmStatus = StringUtils.isEmpty(status) ? null : AlarmStatus.valueOf(status); |
120 | + if (alarmSearchStatus != null && alarmStatus != null) { | ||
121 | + throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " + | ||
122 | + "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | ||
123 | + } | ||
120 | checkEntityId(entityId); | 124 | checkEntityId(entityId); |
121 | try { | 125 | try { |
122 | TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); | 126 | TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset); |
123 | - return checkNotNull(alarmService.findAlarms(new AlarmQuery(entityId, pageLink, alarmStatus)).get()); | 127 | + return checkNotNull(alarmService.findAlarms(new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get()); |
124 | } catch (Exception e) { | 128 | } catch (Exception e) { |
125 | throw handleException(e); | 129 | throw handleException(e); |
126 | } | 130 | } |
@@ -53,6 +53,21 @@ public class Alarm extends BaseData<AlarmId> implements HasName { | @@ -53,6 +53,21 @@ public class Alarm extends BaseData<AlarmId> implements HasName { | ||
53 | super(id); | 53 | super(id); |
54 | } | 54 | } |
55 | 55 | ||
56 | + public Alarm(Alarm alarm) { | ||
57 | + super(alarm.getId()); | ||
58 | + this.tenantId = alarm.getTenantId(); | ||
59 | + this.type = alarm.getType(); | ||
60 | + this.originator = alarm.getOriginator(); | ||
61 | + this.severity = alarm.getSeverity(); | ||
62 | + this.status = alarm.getStatus(); | ||
63 | + this.startTs = alarm.getStartTs(); | ||
64 | + this.endTs = alarm.getEndTs(); | ||
65 | + this.ackTs = alarm.getAckTs(); | ||
66 | + this.clearTs = alarm.getClearTs(); | ||
67 | + this.details = alarm.getDetails(); | ||
68 | + this.propagate = alarm.isPropagate(); | ||
69 | + } | ||
70 | + | ||
56 | @Override | 71 | @Override |
57 | @JsonProperty(access = JsonProperty.Access.READ_ONLY) | 72 | @JsonProperty(access = JsonProperty.Access.READ_ONLY) |
58 | public String getName() { | 73 | public String getName() { |
1 | +/** | ||
2 | + * Copyright © 2016-2017 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.alarm; | ||
17 | + | ||
18 | +public class AlarmInfo extends Alarm { | ||
19 | + | ||
20 | + private static final long serialVersionUID = 2807343093519543363L; | ||
21 | + | ||
22 | + private String originatorName; | ||
23 | + | ||
24 | + public AlarmInfo() { | ||
25 | + super(); | ||
26 | + } | ||
27 | + | ||
28 | + public AlarmInfo(Alarm alarm) { | ||
29 | + super(alarm); | ||
30 | + } | ||
31 | + | ||
32 | + public String getOriginatorName() { | ||
33 | + return originatorName; | ||
34 | + } | ||
35 | + | ||
36 | + public void setOriginatorName(String originatorName) { | ||
37 | + this.originatorName = originatorName; | ||
38 | + } | ||
39 | + | ||
40 | + @Override | ||
41 | + public boolean equals(Object o) { | ||
42 | + if (this == o) return true; | ||
43 | + if (o == null || getClass() != o.getClass()) return false; | ||
44 | + if (!super.equals(o)) return false; | ||
45 | + | ||
46 | + AlarmInfo alarmInfo = (AlarmInfo) o; | ||
47 | + | ||
48 | + return originatorName != null ? originatorName.equals(alarmInfo.originatorName) : alarmInfo.originatorName == null; | ||
49 | + | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public int hashCode() { | ||
54 | + int result = super.hashCode(); | ||
55 | + result = 31 * result + (originatorName != null ? originatorName.hashCode() : 0); | ||
56 | + return result; | ||
57 | + } | ||
58 | +} |
@@ -32,6 +32,8 @@ public class AlarmQuery { | @@ -32,6 +32,8 @@ public class AlarmQuery { | ||
32 | 32 | ||
33 | private EntityId affectedEntityId; | 33 | private EntityId affectedEntityId; |
34 | private TimePageLink pageLink; | 34 | private TimePageLink pageLink; |
35 | + private AlarmSearchStatus searchStatus; | ||
35 | private AlarmStatus status; | 36 | private AlarmStatus status; |
37 | + private Boolean fetchOriginator; | ||
36 | 38 | ||
37 | } | 39 | } |
common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmSearchStatus.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2017 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +package org.thingsboard.server.common.data.alarm; | ||
18 | + | ||
19 | +public enum AlarmSearchStatus { | ||
20 | + | ||
21 | + ANY, ACTIVE, CLEARED, ACK, UNACK | ||
22 | + | ||
23 | +} |
@@ -30,4 +30,13 @@ public enum AlarmStatus { | @@ -30,4 +30,13 @@ public enum AlarmStatus { | ||
30 | return this == CLEARED_ACK || this == CLEARED_UNACK; | 30 | return this == CLEARED_ACK || this == CLEARED_UNACK; |
31 | } | 31 | } |
32 | 32 | ||
33 | + public AlarmSearchStatus getClearSearchStatus() { | ||
34 | + return this.isCleared() ? AlarmSearchStatus.CLEARED : AlarmSearchStatus.ACTIVE; | ||
35 | + } | ||
36 | + | ||
37 | + public AlarmSearchStatus getAckSearchStatus() { | ||
38 | + return this.isAck() ? AlarmSearchStatus.ACK : AlarmSearchStatus.UNACK; | ||
39 | + } | ||
40 | + | ||
41 | + | ||
33 | } | 42 | } |
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; | ||
17 | 17 | ||
18 | import com.google.common.util.concurrent.ListenableFuture; | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | import org.thingsboard.server.common.data.alarm.Alarm; | 19 | import org.thingsboard.server.common.data.alarm.Alarm; |
20 | +import org.thingsboard.server.common.data.alarm.AlarmInfo; | ||
20 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 21 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
21 | import org.thingsboard.server.common.data.id.EntityId; | 22 | import org.thingsboard.server.common.data.id.EntityId; |
22 | import org.thingsboard.server.common.data.id.TenantId; | 23 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -37,5 +38,5 @@ public interface AlarmDao extends Dao<AlarmEntity> { | @@ -37,5 +38,5 @@ public interface AlarmDao extends Dao<AlarmEntity> { | ||
37 | 38 | ||
38 | AlarmEntity save(Alarm alarm); | 39 | AlarmEntity save(Alarm alarm); |
39 | 40 | ||
40 | - ListenableFuture<List<Alarm>> findAlarms(AlarmQuery query); | 41 | + ListenableFuture<List<AlarmInfo>> findAlarms(AlarmQuery query); |
41 | } | 42 | } |
@@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; | @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.alarm; | ||
17 | 17 | ||
18 | import com.datastax.driver.core.querybuilder.QueryBuilder; | 18 | import com.datastax.driver.core.querybuilder.QueryBuilder; |
19 | import com.datastax.driver.core.querybuilder.Select; | 19 | import com.datastax.driver.core.querybuilder.Select; |
20 | +import com.google.common.base.Function; | ||
20 | import com.google.common.util.concurrent.AsyncFunction; | 21 | import com.google.common.util.concurrent.AsyncFunction; |
21 | import com.google.common.util.concurrent.Futures; | 22 | import com.google.common.util.concurrent.Futures; |
22 | import com.google.common.util.concurrent.ListenableFuture; | 23 | import com.google.common.util.concurrent.ListenableFuture; |
@@ -25,7 +26,9 @@ import org.springframework.beans.factory.annotation.Autowired; | @@ -25,7 +26,9 @@ import org.springframework.beans.factory.annotation.Autowired; | ||
25 | import org.springframework.stereotype.Component; | 26 | import org.springframework.stereotype.Component; |
26 | import org.thingsboard.server.common.data.EntityType; | 27 | import org.thingsboard.server.common.data.EntityType; |
27 | import org.thingsboard.server.common.data.alarm.Alarm; | 28 | import org.thingsboard.server.common.data.alarm.Alarm; |
29 | +import org.thingsboard.server.common.data.alarm.AlarmInfo; | ||
28 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 30 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
31 | +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | ||
29 | import org.thingsboard.server.common.data.id.EntityId; | 32 | import org.thingsboard.server.common.data.id.EntityId; |
30 | import org.thingsboard.server.common.data.id.TenantId; | 33 | import org.thingsboard.server.common.data.id.TenantId; |
31 | import org.thingsboard.server.common.data.relation.EntityRelation; | 34 | import org.thingsboard.server.common.data.relation.EntityRelation; |
@@ -94,15 +97,25 @@ public class AlarmDaoImpl extends AbstractModelDao<AlarmEntity> implements Alarm | @@ -94,15 +97,25 @@ public class AlarmDaoImpl extends AbstractModelDao<AlarmEntity> implements Alarm | ||
94 | } | 97 | } |
95 | 98 | ||
96 | @Override | 99 | @Override |
97 | - public ListenableFuture<List<Alarm>> findAlarms(AlarmQuery query) { | ||
98 | - log.trace("Try to find alarms by entity [{}], status [{}] and pageLink [{}]", query.getAffectedEntityId(), query.getStatus(), query.getPageLink()); | 100 | + public ListenableFuture<List<AlarmInfo>> findAlarms(AlarmQuery query) { |
101 | + log.trace("Try to find alarms by entity [{}], searchStatus [{}], status [{}] and pageLink [{}]", query.getAffectedEntityId(), query.getSearchStatus(), query.getStatus(), query.getPageLink()); | ||
99 | EntityId affectedEntity = query.getAffectedEntityId(); | 102 | EntityId affectedEntity = query.getAffectedEntityId(); |
100 | - String relationType = query.getStatus() == null ? BaseAlarmService.ALARM_RELATION : BaseAlarmService.ALARM_RELATION_PREFIX + query.getStatus().name(); | 103 | + String searchStatusName; |
104 | + if (query.getSearchStatus() == null && query.getStatus() == null) { | ||
105 | + searchStatusName = AlarmSearchStatus.ANY.name(); | ||
106 | + } else if (query.getSearchStatus() != null) { | ||
107 | + searchStatusName = query.getSearchStatus().name(); | ||
108 | + } else { | ||
109 | + searchStatusName = query.getStatus().name(); | ||
110 | + } | ||
111 | + String relationType = BaseAlarmService.ALARM_RELATION_PREFIX + searchStatusName; | ||
101 | ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(affectedEntity, relationType, RelationTypeGroup.ALARM, EntityType.ALARM, query.getPageLink()); | 112 | ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(affectedEntity, relationType, RelationTypeGroup.ALARM, EntityType.ALARM, query.getPageLink()); |
102 | - return Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<Alarm>>) input -> { | ||
103 | - List<ListenableFuture<Alarm>> alarmFutures = new ArrayList<>(input.size()); | 113 | + return Futures.transform(relations, (AsyncFunction<List<EntityRelation>, List<AlarmInfo>>) input -> { |
114 | + List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(input.size()); | ||
104 | for (EntityRelation relation : input) { | 115 | for (EntityRelation relation : input) { |
105 | - alarmFutures.add(findAlarmByIdAsync(relation.getTo().getId())); | 116 | + alarmFutures.add(Futures.transform( |
117 | + findAlarmByIdAsync(relation.getTo().getId()), (Function<Alarm, AlarmInfo>) | ||
118 | + alarm1 -> new AlarmInfo(alarm1))); | ||
106 | } | 119 | } |
107 | return Futures.successfulAsList(alarmFutures); | 120 | return Futures.successfulAsList(alarmFutures); |
108 | }); | 121 | }); |
@@ -18,6 +18,7 @@ package org.thingsboard.server.dao.alarm; | @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.alarm; | ||
18 | import com.google.common.util.concurrent.ListenableFuture; | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | import org.thingsboard.server.common.data.alarm.Alarm; | 19 | import org.thingsboard.server.common.data.alarm.Alarm; |
20 | import org.thingsboard.server.common.data.alarm.AlarmId; | 20 | import org.thingsboard.server.common.data.alarm.AlarmId; |
21 | +import org.thingsboard.server.common.data.alarm.AlarmInfo; | ||
21 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 22 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
22 | import org.thingsboard.server.common.data.page.TimePageData; | 23 | import org.thingsboard.server.common.data.page.TimePageData; |
23 | 24 | ||
@@ -34,6 +35,6 @@ public interface AlarmService { | @@ -34,6 +35,6 @@ public interface AlarmService { | ||
34 | 35 | ||
35 | ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId); | 36 | ListenableFuture<Alarm> findAlarmByIdAsync(AlarmId alarmId); |
36 | 37 | ||
37 | - ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query); | 38 | + ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query); |
38 | 39 | ||
39 | } | 40 | } |
@@ -17,22 +17,21 @@ package org.thingsboard.server.dao.alarm; | @@ -17,22 +17,21 @@ package org.thingsboard.server.dao.alarm; | ||
17 | 17 | ||
18 | 18 | ||
19 | import com.google.common.base.Function; | 19 | import com.google.common.base.Function; |
20 | +import com.google.common.util.concurrent.AsyncFunction; | ||
20 | import com.google.common.util.concurrent.Futures; | 21 | import com.google.common.util.concurrent.Futures; |
21 | import com.google.common.util.concurrent.ListenableFuture; | 22 | import com.google.common.util.concurrent.ListenableFuture; |
22 | import lombok.extern.slf4j.Slf4j; | 23 | import lombok.extern.slf4j.Slf4j; |
23 | import org.springframework.beans.factory.annotation.Autowired; | 24 | import org.springframework.beans.factory.annotation.Autowired; |
24 | import org.springframework.stereotype.Service; | 25 | import org.springframework.stereotype.Service; |
25 | import org.springframework.util.StringUtils; | 26 | import org.springframework.util.StringUtils; |
26 | -import org.thingsboard.server.common.data.alarm.Alarm; | ||
27 | -import org.thingsboard.server.common.data.alarm.AlarmId; | ||
28 | -import org.thingsboard.server.common.data.alarm.AlarmQuery; | ||
29 | -import org.thingsboard.server.common.data.alarm.AlarmStatus; | 27 | +import org.thingsboard.server.common.data.alarm.*; |
30 | import org.thingsboard.server.common.data.id.EntityId; | 28 | import org.thingsboard.server.common.data.id.EntityId; |
31 | import org.thingsboard.server.common.data.page.TimePageData; | 29 | import org.thingsboard.server.common.data.page.TimePageData; |
32 | import org.thingsboard.server.common.data.relation.EntityRelation; | 30 | import org.thingsboard.server.common.data.relation.EntityRelation; |
33 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; | 31 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
34 | import org.thingsboard.server.dao.entity.AbstractEntityService; | 32 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
35 | import org.thingsboard.server.dao.entity.BaseEntityService; | 33 | import org.thingsboard.server.dao.entity.BaseEntityService; |
34 | +import org.thingsboard.server.dao.entity.EntityService; | ||
36 | import org.thingsboard.server.dao.exception.DataValidationException; | 35 | import org.thingsboard.server.dao.exception.DataValidationException; |
37 | import org.thingsboard.server.dao.model.*; | 36 | import org.thingsboard.server.dao.model.*; |
38 | import org.thingsboard.server.dao.relation.EntityRelationsQuery; | 37 | import org.thingsboard.server.dao.relation.EntityRelationsQuery; |
@@ -45,6 +44,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; | @@ -45,6 +44,7 @@ import org.thingsboard.server.dao.tenant.TenantDao; | ||
45 | import javax.annotation.Nullable; | 44 | import javax.annotation.Nullable; |
46 | import javax.annotation.PostConstruct; | 45 | import javax.annotation.PostConstruct; |
47 | import javax.annotation.PreDestroy; | 46 | import javax.annotation.PreDestroy; |
47 | +import java.util.ArrayList; | ||
48 | import java.util.List; | 48 | import java.util.List; |
49 | import java.util.concurrent.ExecutionException; | 49 | import java.util.concurrent.ExecutionException; |
50 | import java.util.concurrent.ExecutorService; | 50 | import java.util.concurrent.ExecutorService; |
@@ -59,7 +59,6 @@ import static org.thingsboard.server.dao.service.Validator.*; | @@ -59,7 +59,6 @@ import static org.thingsboard.server.dao.service.Validator.*; | ||
59 | public class BaseAlarmService extends AbstractEntityService implements AlarmService { | 59 | public class BaseAlarmService extends AbstractEntityService implements AlarmService { |
60 | 60 | ||
61 | public static final String ALARM_RELATION_PREFIX = "ALARM_"; | 61 | public static final String ALARM_RELATION_PREFIX = "ALARM_"; |
62 | - public static final String ALARM_RELATION = "ALARM_ANY"; | ||
63 | 62 | ||
64 | @Autowired | 63 | @Autowired |
65 | private AlarmDao alarmDao; | 64 | private AlarmDao alarmDao; |
@@ -70,6 +69,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | @@ -70,6 +69,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | ||
70 | @Autowired | 69 | @Autowired |
71 | private RelationService relationService; | 70 | private RelationService relationService; |
72 | 71 | ||
72 | + @Autowired | ||
73 | + private EntityService entityService; | ||
74 | + | ||
73 | protected ExecutorService readResultsProcessingExecutor; | 75 | protected ExecutorService readResultsProcessingExecutor; |
74 | 76 | ||
75 | @PostConstruct | 77 | @PostConstruct |
@@ -116,11 +118,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | @@ -116,11 +118,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | ||
116 | query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); | 118 | query.setParameters(new RelationsSearchParameters(saved.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); |
117 | List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); | 119 | List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); |
118 | for (EntityId parentId : parentEntities) { | 120 | for (EntityId parentId : parentEntities) { |
119 | - createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION, RelationTypeGroup.ALARM)); | ||
120 | - createRelation(new EntityRelation(parentId, saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name(), RelationTypeGroup.ALARM)); | 121 | + createAlarmRelation(parentId, saved.getId(), saved.getStatus(), true); |
121 | } | 122 | } |
122 | - createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION, RelationTypeGroup.ALARM)); | ||
123 | - createRelation(new EntityRelation(alarm.getOriginator(), saved.getId(), ALARM_RELATION_PREFIX + saved.getStatus().name(), RelationTypeGroup.ALARM)); | 123 | + createAlarmRelation(alarm.getOriginator(), saved.getId(), saved.getStatus(), true); |
124 | return saved; | 124 | return saved; |
125 | } | 125 | } |
126 | 126 | ||
@@ -199,12 +199,27 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | @@ -199,12 +199,27 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | ||
199 | } | 199 | } |
200 | 200 | ||
201 | @Override | 201 | @Override |
202 | - public ListenableFuture<TimePageData<Alarm>> findAlarms(AlarmQuery query) { | ||
203 | - ListenableFuture<List<Alarm>> alarms = alarmDao.findAlarms(query); | ||
204 | - return Futures.transform(alarms, new Function<List<Alarm>, TimePageData<Alarm>>() { | 202 | + public ListenableFuture<TimePageData<AlarmInfo>> findAlarms(AlarmQuery query) { |
203 | + ListenableFuture<List<AlarmInfo>> alarms = alarmDao.findAlarms(query); | ||
204 | + if (query.getFetchOriginator() != null && query.getFetchOriginator().booleanValue()) { | ||
205 | + alarms = Futures.transform(alarms, (AsyncFunction<List<AlarmInfo>, List<AlarmInfo>>) input -> { | ||
206 | + List<ListenableFuture<AlarmInfo>> alarmFutures = new ArrayList<>(input.size()); | ||
207 | + for (AlarmInfo alarmInfo : input) { | ||
208 | + alarmFutures.add(Futures.transform( | ||
209 | + entityService.fetchEntityNameAsync(alarmInfo.getOriginator()), (Function<String, AlarmInfo>) | ||
210 | + originatorName -> { | ||
211 | + alarmInfo.setOriginatorName(originatorName); | ||
212 | + return alarmInfo; | ||
213 | + } | ||
214 | + )); | ||
215 | + } | ||
216 | + return Futures.successfulAsList(alarmFutures); | ||
217 | + }); | ||
218 | + } | ||
219 | + return Futures.transform(alarms, new Function<List<AlarmInfo>, TimePageData<AlarmInfo>>() { | ||
205 | @Nullable | 220 | @Nullable |
206 | @Override | 221 | @Override |
207 | - public TimePageData<Alarm> apply(@Nullable List<Alarm> alarms) { | 222 | + public TimePageData<AlarmInfo> apply(@Nullable List<AlarmInfo> alarms) { |
208 | return new TimePageData<>(alarms, query.getPageLink()); | 223 | return new TimePageData<>(alarms, query.getPageLink()); |
209 | } | 224 | } |
210 | }); | 225 | }); |
@@ -245,17 +260,45 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | @@ -245,17 +260,45 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | ||
245 | query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); | 260 | query.setParameters(new RelationsSearchParameters(alarm.getOriginator(), EntitySearchDirection.TO, Integer.MAX_VALUE)); |
246 | List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); | 261 | List<EntityId> parentEntities = relationService.findByQuery(query).get().stream().map(r -> r.getFrom()).collect(Collectors.toList()); |
247 | for (EntityId parentId : parentEntities) { | 262 | for (EntityId parentId : parentEntities) { |
248 | - deleteRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name(), RelationTypeGroup.ALARM)); | ||
249 | - createRelation(new EntityRelation(parentId, alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name(), RelationTypeGroup.ALARM)); | ||
250 | - } | ||
251 | - deleteRelation(new EntityRelation(alarm.getOriginator(), alarm.getId(), ALARM_RELATION_PREFIX + oldStatus.name(), RelationTypeGroup.ALARM)); | ||
252 | - createRelation(new EntityRelation(alarm.getOriginator(), alarm.getId(), ALARM_RELATION_PREFIX + newStatus.name(), RelationTypeGroup.ALARM)); | 263 | + updateAlarmRelation(parentId, alarm.getId(), oldStatus, newStatus); |
264 | + } | ||
265 | + updateAlarmRelation(alarm.getOriginator(), alarm.getId(), oldStatus, newStatus); | ||
253 | } catch (ExecutionException | InterruptedException e) { | 266 | } catch (ExecutionException | InterruptedException e) { |
254 | log.warn("[{}] Failed to update relations. Old status: [{}], New status: [{}]", alarm.getId(), oldStatus, newStatus); | 267 | log.warn("[{}] Failed to update relations. Old status: [{}], New status: [{}]", alarm.getId(), oldStatus, newStatus); |
255 | throw new RuntimeException(e); | 268 | throw new RuntimeException(e); |
256 | } | 269 | } |
257 | } | 270 | } |
258 | 271 | ||
272 | + private void createAlarmRelation(EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) { | ||
273 | + try { | ||
274 | + if (createAnyRelation) { | ||
275 | + createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM)); | ||
276 | + } | ||
277 | + createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM)); | ||
278 | + createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM)); | ||
279 | + createRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM)); | ||
280 | + } catch (ExecutionException | InterruptedException e) { | ||
281 | + log.warn("[{}] Failed to create relation. Status: [{}]", alarmId, status); | ||
282 | + throw new RuntimeException(e); | ||
283 | + } | ||
284 | + } | ||
285 | + | ||
286 | + private void deleteAlarmRelation(EntityId entityId, EntityId alarmId, AlarmStatus status) { | ||
287 | + try { | ||
288 | + deleteRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM)); | ||
289 | + deleteRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM)); | ||
290 | + deleteRelation(new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM)); | ||
291 | + } catch (ExecutionException | InterruptedException e) { | ||
292 | + log.warn("[{}] Failed to delete relation. Status: [{}]", alarmId, status); | ||
293 | + throw new RuntimeException(e); | ||
294 | + } | ||
295 | + } | ||
296 | + | ||
297 | + private void updateAlarmRelation(EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) { | ||
298 | + deleteAlarmRelation(entityId, alarmId, oldStatus); | ||
299 | + createAlarmRelation(entityId, alarmId, newStatus, false); | ||
300 | + } | ||
301 | + | ||
259 | private <T> ListenableFuture<T> getAndUpdate(AlarmId alarmId, Function<Alarm, T> function) { | 302 | private <T> ListenableFuture<T> getAndUpdate(AlarmId alarmId, Function<Alarm, T> function) { |
260 | validateId(alarmId, "Alarm id should be specified!"); | 303 | validateId(alarmId, "Alarm id should be specified!"); |
261 | ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(alarmId.getId()); | 304 | ListenableFuture<Alarm> entity = alarmDao.findAlarmByIdAsync(alarmId.getId()); |
@@ -178,9 +178,14 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { | @@ -178,9 +178,14 @@ public class BaseRelationDao extends AbstractAsyncDao implements RelationDao { | ||
178 | eq(ModelConstants.RELATION_TYPE_GROUP_PROPERTY, typeGroup.name()), | 178 | eq(ModelConstants.RELATION_TYPE_GROUP_PROPERTY, typeGroup.name()), |
179 | eq(ModelConstants.RELATION_TYPE_PROPERTY, relationType), | 179 | eq(ModelConstants.RELATION_TYPE_PROPERTY, relationType), |
180 | eq(ModelConstants.RELATION_TO_TYPE_PROPERTY, childType.name())), | 180 | eq(ModelConstants.RELATION_TO_TYPE_PROPERTY, childType.name())), |
181 | - Arrays.asList(QueryBuilder.asc(ModelConstants.RELATION_TYPE_GROUP_PROPERTY), | ||
182 | - QueryBuilder.asc(ModelConstants.RELATION_TYPE_PROPERTY), | ||
183 | - QueryBuilder.asc(ModelConstants.RELATION_TO_TYPE_PROPERTY)), | 181 | + Arrays.asList( |
182 | + pageLink.isAscOrder() ? QueryBuilder.desc(ModelConstants.RELATION_TYPE_GROUP_PROPERTY) : | ||
183 | + QueryBuilder.asc(ModelConstants.RELATION_TYPE_GROUP_PROPERTY), | ||
184 | + pageLink.isAscOrder() ? QueryBuilder.desc(ModelConstants.RELATION_TYPE_PROPERTY) : | ||
185 | + QueryBuilder.asc(ModelConstants.RELATION_TYPE_PROPERTY), | ||
186 | + pageLink.isAscOrder() ? QueryBuilder.desc(ModelConstants.RELATION_TO_TYPE_PROPERTY) : | ||
187 | + QueryBuilder.asc(ModelConstants.RELATION_TO_TYPE_PROPERTY) | ||
188 | + ), | ||
184 | pageLink, ModelConstants.RELATION_TO_ID_PROPERTY); | 189 | pageLink, ModelConstants.RELATION_TO_ID_PROPERTY); |
185 | return getFuture(executeAsyncRead(query), rs -> getEntityRelations(rs)); | 190 | return getFuture(executeAsyncRead(query), rs -> getEntityRelations(rs)); |
186 | } | 191 | } |
@@ -22,10 +22,7 @@ import org.junit.Before; | @@ -22,10 +22,7 @@ import org.junit.Before; | ||
22 | import org.junit.Test; | 22 | import org.junit.Test; |
23 | import org.thingsboard.server.common.data.EntityType; | 23 | import org.thingsboard.server.common.data.EntityType; |
24 | import org.thingsboard.server.common.data.Tenant; | 24 | import org.thingsboard.server.common.data.Tenant; |
25 | -import org.thingsboard.server.common.data.alarm.Alarm; | ||
26 | -import org.thingsboard.server.common.data.alarm.AlarmQuery; | ||
27 | -import org.thingsboard.server.common.data.alarm.AlarmSeverity; | ||
28 | -import org.thingsboard.server.common.data.alarm.AlarmStatus; | 25 | +import org.thingsboard.server.common.data.alarm.*; |
29 | import org.thingsboard.server.common.data.id.AssetId; | 26 | import org.thingsboard.server.common.data.id.AssetId; |
30 | import org.thingsboard.server.common.data.id.DeviceId; | 27 | import org.thingsboard.server.common.data.id.DeviceId; |
31 | import org.thingsboard.server.common.data.id.TenantId; | 28 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -117,7 +114,7 @@ public class AlarmServiceTest extends AbstractServiceTest { | @@ -117,7 +114,7 @@ public class AlarmServiceTest extends AbstractServiceTest { | ||
117 | Alarm created = alarmService.createOrUpdateAlarm(alarm); | 114 | Alarm created = alarmService.createOrUpdateAlarm(alarm); |
118 | 115 | ||
119 | // Check child relation | 116 | // Check child relation |
120 | - TimePageData<Alarm> alarms = alarmService.findAlarms(AlarmQuery.builder() | 117 | + TimePageData<AlarmInfo> alarms = alarmService.findAlarms(AlarmQuery.builder() |
121 | .affectedEntityId(childId) | 118 | .affectedEntityId(childId) |
122 | .status(AlarmStatus.ACTIVE_UNACK).pageLink( | 119 | .status(AlarmStatus.ACTIVE_UNACK).pageLink( |
123 | new TimePageLink(1, 0L, System.currentTimeMillis(), false) | 120 | new TimePageLink(1, 0L, System.currentTimeMillis(), false) |
@@ -91,7 +91,7 @@ function AlarmService($http, $q, $interval, $filter) { | @@ -91,7 +91,7 @@ function AlarmService($http, $q, $interval, $filter) { | ||
91 | return deferred.promise; | 91 | return deferred.promise; |
92 | } | 92 | } |
93 | 93 | ||
94 | - function getAlarms(entityType, entityId, pageLink, alarmStatus, ascOrder, config) { | 94 | + function getAlarms(entityType, entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator, ascOrder, config) { |
95 | var deferred = $q.defer(); | 95 | var deferred = $q.defer(); |
96 | var url = '/api/alarm/' + entityType + '/' + entityId + '?limit=' + pageLink.limit; | 96 | var url = '/api/alarm/' + entityType + '/' + entityId + '?limit=' + pageLink.limit; |
97 | 97 | ||
@@ -104,9 +104,15 @@ function AlarmService($http, $q, $interval, $filter) { | @@ -104,9 +104,15 @@ function AlarmService($http, $q, $interval, $filter) { | ||
104 | if (angular.isDefined(pageLink.idOffset)) { | 104 | if (angular.isDefined(pageLink.idOffset)) { |
105 | url += '&offset=' + pageLink.idOffset; | 105 | url += '&offset=' + pageLink.idOffset; |
106 | } | 106 | } |
107 | + if (alarmSearchStatus) { | ||
108 | + url += '&searchStatus=' + alarmSearchStatus; | ||
109 | + } | ||
107 | if (alarmStatus) { | 110 | if (alarmStatus) { |
108 | url += '&status=' + alarmStatus; | 111 | url += '&status=' + alarmStatus; |
109 | } | 112 | } |
113 | + if (fetchOriginator) { | ||
114 | + url += '&fetchOriginator=' + ((fetchOriginator===true) ? 'true' : 'false'); | ||
115 | + } | ||
110 | if (angular.isDefined(ascOrder) && ascOrder != null) { | 116 | if (angular.isDefined(ascOrder) && ascOrder != null) { |
111 | url += '&ascOrder=' + (ascOrder ? 'true' : 'false'); | 117 | url += '&ascOrder=' + (ascOrder ? 'true' : 'false'); |
112 | } | 118 | } |
@@ -121,7 +127,8 @@ function AlarmService($http, $q, $interval, $filter) { | @@ -121,7 +127,8 @@ function AlarmService($http, $q, $interval, $filter) { | ||
121 | 127 | ||
122 | function fetchAlarms(alarmsQuery, pageLink, deferred, alarmsList) { | 128 | function fetchAlarms(alarmsQuery, pageLink, deferred, alarmsList) { |
123 | getAlarms(alarmsQuery.entityType, alarmsQuery.entityId, | 129 | getAlarms(alarmsQuery.entityType, alarmsQuery.entityId, |
124 | - pageLink, alarmsQuery.alarmStatus, false, {ignoreLoading: true}).then( | 130 | + pageLink, alarmsQuery.alarmSearchStatus, alarmsQuery.alarmStatus, |
131 | + alarmsQuery.fetchOriginator, false, {ignoreLoading: true}).then( | ||
125 | function success(alarms) { | 132 | function success(alarms) { |
126 | if (!alarmsList) { | 133 | if (!alarmsList) { |
127 | alarmsList = []; | 134 | alarmsList = []; |
@@ -171,7 +178,9 @@ function AlarmService($http, $q, $interval, $filter) { | @@ -171,7 +178,9 @@ function AlarmService($http, $q, $interval, $filter) { | ||
171 | var alarmsQuery = { | 178 | var alarmsQuery = { |
172 | entityType: entityType, | 179 | entityType: entityType, |
173 | entityId: entityId, | 180 | entityId: entityId, |
181 | + alarmSearchStatus: null, | ||
174 | alarmStatus: alarmStatus, | 182 | alarmStatus: alarmStatus, |
183 | + fetchOriginator: false, | ||
175 | interval: interval, | 184 | interval: interval, |
176 | limit: limit, | 185 | limit: limit, |
177 | onAlarms: onAlarms | 186 | onAlarms: onAlarms |
@@ -65,6 +65,13 @@ export default angular.module('thingsboard.types', []) | @@ -65,6 +65,13 @@ export default angular.module('thingsboard.types', []) | ||
65 | clearedUnack: "CLEARED_UNACK", | 65 | clearedUnack: "CLEARED_UNACK", |
66 | clearedAck: "CLEARED_ACK" | 66 | clearedAck: "CLEARED_ACK" |
67 | }, | 67 | }, |
68 | + alarmSearchStatus: { | ||
69 | + any: "ANY", | ||
70 | + active: "ACTIVE", | ||
71 | + cleared: "CLEARED", | ||
72 | + ack: "ACK", | ||
73 | + unack: "UNACK" | ||
74 | + }, | ||
68 | aliasFilterType: { | 75 | aliasFilterType: { |
69 | entityList: { | 76 | entityList: { |
70 | value: 'entityList', | 77 | value: 'entityList', |