Showing
38 changed files
with
1262 additions
and
122 deletions
@@ -34,20 +34,26 @@ import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; | @@ -34,20 +34,26 @@ import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; | ||
34 | import org.thingsboard.server.common.data.kv.ReadTsKvQuery; | 34 | import org.thingsboard.server.common.data.kv.ReadTsKvQuery; |
35 | import org.thingsboard.server.common.data.kv.TsKvEntry; | 35 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
36 | import org.thingsboard.server.common.data.page.PageData; | 36 | import org.thingsboard.server.common.data.page.PageData; |
37 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
38 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
37 | import org.thingsboard.server.common.data.query.EntityData; | 39 | import org.thingsboard.server.common.data.query.EntityData; |
40 | +import org.thingsboard.server.common.data.query.EntityDataPageLink; | ||
38 | import org.thingsboard.server.common.data.query.EntityDataQuery; | 41 | import org.thingsboard.server.common.data.query.EntityDataQuery; |
42 | +import org.thingsboard.server.common.data.query.EntityDataSortOrder; | ||
39 | import org.thingsboard.server.common.data.query.EntityKey; | 43 | import org.thingsboard.server.common.data.query.EntityKey; |
40 | import org.thingsboard.server.common.data.query.EntityKeyType; | 44 | import org.thingsboard.server.common.data.query.EntityKeyType; |
41 | import org.thingsboard.server.common.data.query.TsValue; | 45 | import org.thingsboard.server.common.data.query.TsValue; |
46 | +import org.thingsboard.server.dao.alarm.AlarmService; | ||
42 | import org.thingsboard.server.dao.entity.EntityService; | 47 | import org.thingsboard.server.dao.entity.EntityService; |
43 | -import org.thingsboard.server.dao.entityview.EntityViewService; | 48 | +import org.thingsboard.server.dao.model.ModelConstants; |
44 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 49 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
45 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | 50 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
46 | import org.thingsboard.server.queue.util.TbCoreComponent; | 51 | import org.thingsboard.server.queue.util.TbCoreComponent; |
47 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; | 52 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
48 | -import org.thingsboard.server.service.telemetry.DefaultTelemetryWebSocketService; | ||
49 | import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; | 53 | import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; |
50 | import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; | 54 | import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; |
55 | +import org.thingsboard.server.service.telemetry.cmd.v2.AlarmDataCmd; | ||
56 | +import org.thingsboard.server.service.telemetry.cmd.v2.AlarmDataUpdate; | ||
51 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; | 57 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; |
52 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; | 58 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; |
53 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; | 59 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; |
@@ -63,7 +69,6 @@ import java.util.ArrayList; | @@ -63,7 +69,6 @@ import java.util.ArrayList; | ||
63 | import java.util.Arrays; | 69 | import java.util.Arrays; |
64 | import java.util.Collection; | 70 | import java.util.Collection; |
65 | import java.util.Collections; | 71 | import java.util.Collections; |
66 | -import java.util.Comparator; | ||
67 | import java.util.HashMap; | 72 | import java.util.HashMap; |
68 | import java.util.LinkedHashMap; | 73 | import java.util.LinkedHashMap; |
69 | import java.util.LinkedHashSet; | 74 | import java.util.LinkedHashSet; |
@@ -88,7 +93,7 @@ import java.util.stream.Collectors; | @@ -88,7 +93,7 @@ import java.util.stream.Collectors; | ||
88 | public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubscriptionService { | 93 | public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubscriptionService { |
89 | 94 | ||
90 | private static final int DEFAULT_LIMIT = 100; | 95 | private static final int DEFAULT_LIMIT = 100; |
91 | - private final Map<String, Map<Integer, TbEntityDataSubCtx>> subscriptionsBySessionId = new ConcurrentHashMap<>(); | 96 | + private final Map<String, Map<Integer, TbAbstractDataSubCtx>> subscriptionsBySessionId = new ConcurrentHashMap<>(); |
92 | 97 | ||
93 | @Autowired | 98 | @Autowired |
94 | private TelemetryWebSocketService wsService; | 99 | private TelemetryWebSocketService wsService; |
@@ -97,6 +102,9 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -97,6 +102,9 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
97 | private EntityService entityService; | 102 | private EntityService entityService; |
98 | 103 | ||
99 | @Autowired | 104 | @Autowired |
105 | + private AlarmService alarmService; | ||
106 | + | ||
107 | + @Autowired | ||
100 | @Lazy | 108 | @Lazy |
101 | private TbLocalSubscriptionService localSubscriptionService; | 109 | private TbLocalSubscriptionService localSubscriptionService; |
102 | 110 | ||
@@ -114,10 +122,12 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -114,10 +122,12 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
114 | 122 | ||
115 | @Value("${database.ts.type}") | 123 | @Value("${database.ts.type}") |
116 | private String databaseTsType; | 124 | private String databaseTsType; |
117 | - @Value("${server.ws.dynamic_page_link_refresh_interval:6}") | 125 | + @Value("${server.ws.dynamic_page_link.refresh_interval:6}") |
118 | private long dynamicPageLinkRefreshInterval; | 126 | private long dynamicPageLinkRefreshInterval; |
119 | - @Value("${server.ws.dynamic_page_link_refresh_pool_size:1}") | 127 | + @Value("${server.ws.dynamic_page_link.refresh_pool_size:1}") |
120 | private int dynamicPageLinkRefreshPoolSize; | 128 | private int dynamicPageLinkRefreshPoolSize; |
129 | + @Value("${server.ws.max_entities_per_alarm_subscription:1000}") | ||
130 | + private int maxEntitiesPerAlarmSubscription; | ||
121 | 131 | ||
122 | private ExecutorService wsCallBackExecutor; | 132 | private ExecutorService wsCallBackExecutor; |
123 | private boolean tsInSqlDB; | 133 | private boolean tsInSqlDB; |
@@ -195,6 +205,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -195,6 +205,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
195 | ctx.setData(data); | 205 | ctx.setData(data); |
196 | ctx.cancelRefreshTask(); | 206 | ctx.cancelRefreshTask(); |
197 | if (ctx.getQuery().getPageLink().isDynamic()) { | 207 | if (ctx.getQuery().getPageLink().isDynamic()) { |
208 | + //TODO: validate number of dynamic page links against rate limits. Ignore dynamic flag if limit is reached. | ||
198 | TbEntityDataSubCtx finalCtx = ctx; | 209 | TbEntityDataSubCtx finalCtx = ctx; |
199 | ScheduledFuture<?> task = scheduler.scheduleWithFixedDelay( | 210 | ScheduledFuture<?> task = scheduler.scheduleWithFixedDelay( |
200 | () -> refreshDynamicQuery(tenantId, customerId, finalCtx), | 211 | () -> refreshDynamicQuery(tenantId, customerId, finalCtx), |
@@ -230,6 +241,39 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -230,6 +241,39 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
230 | }, wsCallBackExecutor); | 241 | }, wsCallBackExecutor); |
231 | } | 242 | } |
232 | 243 | ||
244 | + @Override | ||
245 | + public void handleCmd(TelemetryWebSocketSessionRef session, AlarmDataCmd cmd) { | ||
246 | + TbAlarmDataSubCtx ctx = getSubCtx(session.getSessionId(), cmd.getCmdId()); | ||
247 | + if (ctx == null) { | ||
248 | + log.debug("[{}][{}] Creating new alarm subscription using: {}", session.getSessionId(), cmd.getCmdId(), cmd); | ||
249 | + ctx = createSubCtx(session, cmd); | ||
250 | + } | ||
251 | + AlarmDataQuery adq = cmd.getQuery(); | ||
252 | + EntityDataSortOrder sortOrder = adq.getPageLink().getSortOrder(); | ||
253 | + EntityDataSortOrder entitiesSortOrder; | ||
254 | + if (sortOrder == null || sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { | ||
255 | + entitiesSortOrder = new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, ModelConstants.CREATED_TIME_PROPERTY)); | ||
256 | + } else { | ||
257 | + entitiesSortOrder = sortOrder; | ||
258 | + } | ||
259 | + EntityDataPageLink edpl = new EntityDataPageLink(0, maxEntitiesPerAlarmSubscription, null, entitiesSortOrder); | ||
260 | + EntityDataQuery edq = new EntityDataQuery(adq.getEntityFilter(), edpl, adq.getEntityFields(), adq.getLatestValues(), adq.getKeyFilters()); | ||
261 | + PageData<EntityData> entitiesData = entityService.findEntityDataByQuery(ctx.getTenantId(), ctx.getCustomerId(), edq); | ||
262 | + List<EntityData> entities = entitiesData.getData(); | ||
263 | + ctx.setEntitiesData(entitiesData); | ||
264 | + if (entities.isEmpty()) { | ||
265 | + AlarmDataUpdate update = new AlarmDataUpdate(cmd.getCmdId(), new PageData<>(Collections.emptyList(), 1, 0, false), null); | ||
266 | + wsService.sendWsMsg(ctx.getSessionId(), update); | ||
267 | + } else { | ||
268 | + PageData<AlarmData> alarms = alarmService.findAlarmDataByQueryForEntities(ctx.getTenantId(), ctx.getCustomerId(), | ||
269 | + ctx.getQuery().getPageLink(), ctx.getOrderedEntityIds()); | ||
270 | + ctx.setAlarmsData(alarms); | ||
271 | + AlarmDataUpdate update = new AlarmDataUpdate(cmd.getCmdId(), alarms, null); | ||
272 | + wsService.sendWsMsg(ctx.getSessionId(), update); | ||
273 | + //TODO: Create WS subscription for alarms for this entities. If this is first page(?!) and new alarm matches the filter - invalidate alarms. | ||
274 | + } | ||
275 | + } | ||
276 | + | ||
233 | private void refreshDynamicQuery(TenantId tenantId, CustomerId customerId, TbEntityDataSubCtx finalCtx) { | 277 | private void refreshDynamicQuery(TenantId tenantId, CustomerId customerId, TbEntityDataSubCtx finalCtx) { |
234 | try { | 278 | try { |
235 | long start = System.currentTimeMillis(); | 279 | long start = System.currentTimeMillis(); |
@@ -244,7 +288,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -244,7 +288,7 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
244 | } | 288 | } |
245 | } | 289 | } |
246 | 290 | ||
247 | - @Scheduled(fixedDelayString = "${server.ws.dynamic_page_link_stats:10000}") | 291 | + @Scheduled(fixedDelayString = "${server.ws.dynamic_page_link.stats:10000}") |
248 | public void printStats() { | 292 | public void printStats() { |
249 | int regularQueryInvocationCntValue = regularQueryInvocationCnt.getAndSet(0); | 293 | int regularQueryInvocationCntValue = regularQueryInvocationCnt.getAndSet(0); |
250 | long regularQueryInvocationTimeValue = regularQueryTimeSpent.getAndSet(0); | 294 | long regularQueryInvocationTimeValue = regularQueryTimeSpent.getAndSet(0); |
@@ -263,17 +307,25 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -263,17 +307,25 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
263 | } | 307 | } |
264 | 308 | ||
265 | private TbEntityDataSubCtx createSubCtx(TelemetryWebSocketSessionRef sessionRef, EntityDataCmd cmd) { | 309 | private TbEntityDataSubCtx createSubCtx(TelemetryWebSocketSessionRef sessionRef, EntityDataCmd cmd) { |
266 | - Map<Integer, TbEntityDataSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); | 310 | + Map<Integer, TbAbstractDataSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); |
267 | TbEntityDataSubCtx ctx = new TbEntityDataSubCtx(serviceId, wsService, sessionRef, cmd.getCmdId()); | 311 | TbEntityDataSubCtx ctx = new TbEntityDataSubCtx(serviceId, wsService, sessionRef, cmd.getCmdId()); |
268 | ctx.setQuery(cmd.getQuery()); | 312 | ctx.setQuery(cmd.getQuery()); |
269 | sessionSubs.put(cmd.getCmdId(), ctx); | 313 | sessionSubs.put(cmd.getCmdId(), ctx); |
270 | return ctx; | 314 | return ctx; |
271 | } | 315 | } |
272 | 316 | ||
273 | - private TbEntityDataSubCtx getSubCtx(String sessionId, int cmdId) { | ||
274 | - Map<Integer, TbEntityDataSubCtx> sessionSubs = subscriptionsBySessionId.get(sessionId); | 317 | + private TbAlarmDataSubCtx createSubCtx(TelemetryWebSocketSessionRef sessionRef, AlarmDataCmd cmd) { |
318 | + Map<Integer, TbAbstractDataSubCtx> sessionSubs = subscriptionsBySessionId.computeIfAbsent(sessionRef.getSessionId(), k -> new HashMap<>()); | ||
319 | + TbAlarmDataSubCtx ctx = new TbAlarmDataSubCtx(serviceId, wsService, sessionRef, cmd.getCmdId()); | ||
320 | + ctx.setQuery(cmd.getQuery()); | ||
321 | + sessionSubs.put(cmd.getCmdId(), ctx); | ||
322 | + return ctx; | ||
323 | + } | ||
324 | + | ||
325 | + private <T extends TbAbstractDataSubCtx> T getSubCtx(String sessionId, int cmdId) { | ||
326 | + Map<Integer, TbAbstractDataSubCtx> sessionSubs = subscriptionsBySessionId.get(sessionId); | ||
275 | if (sessionSubs != null) { | 327 | if (sessionSubs != null) { |
276 | - return sessionSubs.get(cmdId); | 328 | + return (T) sessionSubs.get(cmdId); |
277 | } else { | 329 | } else { |
278 | return null; | 330 | return null; |
279 | } | 331 | } |
@@ -420,14 +472,6 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -420,14 +472,6 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
420 | return data.stream().collect(Collectors.toMap(TsKvEntry::getKey, value -> new TsValue(value.getTs(), value.getValueAsString()))); | 472 | return data.stream().collect(Collectors.toMap(TsKvEntry::getKey, value -> new TsValue(value.getTs(), value.getValueAsString()))); |
421 | } | 473 | } |
422 | 474 | ||
423 | - private Map<String, List<TsValue>> toTsValues(List<TsKvEntry> data) { | ||
424 | - Map<String, List<TsValue>> results = new HashMap<>(); | ||
425 | - for (TsKvEntry tsKvEntry : data) { | ||
426 | - results.computeIfAbsent(tsKvEntry.getKey(), k -> new ArrayList<>()).add(new TsValue(tsKvEntry.getTs(), tsKvEntry.getValueAsString())); | ||
427 | - } | ||
428 | - return results; | ||
429 | - } | ||
430 | - | ||
431 | @Override | 475 | @Override |
432 | public void cancelSubscription(String sessionId, EntityDataUnsubscribeCmd cmd) { | 476 | public void cancelSubscription(String sessionId, EntityDataUnsubscribeCmd cmd) { |
433 | cleanupAndCancel(getSubCtx(sessionId, cmd.getCmdId())); | 477 | cleanupAndCancel(getSubCtx(sessionId, cmd.getCmdId())); |
@@ -442,9 +486,9 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | @@ -442,9 +486,9 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc | ||
442 | 486 | ||
443 | @Override | 487 | @Override |
444 | public void cancelAllSessionSubscriptions(String sessionId) { | 488 | public void cancelAllSessionSubscriptions(String sessionId) { |
445 | - Map<Integer, TbEntityDataSubCtx> sessionSubs = subscriptionsBySessionId.remove(sessionId); | 489 | + Map<Integer, TbAbstractDataSubCtx> sessionSubs = subscriptionsBySessionId.remove(sessionId); |
446 | if (sessionSubs != null) { | 490 | if (sessionSubs != null) { |
447 | - sessionSubs.values().forEach(this::cleanupAndCancel); | 491 | + sessionSubs.values().stream().filter(sub -> sub instanceof TbEntityDataSubCtx).map(sub -> (TbEntityDataSubCtx) sub).forEach(this::cleanupAndCancel); |
448 | } | 492 | } |
449 | } | 493 | } |
450 | 494 |
application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.service.subscription; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import lombok.Getter; | ||
20 | +import lombok.Setter; | ||
21 | +import lombok.extern.slf4j.Slf4j; | ||
22 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
23 | +import org.thingsboard.server.common.data.id.TenantId; | ||
24 | +import org.thingsboard.server.common.data.query.AbstractDataQuery; | ||
25 | +import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; | ||
26 | +import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; | ||
27 | + | ||
28 | +@Slf4j | ||
29 | +@Data | ||
30 | +public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery> { | ||
31 | + | ||
32 | + protected final String serviceId; | ||
33 | + protected final TelemetryWebSocketService wsService; | ||
34 | + protected final TelemetryWebSocketSessionRef sessionRef; | ||
35 | + protected final int cmdId; | ||
36 | + @Getter | ||
37 | + @Setter | ||
38 | + protected T query; | ||
39 | + | ||
40 | + public TbAbstractDataSubCtx(String serviceId, TelemetryWebSocketService wsService, TelemetryWebSocketSessionRef sessionRef, int cmdId) { | ||
41 | + this.serviceId = serviceId; | ||
42 | + this.wsService = wsService; | ||
43 | + this.sessionRef = sessionRef; | ||
44 | + this.cmdId = cmdId; | ||
45 | + } | ||
46 | + | ||
47 | + public String getSessionId() { | ||
48 | + return sessionRef.getSessionId(); | ||
49 | + } | ||
50 | + | ||
51 | + public TenantId getTenantId() { | ||
52 | + return sessionRef.getSecurityCtx().getTenantId(); | ||
53 | + } | ||
54 | + | ||
55 | + public CustomerId getCustomerId() { | ||
56 | + return sessionRef.getSecurityCtx().getCustomerId(); | ||
57 | + } | ||
58 | + | ||
59 | +} |
application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.service.subscription; | ||
17 | + | ||
18 | +import lombok.Getter; | ||
19 | +import lombok.Setter; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.thingsboard.server.common.data.id.EntityId; | ||
22 | +import org.thingsboard.server.common.data.page.PageData; | ||
23 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
24 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
25 | +import org.thingsboard.server.common.data.query.EntityData; | ||
26 | +import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; | ||
27 | +import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; | ||
28 | + | ||
29 | +import java.util.Collection; | ||
30 | +import java.util.LinkedHashMap; | ||
31 | +import java.util.List; | ||
32 | + | ||
33 | +@Slf4j | ||
34 | +public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx<AlarmDataQuery> { | ||
35 | + | ||
36 | + @Getter | ||
37 | + @Setter | ||
38 | + private final LinkedHashMap<EntityId, EntityData> entitiesMap; | ||
39 | + @Getter | ||
40 | + @Setter | ||
41 | + private boolean tooManyEntities; | ||
42 | + | ||
43 | + public TbAlarmDataSubCtx(String serviceId, TelemetryWebSocketService wsService, TelemetryWebSocketSessionRef sessionRef, int cmdId) { | ||
44 | + super(serviceId, wsService, sessionRef, cmdId); | ||
45 | + this.entitiesMap = new LinkedHashMap<>(); | ||
46 | + } | ||
47 | + | ||
48 | + public void setEntitiesData(PageData<EntityData> entitiesData) { | ||
49 | + entitiesMap.clear(); | ||
50 | + tooManyEntities = entitiesData.hasNext(); | ||
51 | + for (EntityData entityData : entitiesData.getData()) { | ||
52 | + entitiesMap.put(entityData.getEntityId(), entityData); | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + public Collection<EntityId> getOrderedEntityIds() { | ||
57 | + return entitiesMap.keySet(); | ||
58 | + } | ||
59 | + | ||
60 | + public void setAlarmsData(PageData<AlarmData> alarms) { | ||
61 | +// TODO: implement | ||
62 | + } | ||
63 | +} |
@@ -17,6 +17,9 @@ package org.thingsboard.server.service.subscription; | @@ -17,6 +17,9 @@ package org.thingsboard.server.service.subscription; | ||
17 | 17 | ||
18 | import lombok.AllArgsConstructor; | 18 | import lombok.AllArgsConstructor; |
19 | import lombok.Data; | 19 | import lombok.Data; |
20 | +import lombok.Getter; | ||
21 | +import lombok.RequiredArgsConstructor; | ||
22 | +import lombok.Setter; | ||
20 | import lombok.extern.slf4j.Slf4j; | 23 | import lombok.extern.slf4j.Slf4j; |
21 | import org.thingsboard.server.common.data.id.CustomerId; | 24 | import org.thingsboard.server.common.data.id.CustomerId; |
22 | import org.thingsboard.server.common.data.id.EntityId; | 25 | import org.thingsboard.server.common.data.id.EntityId; |
@@ -51,17 +54,13 @@ import java.util.function.Function; | @@ -51,17 +54,13 @@ import java.util.function.Function; | ||
51 | import java.util.stream.Collectors; | 54 | import java.util.stream.Collectors; |
52 | 55 | ||
53 | @Slf4j | 56 | @Slf4j |
54 | -@Data | ||
55 | -public class TbEntityDataSubCtx { | 57 | +public class TbEntityDataSubCtx extends TbAbstractDataSubCtx<EntityDataQuery> { |
56 | 58 | ||
57 | - public static final int MAX_SUBS_PER_CMD = 1024 * 8; | ||
58 | - private final String serviceId; | ||
59 | - private final TelemetryWebSocketService wsService; | ||
60 | - private final TelemetryWebSocketSessionRef sessionRef; | ||
61 | - private final int cmdId; | ||
62 | - private EntityDataQuery query; | 59 | + @Getter @Setter |
63 | private TimeSeriesCmd tsCmd; | 60 | private TimeSeriesCmd tsCmd; |
61 | + @Getter | ||
64 | private PageData<EntityData> data; | 62 | private PageData<EntityData> data; |
63 | + @Getter @Setter | ||
65 | private boolean initialDataSent; | 64 | private boolean initialDataSent; |
66 | private Map<Integer, EntityId> subToEntityIdMap; | 65 | private Map<Integer, EntityId> subToEntityIdMap; |
67 | private volatile ScheduledFuture<?> refreshTask; | 66 | private volatile ScheduledFuture<?> refreshTask; |
@@ -69,22 +68,7 @@ public class TbEntityDataSubCtx { | @@ -69,22 +68,7 @@ public class TbEntityDataSubCtx { | ||
69 | private LatestValueCmd latestValueCmd; | 68 | private LatestValueCmd latestValueCmd; |
70 | 69 | ||
71 | public TbEntityDataSubCtx(String serviceId, TelemetryWebSocketService wsService, TelemetryWebSocketSessionRef sessionRef, int cmdId) { | 70 | public TbEntityDataSubCtx(String serviceId, TelemetryWebSocketService wsService, TelemetryWebSocketSessionRef sessionRef, int cmdId) { |
72 | - this.serviceId = serviceId; | ||
73 | - this.wsService = wsService; | ||
74 | - this.sessionRef = sessionRef; | ||
75 | - this.cmdId = cmdId; | ||
76 | - } | ||
77 | - | ||
78 | - public String getSessionId() { | ||
79 | - return sessionRef.getSessionId(); | ||
80 | - } | ||
81 | - | ||
82 | - public TenantId getTenantId() { | ||
83 | - return sessionRef.getSecurityCtx().getTenantId(); | ||
84 | - } | ||
85 | - | ||
86 | - public CustomerId getCustomerId() { | ||
87 | - return sessionRef.getSecurityCtx().getCustomerId(); | 71 | + super(serviceId, wsService, sessionRef, cmdId); |
88 | } | 72 | } |
89 | 73 | ||
90 | public void setData(PageData<EntityData> data) { | 74 | public void setData(PageData<EntityData> data) { |
@@ -16,6 +16,7 @@ | @@ -16,6 +16,7 @@ | ||
16 | package org.thingsboard.server.service.subscription; | 16 | package org.thingsboard.server.service.subscription; |
17 | 17 | ||
18 | import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; | 18 | import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; |
19 | +import org.thingsboard.server.service.telemetry.cmd.v2.AlarmDataCmd; | ||
19 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; | 20 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; |
20 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; | 21 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; |
21 | 22 | ||
@@ -23,6 +24,8 @@ public interface TbEntityDataSubscriptionService { | @@ -23,6 +24,8 @@ public interface TbEntityDataSubscriptionService { | ||
23 | 24 | ||
24 | void handleCmd(TelemetryWebSocketSessionRef sessionId, EntityDataCmd cmd); | 25 | void handleCmd(TelemetryWebSocketSessionRef sessionId, EntityDataCmd cmd); |
25 | 26 | ||
27 | + void handleCmd(TelemetryWebSocketSessionRef sessionId, AlarmDataCmd cmd); | ||
28 | + | ||
26 | void cancelSubscription(String sessionId, EntityDataUnsubscribeCmd subscriptionId); | 29 | void cancelSubscription(String sessionId, EntityDataUnsubscribeCmd subscriptionId); |
27 | 30 | ||
28 | void cancelAllSessionSubscriptions(String sessionId); | 31 | void cancelAllSessionSubscriptions(String sessionId); |
@@ -63,6 +63,9 @@ import org.thingsboard.server.service.telemetry.cmd.v1.SubscriptionCmd; | @@ -63,6 +63,9 @@ import org.thingsboard.server.service.telemetry.cmd.v1.SubscriptionCmd; | ||
63 | import org.thingsboard.server.service.telemetry.cmd.v1.TelemetryPluginCmd; | 63 | import org.thingsboard.server.service.telemetry.cmd.v1.TelemetryPluginCmd; |
64 | import org.thingsboard.server.service.telemetry.cmd.TelemetryPluginCmdsWrapper; | 64 | import org.thingsboard.server.service.telemetry.cmd.TelemetryPluginCmdsWrapper; |
65 | import org.thingsboard.server.service.telemetry.cmd.v1.TimeseriesSubscriptionCmd; | 65 | import org.thingsboard.server.service.telemetry.cmd.v1.TimeseriesSubscriptionCmd; |
66 | +import org.thingsboard.server.service.telemetry.cmd.v2.AlarmDataCmd; | ||
67 | +import org.thingsboard.server.service.telemetry.cmd.v2.DataCmd; | ||
68 | +import org.thingsboard.server.service.telemetry.cmd.v2.DataUpdate; | ||
66 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; | 69 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; |
67 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; | 70 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; |
68 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; | 71 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; |
@@ -210,6 +213,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | @@ -210,6 +213,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | ||
210 | if (cmdsWrapper.getEntityDataCmds() != null) { | 213 | if (cmdsWrapper.getEntityDataCmds() != null) { |
211 | cmdsWrapper.getEntityDataCmds().forEach(cmd -> handleWsEntityDataCmd(sessionRef, cmd)); | 214 | cmdsWrapper.getEntityDataCmds().forEach(cmd -> handleWsEntityDataCmd(sessionRef, cmd)); |
212 | } | 215 | } |
216 | + if (cmdsWrapper.getAlarmDataCmds() != null) { | ||
217 | + cmdsWrapper.getAlarmDataCmds().forEach(cmd -> handleWsAlarmDataCmd(sessionRef, cmd)); | ||
218 | + } | ||
213 | if (cmdsWrapper.getEntityDataUnsubscribeCmds() != null) { | 219 | if (cmdsWrapper.getEntityDataUnsubscribeCmds() != null) { |
214 | cmdsWrapper.getEntityDataUnsubscribeCmds().forEach(cmd -> handleWsEntityDataUnsubscribeCmd(sessionRef, cmd)); | 220 | cmdsWrapper.getEntityDataUnsubscribeCmds().forEach(cmd -> handleWsEntityDataUnsubscribeCmd(sessionRef, cmd)); |
215 | } | 221 | } |
@@ -231,6 +237,16 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | @@ -231,6 +237,16 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | ||
231 | } | 237 | } |
232 | } | 238 | } |
233 | 239 | ||
240 | + private void handleWsAlarmDataCmd(TelemetryWebSocketSessionRef sessionRef, AlarmDataCmd cmd) { | ||
241 | + String sessionId = sessionRef.getSessionId(); | ||
242 | + log.debug("[{}] Processing: {}", sessionId, cmd); | ||
243 | + | ||
244 | + if (validateSessionMetadata(sessionRef, cmd.getCmdId(), sessionId) | ||
245 | + && validateSubscriptionCmd(sessionRef, cmd)) { | ||
246 | + entityDataSubService.handleCmd(sessionRef, cmd); | ||
247 | + } | ||
248 | + } | ||
249 | + | ||
234 | private void handleWsEntityDataUnsubscribeCmd(TelemetryWebSocketSessionRef sessionRef, EntityDataUnsubscribeCmd cmd) { | 250 | private void handleWsEntityDataUnsubscribeCmd(TelemetryWebSocketSessionRef sessionRef, EntityDataUnsubscribeCmd cmd) { |
235 | String sessionId = sessionRef.getSessionId(); | 251 | String sessionId = sessionRef.getSessionId(); |
236 | log.debug("[{}] Processing: {}", sessionId, cmd); | 252 | log.debug("[{}] Processing: {}", sessionId, cmd); |
@@ -246,7 +262,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | @@ -246,7 +262,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | ||
246 | } | 262 | } |
247 | 263 | ||
248 | @Override | 264 | @Override |
249 | - public void sendWsMsg(String sessionId, EntityDataUpdate update) { | 265 | + public void sendWsMsg(String sessionId, DataUpdate update) { |
250 | sendWsMsg(sessionId, update.getCmdId(), update); | 266 | sendWsMsg(sessionId, update.getCmdId(), update); |
251 | } | 267 | } |
252 | 268 | ||
@@ -661,6 +677,21 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | @@ -661,6 +677,21 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | ||
661 | return true; | 677 | return true; |
662 | } | 678 | } |
663 | 679 | ||
680 | + private boolean validateSubscriptionCmd(TelemetryWebSocketSessionRef sessionRef, AlarmDataCmd cmd) { | ||
681 | + if (cmd.getCmdId() < 0) { | ||
682 | + SubscriptionUpdate update = new SubscriptionUpdate(cmd.getCmdId(), SubscriptionErrorCode.BAD_REQUEST, | ||
683 | + "Cmd id is negative value!"); | ||
684 | + sendWsMsg(sessionRef, update); | ||
685 | + return false; | ||
686 | + } else if (cmd.getQuery() == null) { | ||
687 | + SubscriptionUpdate update = new SubscriptionUpdate(cmd.getCmdId(), SubscriptionErrorCode.BAD_REQUEST, | ||
688 | + "Query is empty!"); | ||
689 | + sendWsMsg(sessionRef, update); | ||
690 | + return false; | ||
691 | + } | ||
692 | + return true; | ||
693 | + } | ||
694 | + | ||
664 | private boolean validateSubscriptionCmd(TelemetryWebSocketSessionRef sessionRef, SubscriptionCmd cmd) { | 695 | private boolean validateSubscriptionCmd(TelemetryWebSocketSessionRef sessionRef, SubscriptionCmd cmd) { |
665 | if (cmd.getEntityId() == null || cmd.getEntityId().isEmpty()) { | 696 | if (cmd.getEntityId() == null || cmd.getEntityId().isEmpty()) { |
666 | SubscriptionUpdate update = new SubscriptionUpdate(cmd.getCmdId(), SubscriptionErrorCode.BAD_REQUEST, | 697 | SubscriptionUpdate update = new SubscriptionUpdate(cmd.getCmdId(), SubscriptionErrorCode.BAD_REQUEST, |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.service.telemetry; | 16 | package org.thingsboard.server.service.telemetry; |
17 | 17 | ||
18 | +import org.thingsboard.server.service.telemetry.cmd.v2.DataUpdate; | ||
18 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; | 19 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; |
19 | import org.thingsboard.server.service.telemetry.sub.SubscriptionUpdate; | 20 | import org.thingsboard.server.service.telemetry.sub.SubscriptionUpdate; |
20 | 21 | ||
@@ -29,6 +30,6 @@ public interface TelemetryWebSocketService { | @@ -29,6 +30,6 @@ public interface TelemetryWebSocketService { | ||
29 | 30 | ||
30 | void sendWsMsg(String sessionId, SubscriptionUpdate update); | 31 | void sendWsMsg(String sessionId, SubscriptionUpdate update); |
31 | 32 | ||
32 | - void sendWsMsg(String sessionId, EntityDataUpdate update); | 33 | + void sendWsMsg(String sessionId, DataUpdate update); |
33 | 34 | ||
34 | } | 35 | } |
@@ -19,6 +19,8 @@ import lombok.Data; | @@ -19,6 +19,8 @@ import lombok.Data; | ||
19 | import org.thingsboard.server.service.telemetry.cmd.v1.AttributesSubscriptionCmd; | 19 | import org.thingsboard.server.service.telemetry.cmd.v1.AttributesSubscriptionCmd; |
20 | import org.thingsboard.server.service.telemetry.cmd.v1.GetHistoryCmd; | 20 | import org.thingsboard.server.service.telemetry.cmd.v1.GetHistoryCmd; |
21 | import org.thingsboard.server.service.telemetry.cmd.v1.TimeseriesSubscriptionCmd; | 21 | import org.thingsboard.server.service.telemetry.cmd.v1.TimeseriesSubscriptionCmd; |
22 | +import org.thingsboard.server.service.telemetry.cmd.v2.AlarmDataCmd; | ||
23 | +import org.thingsboard.server.service.telemetry.cmd.v2.AlarmDataUnsubscribeCmd; | ||
22 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; | 24 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd; |
23 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; | 25 | import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUnsubscribeCmd; |
24 | 26 | ||
@@ -40,4 +42,8 @@ public class TelemetryPluginCmdsWrapper { | @@ -40,4 +42,8 @@ public class TelemetryPluginCmdsWrapper { | ||
40 | 42 | ||
41 | private List<EntityDataUnsubscribeCmd> entityDataUnsubscribeCmds; | 43 | private List<EntityDataUnsubscribeCmd> entityDataUnsubscribeCmds; |
42 | 44 | ||
45 | + private List<AlarmDataCmd> alarmDataCmds; | ||
46 | + | ||
47 | + private List<AlarmDataUnsubscribeCmd> alarmDataUnsubscribeCmds; | ||
48 | + | ||
43 | } | 49 | } |
application/src/main/java/org/thingsboard/server/service/telemetry/cmd/v2/AlarmDataCmd.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.service.telemetry.cmd.v2; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | ||
19 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
20 | +import lombok.Getter; | ||
21 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
22 | + | ||
23 | +public class AlarmDataCmd extends DataCmd { | ||
24 | + | ||
25 | + @Getter | ||
26 | + private final AlarmDataQuery query; | ||
27 | + | ||
28 | + @JsonCreator | ||
29 | + public AlarmDataCmd(@JsonProperty("cmdId") int cmdId, @JsonProperty("query") AlarmDataQuery query) { | ||
30 | + super(cmdId); | ||
31 | + this.query = query; | ||
32 | + } | ||
33 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.service.telemetry.cmd.v2; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +@Data | ||
21 | +public class AlarmDataUnsubscribeCmd { | ||
22 | + | ||
23 | + private final int cmdId; | ||
24 | + | ||
25 | +} |
application/src/main/java/org/thingsboard/server/service/telemetry/cmd/v2/AlarmDataUpdate.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.service.telemetry.cmd.v2; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | ||
19 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
20 | +import lombok.NoArgsConstructor; | ||
21 | +import org.thingsboard.server.common.data.page.PageData; | ||
22 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
23 | +import org.thingsboard.server.common.data.query.EntityData; | ||
24 | +import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode; | ||
25 | + | ||
26 | +import java.util.List; | ||
27 | + | ||
28 | +public class AlarmDataUpdate extends DataUpdate<AlarmData> { | ||
29 | + | ||
30 | + public AlarmDataUpdate(int cmdId, PageData<AlarmData> data, List<AlarmData> update) { | ||
31 | + super(cmdId, data, update, SubscriptionErrorCode.NO_ERROR.getCode(), null); | ||
32 | + } | ||
33 | + | ||
34 | + public AlarmDataUpdate(int cmdId, int errorCode, String errorMsg) { | ||
35 | + super(cmdId, null, null, errorCode, errorMsg); | ||
36 | + } | ||
37 | + | ||
38 | + @JsonCreator | ||
39 | + public AlarmDataUpdate(@JsonProperty("cmdId") int cmdId, | ||
40 | + @JsonProperty("data") PageData<AlarmData> data, | ||
41 | + @JsonProperty("update") List<AlarmData> update, | ||
42 | + @JsonProperty("errorCode") int errorCode, | ||
43 | + @JsonProperty("errorMsg") String errorMsg) { | ||
44 | + super(cmdId, data, update, errorCode, errorMsg); | ||
45 | + } | ||
46 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.service.telemetry.cmd.v2; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import lombok.Getter; | ||
20 | +import lombok.NoArgsConstructor; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class DataCmd { | ||
24 | + | ||
25 | + @Getter | ||
26 | + private final int cmdId; | ||
27 | + | ||
28 | + public DataCmd(int cmdId) { | ||
29 | + this.cmdId = cmdId; | ||
30 | + } | ||
31 | + | ||
32 | +} |
application/src/main/java/org/thingsboard/server/service/telemetry/cmd/v2/DataUpdate.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.service.telemetry.cmd.v2; | ||
17 | + | ||
18 | +import lombok.AllArgsConstructor; | ||
19 | +import lombok.Data; | ||
20 | +import org.thingsboard.server.common.data.page.PageData; | ||
21 | +import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode; | ||
22 | + | ||
23 | +import java.util.List; | ||
24 | + | ||
25 | +@Data | ||
26 | +@AllArgsConstructor | ||
27 | +public abstract class DataUpdate<T> { | ||
28 | + | ||
29 | + private final int cmdId; | ||
30 | + private final PageData<T> data; | ||
31 | + private final List<T> update; | ||
32 | + private final int errorCode; | ||
33 | + private final String errorMsg; | ||
34 | + | ||
35 | + public DataUpdate(int cmdId, PageData<T> data, List<T> update) { | ||
36 | + this(cmdId, data, update, SubscriptionErrorCode.NO_ERROR.getCode(), null); | ||
37 | + } | ||
38 | + | ||
39 | + public DataUpdate(int cmdId, int errorCode, String errorMsg) { | ||
40 | + this(cmdId, null, null, errorCode, errorMsg); | ||
41 | + } | ||
42 | + | ||
43 | +} |
@@ -15,16 +15,32 @@ | @@ -15,16 +15,32 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.service.telemetry.cmd.v2; | 16 | package org.thingsboard.server.service.telemetry.cmd.v2; |
17 | 17 | ||
18 | -import lombok.Data; | 18 | +import com.fasterxml.jackson.annotation.JsonCreator; |
19 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
20 | +import lombok.Getter; | ||
19 | import org.thingsboard.server.common.data.query.EntityDataQuery; | 21 | import org.thingsboard.server.common.data.query.EntityDataQuery; |
20 | 22 | ||
21 | -@Data | ||
22 | -public class EntityDataCmd { | 23 | +public class EntityDataCmd extends DataCmd { |
23 | 24 | ||
24 | - private final int cmdId; | 25 | + @Getter |
25 | private final EntityDataQuery query; | 26 | private final EntityDataQuery query; |
27 | + @Getter | ||
26 | private final EntityHistoryCmd historyCmd; | 28 | private final EntityHistoryCmd historyCmd; |
29 | + @Getter | ||
27 | private final LatestValueCmd latestCmd; | 30 | private final LatestValueCmd latestCmd; |
31 | + @Getter | ||
28 | private final TimeSeriesCmd tsCmd; | 32 | private final TimeSeriesCmd tsCmd; |
29 | 33 | ||
34 | + @JsonCreator | ||
35 | + public EntityDataCmd(@JsonProperty("cmdId") int cmdId, | ||
36 | + @JsonProperty("query") EntityDataQuery query, | ||
37 | + @JsonProperty("historyCmd") EntityHistoryCmd historyCmd, | ||
38 | + @JsonProperty("latestCmd") LatestValueCmd latestCmd, | ||
39 | + @JsonProperty("tsCmd") TimeSeriesCmd tsCmd) { | ||
40 | + super(cmdId); | ||
41 | + this.query = query; | ||
42 | + this.historyCmd = historyCmd; | ||
43 | + this.latestCmd = latestCmd; | ||
44 | + this.tsCmd = tsCmd; | ||
45 | + } | ||
30 | } | 46 | } |
@@ -15,30 +15,31 @@ | @@ -15,30 +15,31 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.service.telemetry.cmd.v2; | 16 | package org.thingsboard.server.service.telemetry.cmd.v2; |
17 | 17 | ||
18 | -import lombok.AllArgsConstructor; | ||
19 | -import lombok.Data; | 18 | +import com.fasterxml.jackson.annotation.JsonCreator; |
19 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
20 | import org.thingsboard.server.common.data.page.PageData; | 20 | import org.thingsboard.server.common.data.page.PageData; |
21 | import org.thingsboard.server.common.data.query.EntityData; | 21 | import org.thingsboard.server.common.data.query.EntityData; |
22 | import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode; | 22 | import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode; |
23 | 23 | ||
24 | import java.util.List; | 24 | import java.util.List; |
25 | 25 | ||
26 | -@Data | ||
27 | -@AllArgsConstructor | ||
28 | -public class EntityDataUpdate { | ||
29 | - | ||
30 | - private final int cmdId; | ||
31 | - private final PageData<EntityData> data; | ||
32 | - private final List<EntityData> update; | ||
33 | - private final int errorCode; | ||
34 | - private final String errorMsg; | 26 | +public class EntityDataUpdate extends DataUpdate<EntityData> { |
35 | 27 | ||
36 | public EntityDataUpdate(int cmdId, PageData<EntityData> data, List<EntityData> update) { | 28 | public EntityDataUpdate(int cmdId, PageData<EntityData> data, List<EntityData> update) { |
37 | - this(cmdId, data, update, SubscriptionErrorCode.NO_ERROR.getCode(), null); | 29 | + super(cmdId, data, update, SubscriptionErrorCode.NO_ERROR.getCode(), null); |
38 | } | 30 | } |
39 | 31 | ||
40 | public EntityDataUpdate(int cmdId, int errorCode, String errorMsg) { | 32 | public EntityDataUpdate(int cmdId, int errorCode, String errorMsg) { |
41 | - this(cmdId, null, null, errorCode, errorMsg); | 33 | + super(cmdId, null, null, errorCode, errorMsg); |
34 | + } | ||
35 | + | ||
36 | + @JsonCreator | ||
37 | + public EntityDataUpdate(@JsonProperty("cmdId") int cmdId, | ||
38 | + @JsonProperty("data") PageData<EntityData> data, | ||
39 | + @JsonProperty("update") List<EntityData> update, | ||
40 | + @JsonProperty("errorCode") int errorCode, | ||
41 | + @JsonProperty("errorMsg") String errorMsg) { | ||
42 | + super(cmdId, data, update, errorCode, errorMsg); | ||
42 | } | 43 | } |
43 | 44 | ||
44 | } | 45 | } |
@@ -46,8 +46,11 @@ server: | @@ -46,8 +46,11 @@ server: | ||
46 | max_subscriptions_per_regular_user: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_SUBSCRIPTIONS_PER_REGULAR_USER:0}" | 46 | max_subscriptions_per_regular_user: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_SUBSCRIPTIONS_PER_REGULAR_USER:0}" |
47 | max_subscriptions_per_public_user: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_SUBSCRIPTIONS_PER_PUBLIC_USER:0}" | 47 | max_subscriptions_per_public_user: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_SUBSCRIPTIONS_PER_PUBLIC_USER:0}" |
48 | max_updates_per_session: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_UPDATES_PER_SESSION:300:1,3000:60}" | 48 | max_updates_per_session: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_UPDATES_PER_SESSION:300:1,3000:60}" |
49 | - dynamic_page_link_refresh_interval: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_INTERVAL_SEC:6}" | ||
50 | - dynamic_page_link_refresh_pool_size: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_POOL_SIZE:1}" | 49 | + dynamic_page_link: |
50 | + refresh_interval: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_INTERVAL_SEC:60}" | ||
51 | + refresh_pool_size: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_POOL_SIZE:1}" | ||
52 | + max_per_user: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_MAX_PER_USER:10}" | ||
53 | + max_entities_per_alarm_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_ALARM_SUBSCRIPTION:1000}" | ||
51 | rest: | 54 | rest: |
52 | limits: | 55 | limits: |
53 | tenant: | 56 | tenant: |
@@ -26,9 +26,9 @@ import java.util.Arrays; | @@ -26,9 +26,9 @@ import java.util.Arrays; | ||
26 | 26 | ||
27 | @RunWith(ClasspathSuite.class) | 27 | @RunWith(ClasspathSuite.class) |
28 | @ClasspathSuite.ClassnameFilters({ | 28 | @ClasspathSuite.ClassnameFilters({ |
29 | -// "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", | 29 | + "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", |
30 | // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", | 30 | // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", |
31 | - "org.thingsboard.server.controller.sql.*Test", | 31 | +// "org.thingsboard.server.controller.sql.*Test", |
32 | }) | 32 | }) |
33 | public class ControllerSqlTestSuite { | 33 | public class ControllerSqlTestSuite { |
34 | 34 |
@@ -24,9 +24,15 @@ import org.thingsboard.server.common.data.alarm.AlarmQuery; | @@ -24,9 +24,15 @@ import org.thingsboard.server.common.data.alarm.AlarmQuery; | ||
24 | import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | 24 | import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; |
25 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 25 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
26 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 26 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
27 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
27 | import org.thingsboard.server.common.data.id.EntityId; | 28 | import org.thingsboard.server.common.data.id.EntityId; |
28 | import org.thingsboard.server.common.data.id.TenantId; | 29 | import org.thingsboard.server.common.data.id.TenantId; |
29 | import org.thingsboard.server.common.data.page.PageData; | 30 | import org.thingsboard.server.common.data.page.PageData; |
31 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
32 | +import org.thingsboard.server.common.data.query.AlarmDataPageLink; | ||
33 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
34 | + | ||
35 | +import java.util.Collection; | ||
30 | 36 | ||
31 | /** | 37 | /** |
32 | * Created by ashvayka on 11.05.17. | 38 | * Created by ashvayka on 11.05.17. |
@@ -52,4 +58,6 @@ public interface AlarmService { | @@ -52,4 +58,6 @@ public interface AlarmService { | ||
52 | 58 | ||
53 | ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type); | 59 | ListenableFuture<Alarm> findLatestByOriginatorAndType(TenantId tenantId, EntityId originator, String type); |
54 | 60 | ||
61 | + PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, | ||
62 | + AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds); | ||
55 | } | 63 | } |
common/data/src/main/java/org/thingsboard/server/common/data/query/AbstractDataQuery.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.query; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import lombok.Getter; | ||
20 | +import lombok.ToString; | ||
21 | + | ||
22 | +import java.util.List; | ||
23 | + | ||
24 | +@ToString | ||
25 | +public abstract class AbstractDataQuery<T extends EntityDataPageLink> extends EntityCountQuery { | ||
26 | + | ||
27 | + @Getter | ||
28 | + protected T pageLink; | ||
29 | + @Getter | ||
30 | + protected List<EntityKey> entityFields; | ||
31 | + @Getter | ||
32 | + protected List<EntityKey> latestValues; | ||
33 | + @Getter | ||
34 | + protected List<KeyFilter> keyFilters; | ||
35 | + | ||
36 | + public AbstractDataQuery() { | ||
37 | + super(); | ||
38 | + } | ||
39 | + | ||
40 | + public AbstractDataQuery(EntityFilter entityFilter) { | ||
41 | + super(entityFilter); | ||
42 | + } | ||
43 | + | ||
44 | + public AbstractDataQuery(EntityFilter entityFilter, | ||
45 | + T pageLink, | ||
46 | + List<EntityKey> entityFields, | ||
47 | + List<EntityKey> latestValues, | ||
48 | + List<KeyFilter> keyFilters) { | ||
49 | + super(entityFilter); | ||
50 | + this.pageLink = pageLink; | ||
51 | + this.entityFields = entityFields; | ||
52 | + this.latestValues = latestValues; | ||
53 | + this.keyFilters = keyFilters; | ||
54 | + } | ||
55 | + | ||
56 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.query; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import org.thingsboard.server.common.data.alarm.Alarm; | ||
20 | +import org.thingsboard.server.common.data.alarm.AlarmInfo; | ||
21 | +import org.thingsboard.server.common.data.id.EntityId; | ||
22 | + | ||
23 | +import java.util.HashMap; | ||
24 | +import java.util.Map; | ||
25 | +import java.util.UUID; | ||
26 | + | ||
27 | +public class AlarmData extends AlarmInfo { | ||
28 | + | ||
29 | + private final UUID entityId; | ||
30 | + private final Map<EntityKeyType, Map<String, TsValue>> latest; | ||
31 | + | ||
32 | + public AlarmData(Alarm alarm, String originatorName, UUID entityId) { | ||
33 | + super(alarm, originatorName); | ||
34 | + this.entityId = entityId; | ||
35 | + this.latest = new HashMap<>(); | ||
36 | + } | ||
37 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.query; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import lombok.AllArgsConstructor; | ||
20 | +import lombok.Data; | ||
21 | +import lombok.Getter; | ||
22 | +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | ||
23 | +import org.thingsboard.server.common.data.alarm.AlarmSeverity; | ||
24 | +import org.thingsboard.server.common.data.alarm.AlarmStatus; | ||
25 | + | ||
26 | +import java.util.List; | ||
27 | + | ||
28 | +@Data | ||
29 | +@AllArgsConstructor | ||
30 | +public class AlarmDataPageLink extends EntityDataPageLink { | ||
31 | + | ||
32 | + private long startTs; | ||
33 | + private long endTs; | ||
34 | + //TODO: handle this; | ||
35 | + private long timeWindow; | ||
36 | + private List<String> typeList; | ||
37 | + private List<AlarmSearchStatus> statusList; | ||
38 | + private List<AlarmSeverity> severityList; | ||
39 | + private boolean searchPropagatedAlarms; | ||
40 | + | ||
41 | + public AlarmDataPageLink() { | ||
42 | + super(); | ||
43 | + } | ||
44 | + | ||
45 | + public AlarmDataPageLink(int pageSize, int page, String textSearch, EntityDataSortOrder sortOrder, boolean dynamic, | ||
46 | + boolean searchPropagatedAlarms, | ||
47 | + long startTs, long endTs, long timeWindow, | ||
48 | + List<String> typeList, List<AlarmSearchStatus> statusList, List<AlarmSeverity> severityList) { | ||
49 | + super(pageSize, page, textSearch, sortOrder, dynamic); | ||
50 | + this.searchPropagatedAlarms = searchPropagatedAlarms; | ||
51 | + this.startTs = startTs; | ||
52 | + this.endTs = endTs; | ||
53 | + this.timeWindow = timeWindow; | ||
54 | + this.typeList = typeList; | ||
55 | + this.statusList = statusList; | ||
56 | + this.severityList = severityList; | ||
57 | + } | ||
58 | + | ||
59 | + @JsonIgnore | ||
60 | + public AlarmDataPageLink nextPageLink() { | ||
61 | + return new AlarmDataPageLink(this.getPageSize(), this.getPage() + 1, this.getTextSearch(), this.getSortOrder(), this.isDynamic(), | ||
62 | + this.searchPropagatedAlarms, | ||
63 | + this.startTs, this.endTs, this.timeWindow, | ||
64 | + this.typeList, this.statusList, this.severityList | ||
65 | + ); | ||
66 | + } | ||
67 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.query; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import lombok.Getter; | ||
20 | +import lombok.ToString; | ||
21 | + | ||
22 | +import java.util.List; | ||
23 | + | ||
24 | +@ToString | ||
25 | +public class AlarmDataQuery extends AbstractDataQuery<AlarmDataPageLink> { | ||
26 | + | ||
27 | + public AlarmDataQuery() { | ||
28 | + } | ||
29 | + | ||
30 | + public AlarmDataQuery(EntityFilter entityFilter) { | ||
31 | + super(entityFilter); | ||
32 | + } | ||
33 | + | ||
34 | + public AlarmDataQuery(EntityFilter entityFilter, AlarmDataPageLink pageLink, List<EntityKey> entityFields, List<EntityKey> latestValues, List<KeyFilter> keyFilters) { | ||
35 | + super(entityFilter, pageLink, entityFields, latestValues, keyFilters); | ||
36 | + } | ||
37 | + | ||
38 | + @JsonIgnore | ||
39 | + public AlarmDataQuery next() { | ||
40 | + return new AlarmDataQuery(getEntityFilter(), getPageLink().nextPageLink(), entityFields, latestValues, keyFilters); | ||
41 | + } | ||
42 | +} |
@@ -38,6 +38,6 @@ public class EntityDataPageLink { | @@ -38,6 +38,6 @@ public class EntityDataPageLink { | ||
38 | 38 | ||
39 | @JsonIgnore | 39 | @JsonIgnore |
40 | public EntityDataPageLink nextPageLink() { | 40 | public EntityDataPageLink nextPageLink() { |
41 | - return new EntityDataPageLink(this.pageSize, this.page+1, this.textSearch, this.sortOrder); | 41 | + return new EntityDataPageLink(this.pageSize, this.page + 1, this.textSearch, this.sortOrder); |
42 | } | 42 | } |
43 | } | 43 | } |
@@ -22,39 +22,22 @@ import lombok.ToString; | @@ -22,39 +22,22 @@ import lombok.ToString; | ||
22 | import java.util.List; | 22 | import java.util.List; |
23 | 23 | ||
24 | @ToString | 24 | @ToString |
25 | -public class EntityDataQuery extends EntityCountQuery { | ||
26 | - | ||
27 | - @Getter | ||
28 | - private EntityDataPageLink pageLink; | ||
29 | - @Getter | ||
30 | - private List<EntityKey> entityFields; | ||
31 | - @Getter | ||
32 | - private List<EntityKey> latestValues; | ||
33 | - @Getter | ||
34 | - private List<KeyFilter> keyFilters; | 25 | +public class EntityDataQuery extends AbstractDataQuery<EntityDataPageLink> { |
35 | 26 | ||
36 | public EntityDataQuery() { | 27 | public EntityDataQuery() { |
37 | - super(); | ||
38 | } | 28 | } |
39 | 29 | ||
40 | public EntityDataQuery(EntityFilter entityFilter) { | 30 | public EntityDataQuery(EntityFilter entityFilter) { |
41 | super(entityFilter); | 31 | super(entityFilter); |
42 | } | 32 | } |
43 | 33 | ||
44 | - public EntityDataQuery(EntityFilter entityFilter, | ||
45 | - EntityDataPageLink pageLink, | ||
46 | - List<EntityKey> entityFields, | ||
47 | - List<EntityKey> latestValues, | ||
48 | - List<KeyFilter> keyFilters) { | ||
49 | - super(entityFilter); | ||
50 | - this.pageLink = pageLink; | ||
51 | - this.entityFields = entityFields; | ||
52 | - this.latestValues = latestValues; | ||
53 | - this.keyFilters = keyFilters; | 34 | + public EntityDataQuery(EntityFilter entityFilter, EntityDataPageLink pageLink, List<EntityKey> entityFields, List<EntityKey> latestValues, List<KeyFilter> keyFilters) { |
35 | + super(entityFilter, pageLink, entityFields, latestValues, keyFilters); | ||
54 | } | 36 | } |
55 | 37 | ||
56 | @JsonIgnore | 38 | @JsonIgnore |
57 | public EntityDataQuery next() { | 39 | public EntityDataQuery next() { |
58 | - return new EntityDataQuery(getEntityFilter(), pageLink.nextPageLink(), entityFields, latestValues, keyFilters); | 40 | + return new EntityDataQuery(getEntityFilter(), getPageLink().nextPageLink(), entityFields, latestValues, keyFilters); |
59 | } | 41 | } |
42 | + | ||
60 | } | 43 | } |
@@ -19,11 +19,16 @@ import com.google.common.util.concurrent.ListenableFuture; | @@ -19,11 +19,16 @@ 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.AlarmInfo; |
21 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 21 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
22 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
22 | import org.thingsboard.server.common.data.id.EntityId; | 23 | import org.thingsboard.server.common.data.id.EntityId; |
23 | import org.thingsboard.server.common.data.id.TenantId; | 24 | import org.thingsboard.server.common.data.id.TenantId; |
24 | import org.thingsboard.server.common.data.page.PageData; | 25 | import org.thingsboard.server.common.data.page.PageData; |
26 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
27 | +import org.thingsboard.server.common.data.query.AlarmDataPageLink; | ||
28 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
25 | import org.thingsboard.server.dao.Dao; | 29 | import org.thingsboard.server.dao.Dao; |
26 | 30 | ||
31 | +import java.util.Collection; | ||
27 | import java.util.UUID; | 32 | import java.util.UUID; |
28 | 33 | ||
29 | /** | 34 | /** |
@@ -40,4 +45,7 @@ public interface AlarmDao extends Dao<Alarm> { | @@ -40,4 +45,7 @@ public interface AlarmDao extends Dao<Alarm> { | ||
40 | Alarm save(TenantId tenantId, Alarm alarm); | 45 | Alarm save(TenantId tenantId, Alarm alarm); |
41 | 46 | ||
42 | PageData<AlarmInfo> findAlarms(TenantId tenantId, AlarmQuery query); | 47 | PageData<AlarmInfo> findAlarms(TenantId tenantId, AlarmQuery query); |
48 | + | ||
49 | + PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, | ||
50 | + AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds); | ||
43 | } | 51 | } |
@@ -35,10 +35,14 @@ import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | @@ -35,10 +35,14 @@ import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | ||
35 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 35 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
36 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 36 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
37 | import org.thingsboard.server.common.data.id.AlarmId; | 37 | import org.thingsboard.server.common.data.id.AlarmId; |
38 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
38 | import org.thingsboard.server.common.data.id.EntityId; | 39 | import org.thingsboard.server.common.data.id.EntityId; |
39 | import org.thingsboard.server.common.data.id.TenantId; | 40 | import org.thingsboard.server.common.data.id.TenantId; |
40 | import org.thingsboard.server.common.data.page.PageData; | 41 | import org.thingsboard.server.common.data.page.PageData; |
41 | import org.thingsboard.server.common.data.page.TimePageLink; | 42 | import org.thingsboard.server.common.data.page.TimePageLink; |
43 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
44 | +import org.thingsboard.server.common.data.query.AlarmDataPageLink; | ||
45 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
42 | import org.thingsboard.server.common.data.relation.EntityRelation; | 46 | import org.thingsboard.server.common.data.relation.EntityRelation; |
43 | import org.thingsboard.server.common.data.relation.EntityRelationsQuery; | 47 | import org.thingsboard.server.common.data.relation.EntityRelationsQuery; |
44 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; | 48 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
@@ -54,6 +58,7 @@ import javax.annotation.Nullable; | @@ -54,6 +58,7 @@ import javax.annotation.Nullable; | ||
54 | import javax.annotation.PostConstruct; | 58 | import javax.annotation.PostConstruct; |
55 | import javax.annotation.PreDestroy; | 59 | import javax.annotation.PreDestroy; |
56 | import java.util.ArrayList; | 60 | import java.util.ArrayList; |
61 | +import java.util.Collection; | ||
57 | import java.util.Comparator; | 62 | import java.util.Comparator; |
58 | import java.util.List; | 63 | import java.util.List; |
59 | import java.util.Set; | 64 | import java.util.Set; |
@@ -69,6 +74,8 @@ import static org.thingsboard.server.dao.service.Validator.validateId; | @@ -69,6 +74,8 @@ import static org.thingsboard.server.dao.service.Validator.validateId; | ||
69 | @Slf4j | 74 | @Slf4j |
70 | public class BaseAlarmService extends AbstractEntityService implements AlarmService { | 75 | public class BaseAlarmService extends AbstractEntityService implements AlarmService { |
71 | 76 | ||
77 | + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; | ||
78 | + public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; | ||
72 | public static final String ALARM_RELATION_PREFIX = "ALARM_"; | 79 | public static final String ALARM_RELATION_PREFIX = "ALARM_"; |
73 | 80 | ||
74 | @Autowired | 81 | @Autowired |
@@ -124,6 +131,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | @@ -124,6 +131,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ | ||
124 | } | 131 | } |
125 | 132 | ||
126 | @Override | 133 | @Override |
134 | + public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, | ||
135 | + AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds) { | ||
136 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
137 | + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId); | ||
138 | + return alarmDao.findAlarmDataByQueryForEntities(tenantId, customerId, pageLink, orderedEntityIds); | ||
139 | + } | ||
140 | + | ||
141 | + @Override | ||
127 | public Boolean deleteAlarm(TenantId tenantId, AlarmId alarmId) { | 142 | public Boolean deleteAlarm(TenantId tenantId, AlarmId alarmId) { |
128 | try { | 143 | try { |
129 | log.debug("Deleting Alarm Id: {}", alarmId); | 144 | log.debug("Deleting Alarm Id: {}", alarmId); |
@@ -227,6 +227,7 @@ public class ModelConstants { | @@ -227,6 +227,7 @@ public class ModelConstants { | ||
227 | public static final String ALARM_TYPE_PROPERTY = "type"; | 227 | public static final String ALARM_TYPE_PROPERTY = "type"; |
228 | public static final String ALARM_DETAILS_PROPERTY = "details"; | 228 | public static final String ALARM_DETAILS_PROPERTY = "details"; |
229 | public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id"; | 229 | public static final String ALARM_ORIGINATOR_ID_PROPERTY = "originator_id"; |
230 | + public static final String ALARM_ORIGINATOR_NAME_PROPERTY = "originator_name"; | ||
230 | public static final String ALARM_ORIGINATOR_TYPE_PROPERTY = "originator_type"; | 231 | public static final String ALARM_ORIGINATOR_TYPE_PROPERTY = "originator_type"; |
231 | public static final String ALARM_SEVERITY_PROPERTY = "severity"; | 232 | public static final String ALARM_SEVERITY_PROPERTY = "severity"; |
232 | public static final String ALARM_STATUS_PROPERTY = "status"; | 233 | public static final String ALARM_STATUS_PROPERTY = "status"; |
@@ -20,10 +20,17 @@ import org.springframework.data.domain.Pageable; | @@ -20,10 +20,17 @@ import org.springframework.data.domain.Pageable; | ||
20 | import org.springframework.data.jpa.repository.Query; | 20 | import org.springframework.data.jpa.repository.Query; |
21 | import org.springframework.data.repository.CrudRepository; | 21 | import org.springframework.data.repository.CrudRepository; |
22 | import org.springframework.data.repository.query.Param; | 22 | import org.springframework.data.repository.query.Param; |
23 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
24 | +import org.thingsboard.server.common.data.id.EntityId; | ||
25 | +import org.thingsboard.server.common.data.id.TenantId; | ||
26 | +import org.thingsboard.server.common.data.page.PageData; | ||
27 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
28 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
23 | import org.thingsboard.server.dao.model.sql.AlarmEntity; | 29 | import org.thingsboard.server.dao.model.sql.AlarmEntity; |
24 | import org.thingsboard.server.dao.model.sql.AlarmInfoEntity; | 30 | import org.thingsboard.server.dao.model.sql.AlarmInfoEntity; |
25 | import org.thingsboard.server.dao.util.SqlDao; | 31 | import org.thingsboard.server.dao.util.SqlDao; |
26 | 32 | ||
33 | +import java.util.Collection; | ||
27 | import java.util.List; | 34 | import java.util.List; |
28 | import java.util.UUID; | 35 | import java.util.UUID; |
29 | 36 | ||
@@ -72,4 +79,6 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> { | @@ -72,4 +79,6 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> { | ||
72 | @Param("endTime") Long endTime, | 79 | @Param("endTime") Long endTime, |
73 | @Param("searchText") String searchText, | 80 | @Param("searchText") String searchText, |
74 | Pageable pageable); | 81 | Pageable pageable); |
82 | + | ||
83 | + | ||
75 | } | 84 | } |
@@ -26,17 +26,23 @@ import org.thingsboard.server.common.data.alarm.Alarm; | @@ -26,17 +26,23 @@ import org.thingsboard.server.common.data.alarm.Alarm; | ||
26 | import org.thingsboard.server.common.data.alarm.AlarmInfo; | 26 | import org.thingsboard.server.common.data.alarm.AlarmInfo; |
27 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 27 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
28 | import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | 28 | import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; |
29 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
29 | import org.thingsboard.server.common.data.id.EntityId; | 30 | import org.thingsboard.server.common.data.id.EntityId; |
30 | import org.thingsboard.server.common.data.id.TenantId; | 31 | import org.thingsboard.server.common.data.id.TenantId; |
31 | import org.thingsboard.server.common.data.page.PageData; | 32 | import org.thingsboard.server.common.data.page.PageData; |
33 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
34 | +import org.thingsboard.server.common.data.query.AlarmDataPageLink; | ||
35 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
32 | import org.thingsboard.server.dao.DaoUtil; | 36 | import org.thingsboard.server.dao.DaoUtil; |
33 | import org.thingsboard.server.dao.alarm.AlarmDao; | 37 | import org.thingsboard.server.dao.alarm.AlarmDao; |
34 | import org.thingsboard.server.dao.alarm.BaseAlarmService; | 38 | import org.thingsboard.server.dao.alarm.BaseAlarmService; |
35 | import org.thingsboard.server.dao.model.sql.AlarmEntity; | 39 | import org.thingsboard.server.dao.model.sql.AlarmEntity; |
36 | import org.thingsboard.server.dao.relation.RelationDao; | 40 | import org.thingsboard.server.dao.relation.RelationDao; |
37 | import org.thingsboard.server.dao.sql.JpaAbstractDao; | 41 | import org.thingsboard.server.dao.sql.JpaAbstractDao; |
42 | +import org.thingsboard.server.dao.sql.query.AlarmQueryRepository; | ||
38 | import org.thingsboard.server.dao.util.SqlDao; | 43 | import org.thingsboard.server.dao.util.SqlDao; |
39 | 44 | ||
45 | +import java.util.Collection; | ||
40 | import java.util.List; | 46 | import java.util.List; |
41 | import java.util.Objects; | 47 | import java.util.Objects; |
42 | import java.util.UUID; | 48 | import java.util.UUID; |
@@ -56,6 +62,9 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A | @@ -56,6 +62,9 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A | ||
56 | private AlarmRepository alarmRepository; | 62 | private AlarmRepository alarmRepository; |
57 | 63 | ||
58 | @Autowired | 64 | @Autowired |
65 | + private AlarmQueryRepository alarmQueryRepository; | ||
66 | + | ||
67 | + @Autowired | ||
59 | private RelationDao relationDao; | 68 | private RelationDao relationDao; |
60 | 69 | ||
61 | @Override | 70 | @Override |
@@ -116,4 +125,9 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A | @@ -116,4 +125,9 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A | ||
116 | ) | 125 | ) |
117 | ); | 126 | ); |
118 | } | 127 | } |
128 | + | ||
129 | + @Override | ||
130 | + public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds) { | ||
131 | + return alarmQueryRepository.findAlarmDataByQueryForEntities(tenantId, customerId, pageLink, orderedEntityIds); | ||
132 | + } | ||
119 | } | 133 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.dao.sql.query; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.springframework.util.StringUtils; | ||
22 | +import org.thingsboard.server.common.data.EntityType; | ||
23 | +import org.thingsboard.server.common.data.alarm.Alarm; | ||
24 | +import org.thingsboard.server.common.data.alarm.AlarmSeverity; | ||
25 | +import org.thingsboard.server.common.data.alarm.AlarmStatus; | ||
26 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
27 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | ||
28 | +import org.thingsboard.server.common.data.id.TenantId; | ||
29 | +import org.thingsboard.server.common.data.page.PageData; | ||
30 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
31 | +import org.thingsboard.server.common.data.query.EntityDataPageLink; | ||
32 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
33 | + | ||
34 | +import java.util.Arrays; | ||
35 | +import java.util.Collections; | ||
36 | +import java.util.List; | ||
37 | +import java.util.Map; | ||
38 | +import java.util.UUID; | ||
39 | +import java.util.stream.Collectors; | ||
40 | + | ||
41 | +@Slf4j | ||
42 | +public class AlarmDataAdapter { | ||
43 | + | ||
44 | + private final static ObjectMapper mapper = new ObjectMapper(); | ||
45 | + | ||
46 | + public static PageData<AlarmData> createAlarmData(EntityDataPageLink pageLink, | ||
47 | + List<Map<String, Object>> rows, | ||
48 | + int totalElements) { | ||
49 | + int totalPages = pageLink.getPageSize() > 0 ? (int) Math.ceil((float) totalElements / pageLink.getPageSize()) : 1; | ||
50 | + int startIndex = pageLink.getPageSize() * pageLink.getPage(); | ||
51 | + boolean hasNext = pageLink.getPageSize() > 0 && totalElements > startIndex + rows.size(); | ||
52 | + List<AlarmData> entitiesData = convertListToAlarmData(rows); | ||
53 | + return new PageData<>(entitiesData, totalPages, totalElements, hasNext); | ||
54 | + } | ||
55 | + | ||
56 | + private static List<AlarmData> convertListToAlarmData(List<Map<String, Object>> result) { | ||
57 | + return result.stream().map(AlarmDataAdapter::toEntityData).collect(Collectors.toList()); | ||
58 | + } | ||
59 | + | ||
60 | + private static AlarmData toEntityData(Map<String, Object> row) { | ||
61 | + Alarm alarm = new Alarm(); | ||
62 | + alarm.setId(new AlarmId((UUID) row.get(ModelConstants.ID_PROPERTY))); | ||
63 | + alarm.setCreatedTime((long) row.get(ModelConstants.CREATED_TIME_PROPERTY)); | ||
64 | + alarm.setAckTs((long) row.get(ModelConstants.ALARM_ACK_TS_PROPERTY)); | ||
65 | + alarm.setClearTs((long) row.get(ModelConstants.ALARM_CLEAR_TS_PROPERTY)); | ||
66 | + alarm.setStartTs((long) row.get(ModelConstants.ALARM_START_TS_PROPERTY)); | ||
67 | + alarm.setEndTs((long) row.get(ModelConstants.ALARM_END_TS_PROPERTY)); | ||
68 | + Object additionalInfo = row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY); | ||
69 | + if (additionalInfo != null) { | ||
70 | + try { | ||
71 | + alarm.setDetails(mapper.readTree(additionalInfo.toString())); | ||
72 | + } catch (JsonProcessingException e) { | ||
73 | + log.warn("Failed to parse json: {}", row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY), e); | ||
74 | + } | ||
75 | + } | ||
76 | + EntityType originatorType = EntityType.values()[(int) row.get(ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY)]; | ||
77 | + UUID originatorId = (UUID) row.get(ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY); | ||
78 | + alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId)); | ||
79 | + alarm.setPropagate((boolean) row.get(ModelConstants.ALARM_PROPAGATE_PROPERTY)); | ||
80 | + alarm.setType(row.get(ModelConstants.ALARM_TYPE_PROPERTY).toString()); | ||
81 | + alarm.setSeverity(AlarmSeverity.valueOf(row.get(ModelConstants.ALARM_SEVERITY_PROPERTY).toString())); | ||
82 | + alarm.setStatus(AlarmStatus.valueOf(row.get(ModelConstants.ALARM_STATUS_PROPERTY).toString())); | ||
83 | + alarm.setTenantId(new TenantId((UUID) row.get(ModelConstants.TENANT_ID_PROPERTY))); | ||
84 | + if (row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES) != null) { | ||
85 | + String propagateRelationTypes = row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES).toString(); | ||
86 | + if (!StringUtils.isEmpty(propagateRelationTypes)) { | ||
87 | + alarm.setPropagateRelationTypes(Arrays.asList(propagateRelationTypes.split(","))); | ||
88 | + } else { | ||
89 | + alarm.setPropagateRelationTypes(Collections.emptyList()); | ||
90 | + } | ||
91 | + } else { | ||
92 | + alarm.setPropagateRelationTypes(Collections.emptyList()); | ||
93 | + } | ||
94 | + UUID entityId = (UUID) row.get(ModelConstants.ENTITY_ID_COLUMN); | ||
95 | + Object originatorNameObj = row.get(ModelConstants.ALARM_ORIGINATOR_NAME_PROPERTY); | ||
96 | + String originatorName = originatorNameObj != null ? originatorNameObj.toString() : null; | ||
97 | + return new AlarmData(alarm, originatorName, entityId); | ||
98 | + } | ||
99 | + | ||
100 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.dao.sql.query; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
19 | +import org.thingsboard.server.common.data.id.EntityId; | ||
20 | +import org.thingsboard.server.common.data.id.TenantId; | ||
21 | +import org.thingsboard.server.common.data.page.PageData; | ||
22 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
23 | +import org.thingsboard.server.common.data.query.AlarmDataPageLink; | ||
24 | + | ||
25 | +import java.util.Collection; | ||
26 | + | ||
27 | +public interface AlarmQueryRepository { | ||
28 | + | ||
29 | + PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, | ||
30 | + AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds); | ||
31 | + | ||
32 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2020 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.dao.sql.query; | ||
17 | + | ||
18 | +import lombok.extern.slf4j.Slf4j; | ||
19 | +import org.springframework.beans.factory.annotation.Autowired; | ||
20 | +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; | ||
21 | +import org.springframework.stereotype.Repository; | ||
22 | +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | ||
23 | +import org.thingsboard.server.common.data.alarm.AlarmSeverity; | ||
24 | +import org.thingsboard.server.common.data.alarm.AlarmStatus; | ||
25 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
26 | +import org.thingsboard.server.common.data.id.EntityId; | ||
27 | +import org.thingsboard.server.common.data.id.TenantId; | ||
28 | +import org.thingsboard.server.common.data.page.PageData; | ||
29 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
30 | +import org.thingsboard.server.common.data.query.AlarmDataPageLink; | ||
31 | +import org.thingsboard.server.common.data.query.EntityDataSortOrder; | ||
32 | +import org.thingsboard.server.common.data.query.EntityKeyType; | ||
33 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
34 | +import org.thingsboard.server.dao.util.SqlDao; | ||
35 | + | ||
36 | +import java.util.Collection; | ||
37 | +import java.util.HashMap; | ||
38 | +import java.util.HashSet; | ||
39 | +import java.util.List; | ||
40 | +import java.util.Map; | ||
41 | +import java.util.Set; | ||
42 | +import java.util.stream.Collectors; | ||
43 | + | ||
44 | +@SqlDao | ||
45 | +@Repository | ||
46 | +@Slf4j | ||
47 | +public class DefaultAlarmQueryRepository implements AlarmQueryRepository { | ||
48 | + | ||
49 | + private static final Map<String, String> alarmFieldColumnMap = new HashMap<>(); | ||
50 | + | ||
51 | + static { | ||
52 | + alarmFieldColumnMap.put("createdTime", ModelConstants.CREATED_TIME_PROPERTY); | ||
53 | + alarmFieldColumnMap.put("ackTs", ModelConstants.ALARM_ACK_TS_PROPERTY); | ||
54 | + alarmFieldColumnMap.put("clearTs", ModelConstants.ALARM_CLEAR_TS_PROPERTY); | ||
55 | + alarmFieldColumnMap.put("details", ModelConstants.ADDITIONAL_INFO_PROPERTY); | ||
56 | + alarmFieldColumnMap.put("endTs", ModelConstants.ALARM_END_TS_PROPERTY); | ||
57 | + alarmFieldColumnMap.put("startTs", ModelConstants.ALARM_START_TS_PROPERTY); | ||
58 | + alarmFieldColumnMap.put("status", ModelConstants.ALARM_STATUS_PROPERTY); | ||
59 | + alarmFieldColumnMap.put("type", ModelConstants.ALARM_TYPE_PROPERTY); | ||
60 | + alarmFieldColumnMap.put("severity", ModelConstants.ALARM_SEVERITY_PROPERTY); | ||
61 | + alarmFieldColumnMap.put("originator_id", ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY); | ||
62 | + alarmFieldColumnMap.put("originator_type", ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY); | ||
63 | + } | ||
64 | + | ||
65 | + public static final String SELECT_ORIGINATOR_NAME = " CASE" + | ||
66 | + " WHEN a.originator_type = 0" + | ||
67 | + " THEN (select title from tenant where id = a.originator_id)" + | ||
68 | + " WHEN a.originator_type = 1 " + | ||
69 | + " THEN (select title from customer where id = a.originator_id)" + | ||
70 | + " WHEN a.originator_type = 2" + | ||
71 | + " THEN (select CONCAT (first_name, ' ', last_name) from tb_user where id = a.originator_id)" + | ||
72 | + " WHEN a.originator_type = 3" + | ||
73 | + " THEN (select title from dashboard where id = a.originator_id)" + | ||
74 | + " WHEN a.originator_type = 4" + | ||
75 | + " THEN (select name from asset where id = a.originator_id)" + | ||
76 | + " WHEN a.originator_type = 5" + | ||
77 | + " THEN (select name from device where id = a.originator_id)" + | ||
78 | + " WHEN a.originator_type = 9" + | ||
79 | + " THEN (select name from entity_view where id = a.originator_id)" + | ||
80 | + " END as originator_name"; | ||
81 | + | ||
82 | + public static final String FIELDS_SELECTION = "select a.id as id," + | ||
83 | + " a.created_time as created_time," + | ||
84 | + " a.ack_ts as ack_ts," + | ||
85 | + " a.clear_ts as clear_ts," + | ||
86 | + " a.additional_info as additional_info," + | ||
87 | + " a.end_ts as end_ts," + | ||
88 | + " a.originator_id as originator_id," + | ||
89 | + " a.originator_type as originator_type," + | ||
90 | + " a.propagate as propagate," + | ||
91 | + " a.severity as severity," + | ||
92 | + " a.start_ts as start_ts," + | ||
93 | + " a.status as status, " + | ||
94 | + " a.tenant_id as tenant_id, " + | ||
95 | + " a.propagate_relation_types as propagate_relation_types, " + | ||
96 | + " a.type as type," + SELECT_ORIGINATOR_NAME + ", "; | ||
97 | + | ||
98 | + public static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ALARM_ANY' and a.id = r.to_id"; | ||
99 | + | ||
100 | + @Autowired | ||
101 | + protected NamedParameterJdbcTemplate jdbcTemplate; | ||
102 | + | ||
103 | + | ||
104 | + @Override | ||
105 | + public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, | ||
106 | + AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds) { | ||
107 | + QueryContext ctx = new QueryContext(); | ||
108 | + | ||
109 | + StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION); | ||
110 | + StringBuilder fromPart = new StringBuilder(" from alarm a "); | ||
111 | + StringBuilder wherePart = new StringBuilder(" where "); | ||
112 | + StringBuilder sortPart = new StringBuilder(" order by "); | ||
113 | + boolean addAnd = false; | ||
114 | + if (pageLink.isSearchPropagatedAlarms()) { | ||
115 | + selectPart.append(" r.from_id as entity_id "); | ||
116 | + fromPart.append(JOIN_RELATIONS); | ||
117 | + } else { | ||
118 | + selectPart.append(" a.originator_id as entity_id "); | ||
119 | + } | ||
120 | + EntityDataSortOrder sortOrder = pageLink.getSortOrder(); | ||
121 | + if (sortOrder != null && sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { | ||
122 | + String sortOrderKey = sortOrder.getKey().getKey(); | ||
123 | + sortPart.append("a.").append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey)) | ||
124 | + .append(" ").append(sortOrder.getDirection().name()); | ||
125 | + ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList())); | ||
126 | + if (pageLink.isSearchPropagatedAlarms()) { | ||
127 | + fromPart.append(" and r.from_id in (:entity_ids)"); | ||
128 | + } else { | ||
129 | + wherePart.append(" a.originator_id in (:entity_ids)"); | ||
130 | + addAnd = true; | ||
131 | + } | ||
132 | + } else { | ||
133 | + fromPart.append(" left join (select * from (VALUES"); | ||
134 | + int entityIdIdx = 0; | ||
135 | + int lastEntityIdIdx = orderedEntityIds.size() - 1; | ||
136 | + for (EntityId entityId : orderedEntityIds) { | ||
137 | + fromPart.append("(uuid('").append(entityId.getId().toString()).append("'), ").append(entityIdIdx).append(")"); | ||
138 | + if (entityIdIdx != lastEntityIdIdx) { | ||
139 | + fromPart.append(","); | ||
140 | + } else { | ||
141 | + fromPart.append(")"); | ||
142 | + } | ||
143 | + entityIdIdx++; | ||
144 | + } | ||
145 | + fromPart.append(" as e(id, priority)) e "); | ||
146 | + if (pageLink.isSearchPropagatedAlarms()) { | ||
147 | + fromPart.append("on r.from_id = e.id"); | ||
148 | + } else { | ||
149 | + fromPart.append("on a.originator_id = e.id"); | ||
150 | + } | ||
151 | + sortPart.append("e.priority"); | ||
152 | + } | ||
153 | + | ||
154 | + if (pageLink.getStartTs() > 0) { | ||
155 | + addAndIfNeeded(wherePart, addAnd); | ||
156 | + addAnd = true; | ||
157 | + ctx.addLongParameter("startTime", pageLink.getStartTs()); | ||
158 | + wherePart.append("a.created_time >= :startTime"); | ||
159 | + } | ||
160 | + | ||
161 | + if (pageLink.getEndTs() > 0) { | ||
162 | + addAndIfNeeded(wherePart, addAnd); | ||
163 | + addAnd = true; | ||
164 | + ctx.addLongParameter("endTime", pageLink.getEndTs()); | ||
165 | + wherePart.append("a.created_time <= :endTime"); | ||
166 | + } | ||
167 | + | ||
168 | + if (pageLink.getTypeList() != null && !pageLink.getTypeList().isEmpty()) { | ||
169 | + addAndIfNeeded(wherePart, addAnd); | ||
170 | + addAnd = true; | ||
171 | + ctx.addStringListParameter("alarmTypes", pageLink.getTypeList()); | ||
172 | + wherePart.append("a.type in (:alarmTypes)"); | ||
173 | + } | ||
174 | + | ||
175 | + if (pageLink.getSeverityList() != null && !pageLink.getSeverityList().isEmpty()) { | ||
176 | + addAndIfNeeded(wherePart, addAnd); | ||
177 | + addAnd = true; | ||
178 | + ctx.addStringListParameter("alarmSeverities", pageLink.getSeverityList().stream().map(AlarmSeverity::name).collect(Collectors.toList())); | ||
179 | + wherePart.append("a.severity in (:alarmSeverities)"); | ||
180 | + } | ||
181 | + | ||
182 | + if (pageLink.getStatusList() != null && !pageLink.getStatusList().isEmpty()) { | ||
183 | + Set<AlarmStatus> statusSet = toStatusSet(pageLink.getStatusList()); | ||
184 | + if (!statusSet.isEmpty()) { | ||
185 | + addAndIfNeeded(wherePart, addAnd); | ||
186 | + addAnd = true; | ||
187 | + ctx.addStringListParameter("alarmStatuses", statusSet.stream().map(AlarmStatus::name).collect(Collectors.toList())); | ||
188 | + wherePart.append(" a.status in (:alarmStatuses)"); | ||
189 | + } | ||
190 | + } | ||
191 | + | ||
192 | + String countQuery = fromPart.toString() + wherePart.toString(); | ||
193 | + int totalElements = jdbcTemplate.queryForObject(String.format("select count(*) %s", countQuery), ctx, Integer.class); | ||
194 | + | ||
195 | + String dataQuery = selectPart.toString() + countQuery + sortPart; | ||
196 | + | ||
197 | + int startIndex = pageLink.getPageSize() * pageLink.getPage(); | ||
198 | + if (pageLink.getPageSize() > 0) { | ||
199 | + dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex); | ||
200 | + } | ||
201 | + List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx); | ||
202 | + return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements); | ||
203 | + } | ||
204 | + | ||
205 | + private Set<AlarmStatus> toStatusSet(List<AlarmSearchStatus> statusList) { | ||
206 | + Set<AlarmStatus> result = new HashSet<>(); | ||
207 | + for (AlarmSearchStatus searchStatus : statusList) { | ||
208 | + switch (searchStatus) { | ||
209 | + case ACK: | ||
210 | + result.add(AlarmStatus.ACTIVE_ACK); | ||
211 | + result.add(AlarmStatus.CLEARED_ACK); | ||
212 | + break; | ||
213 | + case UNACK: | ||
214 | + result.add(AlarmStatus.ACTIVE_UNACK); | ||
215 | + result.add(AlarmStatus.CLEARED_UNACK); | ||
216 | + break; | ||
217 | + case CLEARED: | ||
218 | + result.add(AlarmStatus.CLEARED_ACK); | ||
219 | + result.add(AlarmStatus.CLEARED_UNACK); | ||
220 | + break; | ||
221 | + case ACTIVE: | ||
222 | + result.add(AlarmStatus.ACTIVE_ACK); | ||
223 | + result.add(AlarmStatus.ACTIVE_UNACK); | ||
224 | + break; | ||
225 | + default: | ||
226 | + break; | ||
227 | + } | ||
228 | + if (searchStatus == AlarmSearchStatus.ANY || result.size() == AlarmStatus.values().length) { | ||
229 | + result.clear(); | ||
230 | + return result; | ||
231 | + } | ||
232 | + } | ||
233 | + return result; | ||
234 | + } | ||
235 | + | ||
236 | + private void addAndIfNeeded(StringBuilder wherePart, boolean addAnd) { | ||
237 | + if (addAnd) { | ||
238 | + wherePart.append(" and "); | ||
239 | + } | ||
240 | + } | ||
241 | +} |
@@ -218,7 +218,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -218,7 +218,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
218 | @Override | 218 | @Override |
219 | public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { | 219 | public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { |
220 | EntityType entityType = resolveEntityType(query.getEntityFilter()); | 220 | EntityType entityType = resolveEntityType(query.getEntityFilter()); |
221 | - EntityQueryContext ctx = new EntityQueryContext(); | 221 | + QueryContext ctx = new QueryContext(); |
222 | ctx.append("select count(e.id) from "); | 222 | ctx.append("select count(e.id) from "); |
223 | ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType)); | 223 | ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType)); |
224 | ctx.append(" e where "); | 224 | ctx.append(" e where "); |
@@ -228,7 +228,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -228,7 +228,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
228 | 228 | ||
229 | @Override | 229 | @Override |
230 | public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) { | 230 | public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) { |
231 | - EntityQueryContext ctx = new EntityQueryContext(); | 231 | + QueryContext ctx = new QueryContext(); |
232 | EntityType entityType = resolveEntityType(query.getEntityFilter()); | 232 | EntityType entityType = resolveEntityType(query.getEntityFilter()); |
233 | EntityDataPageLink pageLink = query.getPageLink(); | 233 | EntityDataPageLink pageLink = query.getPageLink(); |
234 | 234 | ||
@@ -308,7 +308,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -308,7 +308,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
308 | return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements); | 308 | return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements); |
309 | } | 309 | } |
310 | 310 | ||
311 | - private String buildEntityWhere(EntityQueryContext ctx, | 311 | + private String buildEntityWhere(QueryContext ctx, |
312 | TenantId tenantId, | 312 | TenantId tenantId, |
313 | CustomerId customerId, | 313 | CustomerId customerId, |
314 | EntityFilter entityFilter, | 314 | EntityFilter entityFilter, |
@@ -327,7 +327,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -327,7 +327,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
327 | return result; | 327 | return result; |
328 | } | 328 | } |
329 | 329 | ||
330 | - private String buildPermissionQuery(EntityQueryContext ctx, EntityFilter entityFilter, TenantId tenantId, CustomerId customerId, EntityType entityType) { | 330 | + private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter, TenantId tenantId, CustomerId customerId, EntityType entityType) { |
331 | switch (entityFilter.getType()) { | 331 | switch (entityFilter.getType()) { |
332 | case RELATIONS_QUERY: | 332 | case RELATIONS_QUERY: |
333 | case DEVICE_SEARCH_QUERY: | 333 | case DEVICE_SEARCH_QUERY: |
@@ -343,7 +343,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -343,7 +343,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
343 | } | 343 | } |
344 | } | 344 | } |
345 | 345 | ||
346 | - private String defaultPermissionQuery(EntityQueryContext ctx, TenantId tenantId, CustomerId customerId, EntityType entityType) { | 346 | + private String defaultPermissionQuery(QueryContext ctx, TenantId tenantId, CustomerId customerId, EntityType entityType) { |
347 | ctx.addUuidParameter("permissions_tenant_id", tenantId.getId()); | 347 | ctx.addUuidParameter("permissions_tenant_id", tenantId.getId()); |
348 | if (customerId != null && !customerId.isNullUid()) { | 348 | if (customerId != null && !customerId.isNullUid()) { |
349 | ctx.addUuidParameter("permissions_customer_id", customerId.getId()); | 349 | ctx.addUuidParameter("permissions_customer_id", customerId.getId()); |
@@ -357,7 +357,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -357,7 +357,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
357 | } | 357 | } |
358 | } | 358 | } |
359 | 359 | ||
360 | - private String buildEntityFilterQuery(EntityQueryContext ctx, EntityFilter entityFilter) { | 360 | + private String buildEntityFilterQuery(QueryContext ctx, EntityFilter entityFilter) { |
361 | switch (entityFilter.getType()) { | 361 | switch (entityFilter.getType()) { |
362 | case SINGLE_ENTITY: | 362 | case SINGLE_ENTITY: |
363 | return this.singleEntityQuery(ctx, (SingleEntityFilter) entityFilter); | 363 | return this.singleEntityQuery(ctx, (SingleEntityFilter) entityFilter); |
@@ -378,7 +378,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -378,7 +378,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
378 | } | 378 | } |
379 | } | 379 | } |
380 | 380 | ||
381 | - private String addEntityTableQuery(EntityQueryContext ctx, EntityFilter entityFilter, EntityType entityType) { | 381 | + private String addEntityTableQuery(QueryContext ctx, EntityFilter entityFilter, EntityType entityType) { |
382 | switch (entityFilter.getType()) { | 382 | switch (entityFilter.getType()) { |
383 | case RELATIONS_QUERY: | 383 | case RELATIONS_QUERY: |
384 | return relationQuery(ctx, (RelationsQueryFilter) entityFilter); | 384 | return relationQuery(ctx, (RelationsQueryFilter) entityFilter); |
@@ -393,7 +393,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -393,7 +393,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
393 | } | 393 | } |
394 | } | 394 | } |
395 | 395 | ||
396 | - private String entitySearchQuery(EntityQueryContext ctx, EntitySearchQueryFilter entityFilter, EntityType entityType, List<String> types) { | 396 | + private String entitySearchQuery(QueryContext ctx, EntitySearchQueryFilter entityFilter, EntityType entityType, List<String> types) { |
397 | EntityId rootId = entityFilter.getRootEntity(); | 397 | EntityId rootId = entityFilter.getRootEntity(); |
398 | //TODO: fetch last level only. | 398 | //TODO: fetch last level only. |
399 | //TODO: fetch distinct records. | 399 | //TODO: fetch distinct records. |
@@ -416,7 +416,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -416,7 +416,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
416 | return query; | 416 | return query; |
417 | } | 417 | } |
418 | 418 | ||
419 | - private String relationQuery(EntityQueryContext ctx, RelationsQueryFilter entityFilter) { | 419 | + private String relationQuery(QueryContext ctx, RelationsQueryFilter entityFilter) { |
420 | EntityId rootId = entityFilter.getRootEntity(); | 420 | EntityId rootId = entityFilter.getRootEntity(); |
421 | String lvlFilter = getLvlFilter(entityFilter.getMaxLevel()); | 421 | String lvlFilter = getLvlFilter(entityFilter.getMaxLevel()); |
422 | String selectFields = SELECT_TENANT_ID + ", " + SELECT_CUSTOMER_ID | 422 | String selectFields = SELECT_TENANT_ID + ", " + SELECT_CUSTOMER_ID |
@@ -478,7 +478,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -478,7 +478,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
478 | return from; | 478 | return from; |
479 | } | 479 | } |
480 | 480 | ||
481 | - private String buildWhere(EntityQueryContext ctx, List<EntityKeyMapping> latestFiltersMapping) { | 481 | + private String buildWhere(QueryContext ctx, List<EntityKeyMapping> latestFiltersMapping) { |
482 | String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping); | 482 | String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping); |
483 | if (!StringUtils.isEmpty(latestFilters)) { | 483 | if (!StringUtils.isEmpty(latestFilters)) { |
484 | return String.format("where %s", latestFilters); | 484 | return String.format("where %s", latestFilters); |
@@ -487,7 +487,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -487,7 +487,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
487 | } | 487 | } |
488 | } | 488 | } |
489 | 489 | ||
490 | - private String buildTextSearchQuery(EntityQueryContext ctx, List<EntityKeyMapping> selectionMapping, String searchText) { | 490 | + private String buildTextSearchQuery(QueryContext ctx, List<EntityKeyMapping> selectionMapping, String searchText) { |
491 | if (!StringUtils.isEmpty(searchText) && !selectionMapping.isEmpty()) { | 491 | if (!StringUtils.isEmpty(searchText) && !selectionMapping.isEmpty()) { |
492 | String lowerSearchText = searchText.toLowerCase() + "%"; | 492 | String lowerSearchText = searchText.toLowerCase() + "%"; |
493 | List<String> searchPredicates = selectionMapping.stream().map(mapping -> { | 493 | List<String> searchPredicates = selectionMapping.stream().map(mapping -> { |
@@ -502,22 +502,22 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | @@ -502,22 +502,22 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { | ||
502 | } | 502 | } |
503 | } | 503 | } |
504 | 504 | ||
505 | - private String singleEntityQuery(EntityQueryContext ctx, SingleEntityFilter filter) { | 505 | + private String singleEntityQuery(QueryContext ctx, SingleEntityFilter filter) { |
506 | ctx.addUuidParameter("entity_filter_single_entity_id", filter.getSingleEntity().getId()); | 506 | ctx.addUuidParameter("entity_filter_single_entity_id", filter.getSingleEntity().getId()); |
507 | return "e.id=:entity_filter_single_entity_id"; | 507 | return "e.id=:entity_filter_single_entity_id"; |
508 | } | 508 | } |
509 | 509 | ||
510 | - private String entityListQuery(EntityQueryContext ctx, EntityListFilter filter) { | 510 | + private String entityListQuery(QueryContext ctx, EntityListFilter filter) { |
511 | ctx.addUuidListParameter("entity_filter_entity_ids", filter.getEntityList().stream().map(UUID::fromString).collect(Collectors.toList())); | 511 | ctx.addUuidListParameter("entity_filter_entity_ids", filter.getEntityList().stream().map(UUID::fromString).collect(Collectors.toList())); |
512 | return "e.id in (:entity_filter_entity_ids)"; | 512 | return "e.id in (:entity_filter_entity_ids)"; |
513 | } | 513 | } |
514 | 514 | ||
515 | - private String entityNameQuery(EntityQueryContext ctx, EntityNameFilter filter) { | 515 | + private String entityNameQuery(QueryContext ctx, EntityNameFilter filter) { |
516 | ctx.addStringParameter("entity_filter_name_filter", filter.getEntityNameFilter()); | 516 | ctx.addStringParameter("entity_filter_name_filter", filter.getEntityNameFilter()); |
517 | return "lower(e.search_text) like lower(concat(:entity_filter_name_filter, '%%'))"; | 517 | return "lower(e.search_text) like lower(concat(:entity_filter_name_filter, '%%'))"; |
518 | } | 518 | } |
519 | 519 | ||
520 | - private String typeQuery(EntityQueryContext ctx, EntityFilter filter) { | 520 | + private String typeQuery(QueryContext ctx, EntityFilter filter) { |
521 | String type; | 521 | String type; |
522 | String name; | 522 | String name; |
523 | switch (filter.getType()) { | 523 | switch (filter.getType()) { |
@@ -194,7 +194,7 @@ public class EntityKeyMapping { | @@ -194,7 +194,7 @@ public class EntityKeyMapping { | ||
194 | } | 194 | } |
195 | } | 195 | } |
196 | 196 | ||
197 | - public Stream<String> toQueries(EntityQueryContext ctx) { | 197 | + public Stream<String> toQueries(QueryContext ctx) { |
198 | if (hasFilter()) { | 198 | if (hasFilter()) { |
199 | String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias; | 199 | String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias; |
200 | return keyFilters.stream().map(keyFilter -> | 200 | return keyFilters.stream().map(keyFilter -> |
@@ -204,7 +204,7 @@ public class EntityKeyMapping { | @@ -204,7 +204,7 @@ public class EntityKeyMapping { | ||
204 | } | 204 | } |
205 | } | 205 | } |
206 | 206 | ||
207 | - public String toLatestJoin(EntityQueryContext ctx, EntityFilter entityFilter, EntityType entityType) { | 207 | + public String toLatestJoin(QueryContext ctx, EntityFilter entityFilter, EntityType entityType) { |
208 | String entityTypeStr; | 208 | String entityTypeStr; |
209 | if (entityFilter.getType().equals(EntityFilterType.RELATIONS_QUERY)) { | 209 | if (entityFilter.getType().equals(EntityFilterType.RELATIONS_QUERY)) { |
210 | entityTypeStr = "entities.entity_type"; | 210 | entityTypeStr = "entities.entity_type"; |
@@ -239,12 +239,12 @@ public class EntityKeyMapping { | @@ -239,12 +239,12 @@ public class EntityKeyMapping { | ||
239 | Collectors.joining(", ")); | 239 | Collectors.joining(", ")); |
240 | } | 240 | } |
241 | 241 | ||
242 | - public static String buildLatestJoins(EntityQueryContext ctx, EntityFilter entityFilter, EntityType entityType, List<EntityKeyMapping> latestMappings) { | 242 | + public static String buildLatestJoins(QueryContext ctx, EntityFilter entityFilter, EntityType entityType, List<EntityKeyMapping> latestMappings) { |
243 | return latestMappings.stream().map(mapping -> mapping.toLatestJoin(ctx, entityFilter, entityType)).collect( | 243 | return latestMappings.stream().map(mapping -> mapping.toLatestJoin(ctx, entityFilter, entityType)).collect( |
244 | Collectors.joining(" ")); | 244 | Collectors.joining(" ")); |
245 | } | 245 | } |
246 | 246 | ||
247 | - public static String buildQuery(EntityQueryContext ctx, List<EntityKeyMapping> mappings) { | 247 | + public static String buildQuery(QueryContext ctx, List<EntityKeyMapping> mappings) { |
248 | return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx)).collect( | 248 | return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx)).collect( |
249 | Collectors.joining(" AND ")); | 249 | Collectors.joining(" AND ")); |
250 | } | 250 | } |
@@ -357,11 +357,11 @@ public class EntityKeyMapping { | @@ -357,11 +357,11 @@ public class EntityKeyMapping { | ||
357 | return String.join(", ", attrValSelection, attrTsSelection); | 357 | return String.join(", ", attrValSelection, attrTsSelection); |
358 | } | 358 | } |
359 | 359 | ||
360 | - private String buildKeyQuery(EntityQueryContext ctx, String alias, KeyFilter keyFilter) { | 360 | + private String buildKeyQuery(QueryContext ctx, String alias, KeyFilter keyFilter) { |
361 | return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate()); | 361 | return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate()); |
362 | } | 362 | } |
363 | 363 | ||
364 | - private String buildPredicateQuery(EntityQueryContext ctx, String alias, EntityKey key, KeyFilterPredicate predicate) { | 364 | + private String buildPredicateQuery(QueryContext ctx, String alias, EntityKey key, KeyFilterPredicate predicate) { |
365 | if (predicate.getType().equals(FilterPredicateType.COMPLEX)) { | 365 | if (predicate.getType().equals(FilterPredicateType.COMPLEX)) { |
366 | return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate); | 366 | return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate); |
367 | } else { | 367 | } else { |
@@ -369,14 +369,14 @@ public class EntityKeyMapping { | @@ -369,14 +369,14 @@ public class EntityKeyMapping { | ||
369 | } | 369 | } |
370 | } | 370 | } |
371 | 371 | ||
372 | - private String buildComplexPredicateQuery(EntityQueryContext ctx, String alias, EntityKey key, ComplexFilterPredicate predicate) { | 372 | + private String buildComplexPredicateQuery(QueryContext ctx, String alias, EntityKey key, ComplexFilterPredicate predicate) { |
373 | return predicate.getPredicates().stream() | 373 | return predicate.getPredicates().stream() |
374 | .map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate)).collect(Collectors.joining( | 374 | .map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate)).collect(Collectors.joining( |
375 | " " + predicate.getOperation().name() + " " | 375 | " " + predicate.getOperation().name() + " " |
376 | )); | 376 | )); |
377 | } | 377 | } |
378 | 378 | ||
379 | - private String buildSimplePredicateQuery(EntityQueryContext ctx, String alias, EntityKey key, KeyFilterPredicate predicate) { | 379 | + private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key, KeyFilterPredicate predicate) { |
380 | if (predicate.getType().equals(FilterPredicateType.NUMERIC)) { | 380 | if (predicate.getType().equals(FilterPredicateType.NUMERIC)) { |
381 | if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) { | 381 | if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) { |
382 | String column = entityFieldColumnMap.get(key.getKey()); | 382 | String column = entityFieldColumnMap.get(key.getKey()); |
@@ -402,7 +402,7 @@ public class EntityKeyMapping { | @@ -402,7 +402,7 @@ public class EntityKeyMapping { | ||
402 | } | 402 | } |
403 | } | 403 | } |
404 | 404 | ||
405 | - private String buildStringPredicateQuery(EntityQueryContext ctx, String field, StringFilterPredicate stringFilterPredicate) { | 405 | + private String buildStringPredicateQuery(QueryContext ctx, String field, StringFilterPredicate stringFilterPredicate) { |
406 | String operationField = field; | 406 | String operationField = field; |
407 | String paramName = getNextParameterName(field); | 407 | String paramName = getNextParameterName(field); |
408 | String value = stringFilterPredicate.getValue(); | 408 | String value = stringFilterPredicate.getValue(); |
@@ -439,7 +439,7 @@ public class EntityKeyMapping { | @@ -439,7 +439,7 @@ public class EntityKeyMapping { | ||
439 | return String.format("(%s is not null and %s)", field, stringOperationQuery); | 439 | return String.format("(%s is not null and %s)", field, stringOperationQuery); |
440 | } | 440 | } |
441 | 441 | ||
442 | - private String buildNumericPredicateQuery(EntityQueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) { | 442 | + private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) { |
443 | String paramName = getNextParameterName(field); | 443 | String paramName = getNextParameterName(field); |
444 | ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue()); | 444 | ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue()); |
445 | String numericOperationQuery = ""; | 445 | String numericOperationQuery = ""; |
@@ -466,7 +466,7 @@ public class EntityKeyMapping { | @@ -466,7 +466,7 @@ public class EntityKeyMapping { | ||
466 | return String.format("(%s is not null and %s)", field, numericOperationQuery); | 466 | return String.format("(%s is not null and %s)", field, numericOperationQuery); |
467 | } | 467 | } |
468 | 468 | ||
469 | - private String buildBooleanPredicateQuery(EntityQueryContext ctx, String field, | 469 | + private String buildBooleanPredicateQuery(QueryContext ctx, String field, |
470 | BooleanFilterPredicate booleanFilterPredicate) { | 470 | BooleanFilterPredicate booleanFilterPredicate) { |
471 | String paramName = getNextParameterName(field); | 471 | String paramName = getNextParameterName(field); |
472 | ctx.addBooleanParameter(paramName, booleanFilterPredicate.isValue()); | 472 | ctx.addBooleanParameter(paramName, booleanFilterPredicate.isValue()); |
dao/src/main/java/org/thingsboard/server/dao/sql/query/QueryContext.java
renamed from
dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityQueryContext.java
@@ -24,13 +24,13 @@ import java.util.List; | @@ -24,13 +24,13 @@ import java.util.List; | ||
24 | import java.util.Map; | 24 | import java.util.Map; |
25 | import java.util.UUID; | 25 | import java.util.UUID; |
26 | 26 | ||
27 | -public class EntityQueryContext implements SqlParameterSource { | 27 | +public class QueryContext implements SqlParameterSource { |
28 | private static final PostgresUUIDType UUID_TYPE = new PostgresUUIDType(); | 28 | private static final PostgresUUIDType UUID_TYPE = new PostgresUUIDType(); |
29 | 29 | ||
30 | private final StringBuilder query; | 30 | private final StringBuilder query; |
31 | private final Map<String, Parameter> params; | 31 | private final Map<String, Parameter> params; |
32 | 32 | ||
33 | - public EntityQueryContext() { | 33 | + public QueryContext() { |
34 | query = new StringBuilder(); | 34 | query = new StringBuilder(); |
35 | params = new HashMap<>(); | 35 | params = new HashMap<>(); |
36 | } | 36 | } |
@@ -91,6 +91,10 @@ public class EntityQueryContext implements SqlParameterSource { | @@ -91,6 +91,10 @@ public class EntityQueryContext implements SqlParameterSource { | ||
91 | addParameter(name, value, Types.DOUBLE, "DOUBLE"); | 91 | addParameter(name, value, Types.DOUBLE, "DOUBLE"); |
92 | } | 92 | } |
93 | 93 | ||
94 | + public void addLongParameter(String name, long value) { | ||
95 | + addParameter(name, value, Types.BIGINT, "BIGINT"); | ||
96 | + } | ||
97 | + | ||
94 | public void addStringListParameter(String name, List<String> value) { | 98 | public void addStringListParameter(String name, List<String> value) { |
95 | addParameter(name, value, Types.VARCHAR, "VARCHAR"); | 99 | addParameter(name, value, Types.VARCHAR, "VARCHAR"); |
96 | } | 100 | } |
@@ -24,16 +24,26 @@ import org.thingsboard.server.common.data.Tenant; | @@ -24,16 +24,26 @@ import org.thingsboard.server.common.data.Tenant; | ||
24 | import org.thingsboard.server.common.data.alarm.Alarm; | 24 | import org.thingsboard.server.common.data.alarm.Alarm; |
25 | import org.thingsboard.server.common.data.alarm.AlarmInfo; | 25 | import org.thingsboard.server.common.data.alarm.AlarmInfo; |
26 | import org.thingsboard.server.common.data.alarm.AlarmQuery; | 26 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
27 | +import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; | ||
27 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 28 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
28 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 29 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
29 | import org.thingsboard.server.common.data.id.AssetId; | 30 | import org.thingsboard.server.common.data.id.AssetId; |
31 | +import org.thingsboard.server.common.data.id.CustomerId; | ||
30 | import org.thingsboard.server.common.data.id.TenantId; | 32 | import org.thingsboard.server.common.data.id.TenantId; |
31 | import org.thingsboard.server.common.data.page.PageData; | 33 | import org.thingsboard.server.common.data.page.PageData; |
32 | import org.thingsboard.server.common.data.page.SortOrder; | 34 | import org.thingsboard.server.common.data.page.SortOrder; |
33 | import org.thingsboard.server.common.data.page.TimePageLink; | 35 | import org.thingsboard.server.common.data.page.TimePageLink; |
36 | +import org.thingsboard.server.common.data.query.AlarmData; | ||
37 | +import org.thingsboard.server.common.data.query.AlarmDataPageLink; | ||
38 | +import org.thingsboard.server.common.data.query.AlarmDataQuery; | ||
39 | +import org.thingsboard.server.common.data.query.EntityDataSortOrder; | ||
40 | +import org.thingsboard.server.common.data.query.EntityKey; | ||
41 | +import org.thingsboard.server.common.data.query.EntityKeyType; | ||
34 | import org.thingsboard.server.common.data.relation.EntityRelation; | 42 | import org.thingsboard.server.common.data.relation.EntityRelation; |
35 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; | 43 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
36 | 44 | ||
45 | +import java.util.Arrays; | ||
46 | +import java.util.Collections; | ||
37 | import java.util.List; | 47 | import java.util.List; |
38 | import java.util.concurrent.ExecutionException; | 48 | import java.util.concurrent.ExecutionException; |
39 | 49 | ||
@@ -196,6 +206,128 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { | @@ -196,6 +206,128 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest { | ||
196 | } | 206 | } |
197 | 207 | ||
198 | @Test | 208 | @Test |
209 | + public void testFindAlarmUsingAlarmDataQuery() throws ExecutionException, InterruptedException { | ||
210 | + AssetId parentId = new AssetId(Uuids.timeBased()); | ||
211 | + AssetId childId = new AssetId(Uuids.timeBased()); | ||
212 | + | ||
213 | + EntityRelation relation = new EntityRelation(parentId, childId, EntityRelation.CONTAINS_TYPE); | ||
214 | + | ||
215 | + Assert.assertTrue(relationService.saveRelationAsync(tenantId, relation).get()); | ||
216 | + | ||
217 | + long ts = System.currentTimeMillis(); | ||
218 | + Alarm alarm = Alarm.builder().tenantId(tenantId).originator(childId) | ||
219 | + .type(TEST_ALARM) | ||
220 | + .propagate(false) | ||
221 | + .severity(AlarmSeverity.CRITICAL) | ||
222 | + .status(AlarmStatus.ACTIVE_UNACK) | ||
223 | + .startTs(ts).build(); | ||
224 | + | ||
225 | + Alarm created = alarmService.createOrUpdateAlarm(alarm); | ||
226 | + | ||
227 | + AlarmDataPageLink pageLink = new AlarmDataPageLink(); | ||
228 | + pageLink.setPage(0); | ||
229 | + pageLink.setPageSize(1); | ||
230 | + pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime"))); | ||
231 | + | ||
232 | + pageLink.setStartTs(0L); | ||
233 | + pageLink.setEndTs(System.currentTimeMillis()); | ||
234 | + pageLink.setSearchPropagatedAlarms(false); | ||
235 | + pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); | ||
236 | + pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); | ||
237 | + | ||
238 | + PageData<AlarmData> alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(childId)); | ||
239 | + | ||
240 | + Assert.assertNotNull(alarms.getData()); | ||
241 | + Assert.assertEquals(1, alarms.getData().size()); | ||
242 | + Assert.assertEquals(created, alarms.getData().get(0)); | ||
243 | + | ||
244 | + pageLink.setPage(0); | ||
245 | + pageLink.setPageSize(1); | ||
246 | + pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime"))); | ||
247 | + | ||
248 | + pageLink.setStartTs(0L); | ||
249 | + pageLink.setEndTs(System.currentTimeMillis()); | ||
250 | + pageLink.setSearchPropagatedAlarms(false); | ||
251 | + pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); | ||
252 | + pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); | ||
253 | + | ||
254 | + alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(childId)); | ||
255 | + Assert.assertNotNull(alarms.getData()); | ||
256 | + Assert.assertEquals(1, alarms.getData().size()); | ||
257 | + Assert.assertEquals(created, alarms.getData().get(0)); | ||
258 | + | ||
259 | + // Check child relation | ||
260 | + Assert.assertNotNull(alarms.getData()); | ||
261 | + Assert.assertEquals(1, alarms.getData().size()); | ||
262 | + Assert.assertEquals(created, new Alarm(alarms.getData().get(0))); | ||
263 | + | ||
264 | + created.setPropagate(true); | ||
265 | + created = alarmService.createOrUpdateAlarm(created); | ||
266 | + | ||
267 | + // Check child relation | ||
268 | + pageLink.setPage(0); | ||
269 | + pageLink.setPageSize(1); | ||
270 | + pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime"))); | ||
271 | + | ||
272 | + pageLink.setStartTs(0L); | ||
273 | + pageLink.setEndTs(System.currentTimeMillis()); | ||
274 | + pageLink.setSearchPropagatedAlarms(true); | ||
275 | + pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); | ||
276 | + pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); | ||
277 | + | ||
278 | + alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(childId)); | ||
279 | + | ||
280 | + // Check parent relation | ||
281 | + pageLink.setPage(0); | ||
282 | + pageLink.setPageSize(1); | ||
283 | + pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime"))); | ||
284 | + | ||
285 | + pageLink.setStartTs(0L); | ||
286 | + pageLink.setEndTs(System.currentTimeMillis()); | ||
287 | + pageLink.setSearchPropagatedAlarms(true); | ||
288 | + pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); | ||
289 | + pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); | ||
290 | + | ||
291 | + alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(parentId)); | ||
292 | + Assert.assertNotNull(alarms.getData()); | ||
293 | + Assert.assertEquals(1, alarms.getData().size()); | ||
294 | + Assert.assertEquals(created, alarms.getData().get(0)); | ||
295 | + | ||
296 | + pageLink.setPage(0); | ||
297 | + pageLink.setPageSize(1); | ||
298 | + pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime"))); | ||
299 | + | ||
300 | + pageLink.setStartTs(0L); | ||
301 | + pageLink.setEndTs(System.currentTimeMillis()); | ||
302 | + pageLink.setSearchPropagatedAlarms(true); | ||
303 | + pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); | ||
304 | + pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); | ||
305 | + | ||
306 | + alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(parentId)); | ||
307 | + Assert.assertNotNull(alarms.getData()); | ||
308 | + Assert.assertEquals(1, alarms.getData().size()); | ||
309 | + Assert.assertEquals(created, alarms.getData().get(0)); | ||
310 | + | ||
311 | + alarmService.ackAlarm(tenantId, created.getId(), System.currentTimeMillis()).get(); | ||
312 | + created = alarmService.findAlarmByIdAsync(tenantId, created.getId()).get(); | ||
313 | + | ||
314 | + pageLink.setPage(0); | ||
315 | + pageLink.setPageSize(1); | ||
316 | + pageLink.setSortOrder(new EntityDataSortOrder(new EntityKey(EntityKeyType.ALARM_FIELD, "createdTime"))); | ||
317 | + | ||
318 | + pageLink.setStartTs(0L); | ||
319 | + pageLink.setEndTs(System.currentTimeMillis()); | ||
320 | + pageLink.setSearchPropagatedAlarms(true); | ||
321 | + pageLink.setSeverityList(Arrays.asList(AlarmSeverity.CRITICAL, AlarmSeverity.WARNING)); | ||
322 | + pageLink.setStatusList(Arrays.asList(AlarmSearchStatus.ACTIVE)); | ||
323 | + | ||
324 | + alarms = alarmService.findAlarmDataByQueryForEntities(tenantId, new CustomerId(CustomerId.NULL_UUID), pageLink, Collections.singletonList(childId)); | ||
325 | + Assert.assertNotNull(alarms.getData()); | ||
326 | + Assert.assertEquals(1, alarms.getData().size()); | ||
327 | + Assert.assertEquals(created, alarms.getData().get(0)); | ||
328 | + } | ||
329 | + | ||
330 | + @Test | ||
199 | public void testDeleteAlarm() throws ExecutionException, InterruptedException { | 331 | public void testDeleteAlarm() throws ExecutionException, InterruptedException { |
200 | AssetId parentId = new AssetId(Uuids.timeBased()); | 332 | AssetId parentId = new AssetId(Uuids.timeBased()); |
201 | AssetId childId = new AssetId(Uuids.timeBased()); | 333 | AssetId childId = new AssetId(Uuids.timeBased()); |
@@ -8997,10 +8997,10 @@ | @@ -8997,10 +8997,10 @@ | ||
8997 | "integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw==" | 8997 | "integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw==" |
8998 | }, | 8998 | }, |
8999 | "ngx-flowchart": { | 8999 | "ngx-flowchart": { |
9000 | - "version": "git://github.com/thingsboard/ngx-flowchart.git#7a02f4748b5e7821a883c903107af5f20415d026", | 9000 | + "version": "git://github.com/thingsboard/ngx-flowchart.git#a4157b0eef2eb3646ef920447c7b06b39d54f87f", |
9001 | "from": "git://github.com/thingsboard/ngx-flowchart.git#master", | 9001 | "from": "git://github.com/thingsboard/ngx-flowchart.git#master", |
9002 | "requires": { | 9002 | "requires": { |
9003 | - "tslib": "^1.13.0" | 9003 | + "tslib": "^1.10.0" |
9004 | }, | 9004 | }, |
9005 | "dependencies": { | 9005 | "dependencies": { |
9006 | "tslib": { | 9006 | "tslib": { |