Commit dfb82bf28fb13ed7cf590eb37366487e7a6a80da
1 parent
f63b4b1f
findEntityTimeseriesAndAttributesKeysByQuery improvements
Showing
3 changed files
with
61 additions
and
63 deletions
... | ... | @@ -45,6 +45,8 @@ public class EntityQueryController extends BaseController { |
45 | 45 | @Autowired |
46 | 46 | private EntityQueryService entityQueryService; |
47 | 47 | |
48 | + private static final int MAX_PAGE_SIZE = 100; | |
49 | + | |
48 | 50 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
49 | 51 | @RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST) |
50 | 52 | @ResponseBody |
... | ... | @@ -91,12 +93,10 @@ public class EntityQueryController extends BaseController { |
91 | 93 | checkNotNull(query); |
92 | 94 | try { |
93 | 95 | EntityDataPageLink pageLink = query.getPageLink(); |
94 | - if (pageLink.getPageSize() > 100) { | |
95 | - pageLink.setPageSize(100); | |
96 | + if (pageLink.getPageSize() > MAX_PAGE_SIZE) { | |
97 | + pageLink.setPageSize(MAX_PAGE_SIZE); | |
96 | 98 | } |
97 | - DeferredResult<ResponseEntity> response = new DeferredResult<>(); | |
98 | - entityQueryService.getKeysByQueryCallback(getCurrentUser(), tenantId, query, isTimeseries, isAttributes, response); | |
99 | - return response; | |
99 | + return entityQueryService.getKeysByQuery(getCurrentUser(), tenantId, query, isTimeseries, isAttributes); | |
100 | 100 | } catch (Exception e) { |
101 | 101 | throw handleException(e); |
102 | 102 | } | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.query; |
17 | 17 | |
18 | -import com.datastax.oss.driver.internal.core.util.CollectionsUtils; | |
19 | 18 | import com.fasterxml.jackson.databind.node.ArrayNode; |
20 | 19 | import com.fasterxml.jackson.databind.node.ObjectNode; |
21 | 20 | import com.google.common.util.concurrent.FutureCallback; |
... | ... | @@ -61,6 +60,7 @@ import java.util.LinkedHashMap; |
61 | 60 | import java.util.List; |
62 | 61 | import java.util.Map; |
63 | 62 | import java.util.Set; |
63 | +import java.util.function.Consumer; | |
64 | 64 | import java.util.stream.Collectors; |
65 | 65 | |
66 | 66 | @Service |
... | ... | @@ -123,25 +123,38 @@ public class DefaultEntityQueryService implements EntityQueryService { |
123 | 123 | } |
124 | 124 | } |
125 | 125 | |
126 | + private EntityDataQuery buildEntityDataQuery(AlarmDataQuery query) { | |
127 | + EntityDataSortOrder sortOrder = query.getPageLink().getSortOrder(); | |
128 | + EntityDataSortOrder entitiesSortOrder; | |
129 | + if (sortOrder == null || sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { | |
130 | + entitiesSortOrder = new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, ModelConstants.CREATED_TIME_PROPERTY)); | |
131 | + } else { | |
132 | + entitiesSortOrder = sortOrder; | |
133 | + } | |
134 | + EntityDataPageLink edpl = new EntityDataPageLink(maxEntitiesPerAlarmSubscription, 0, null, entitiesSortOrder); | |
135 | + return new EntityDataQuery(query.getEntityFilter(), edpl, query.getEntityFields(), query.getLatestValues(), query.getKeyFilters()); | |
136 | + } | |
137 | + | |
126 | 138 | @Override |
127 | - public void getKeysByQueryCallback(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, | |
128 | - boolean isTimeseries, boolean isAttributes, DeferredResult<ResponseEntity> response) { | |
139 | + public DeferredResult<ResponseEntity> getKeysByQuery(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, | |
140 | + boolean isTimeseries, boolean isAttributes) { | |
141 | + final DeferredResult<ResponseEntity> response = new DeferredResult<>(); | |
129 | 142 | if (!isAttributes && !isTimeseries) { |
130 | - getEmptyResponseCallback(response); | |
131 | - return; | |
143 | + replyWithEmptyResponse(response); | |
144 | + return response; | |
132 | 145 | } |
133 | 146 | |
134 | 147 | List<EntityId> ids = this.findEntityDataByQuery(securityUser, query).getData().stream() |
135 | 148 | .map(EntityData::getEntityId) |
136 | 149 | .collect(Collectors.toList()); |
137 | 150 | if (ids.isEmpty()) { |
138 | - getEmptyResponseCallback(response); | |
139 | - return; | |
151 | + replyWithEmptyResponse(response); | |
152 | + return response; | |
140 | 153 | } |
141 | 154 | |
142 | 155 | Set<EntityType> types = ids.stream().map(EntityId::getEntityType).collect(Collectors.toSet()); |
143 | - ListenableFuture<List<String>> timeseriesKeysFuture; | |
144 | - ListenableFuture<List<String>> attributesKeysFuture; | |
156 | + final ListenableFuture<List<String>> timeseriesKeysFuture; | |
157 | + final ListenableFuture<List<String>> attributesKeysFuture; | |
145 | 158 | |
146 | 159 | if (isTimeseries) { |
147 | 160 | timeseriesKeysFuture = dbCallbackExecutor.submit(() -> timeseriesService.findAllKeysByEntityIds(tenantId, ids)); |
... | ... | @@ -155,67 +168,49 @@ public class DefaultEntityQueryService implements EntityQueryService { |
155 | 168 | typesMap.forEach((type, entityIds) -> futures.add(dbCallbackExecutor.submit(() -> attributesService.findAllKeysByEntityIds(tenantId, type, entityIds)))); |
156 | 169 | attributesKeysFuture = Futures.transform(Futures.allAsList(futures), lists -> { |
157 | 170 | if (CollectionUtils.isEmpty(lists)) { |
158 | - return null; | |
171 | + return Collections.emptyList(); | |
159 | 172 | } |
160 | - | |
161 | 173 | return lists.stream().flatMap(List::stream).distinct().sorted().collect(Collectors.toList()); |
162 | 174 | }, dbCallbackExecutor); |
163 | 175 | } else { |
164 | 176 | attributesKeysFuture = null; |
165 | 177 | } |
166 | 178 | |
167 | - if (timeseriesKeysFuture != null && attributesKeysFuture != null) { | |
168 | - Futures.whenAllComplete(timeseriesKeysFuture, attributesKeysFuture).call(() -> { | |
179 | + if (isTimeseries && isAttributes) { | |
180 | + Futures.whenAllComplete(timeseriesKeysFuture, attributesKeysFuture).run(() -> { | |
169 | 181 | try { |
170 | - getResponseCallback(response, types, timeseriesKeysFuture.get(), attributesKeysFuture.get()); | |
182 | + replyWithResponse(response, types, timeseriesKeysFuture.get(), attributesKeysFuture.get()); | |
171 | 183 | } catch (Exception e) { |
172 | 184 | log.error("Failed to fetch timeseries and attributes keys!", e); |
173 | 185 | AccessValidator.handleError(e, response, HttpStatus.INTERNAL_SERVER_ERROR); |
174 | 186 | } |
175 | - | |
176 | - return null; | |
177 | - }, dbCallbackExecutor); | |
178 | - } else if (timeseriesKeysFuture != null) { | |
179 | - Futures.addCallback(timeseriesKeysFuture, new FutureCallback<List<String>>() { | |
180 | - @Override | |
181 | - public void onSuccess(@Nullable List<String> keys) { | |
182 | - getResponseCallback(response, types, keys, null); | |
183 | - } | |
184 | - | |
185 | - @Override | |
186 | - public void onFailure(Throwable t) { | |
187 | - log.error("Failed to fetch timeseries keys!", t); | |
188 | - AccessValidator.handleError(t, response, HttpStatus.INTERNAL_SERVER_ERROR); | |
189 | - } | |
190 | - | |
191 | 187 | }, dbCallbackExecutor); |
188 | + } else if (isTimeseries) { | |
189 | + addCallback(timeseriesKeysFuture, keys -> replyWithResponse(response, types, keys, null), | |
190 | + error -> { | |
191 | + log.error("Failed to fetch timeseries keys!", error); | |
192 | + AccessValidator.handleError(error, response, HttpStatus.INTERNAL_SERVER_ERROR); | |
193 | + }); | |
192 | 194 | } else { |
193 | - Futures.addCallback(attributesKeysFuture, new FutureCallback<List<String>>() { | |
194 | - @Override | |
195 | - public void onSuccess(@Nullable List<String> keys) { | |
196 | - getResponseCallback(response, types, null, keys); | |
197 | - } | |
198 | - | |
199 | - @Override | |
200 | - public void onFailure(Throwable t) { | |
201 | - log.error("Failed to fetch attributes keys!", t); | |
202 | - AccessValidator.handleError(t, response, HttpStatus.INTERNAL_SERVER_ERROR); | |
203 | - } | |
204 | - }, dbCallbackExecutor); | |
195 | + addCallback(attributesKeysFuture, keys -> replyWithResponse(response, types, null, keys), | |
196 | + error -> { | |
197 | + log.error("Failed to fetch attributes keys!", error); | |
198 | + AccessValidator.handleError(error, response, HttpStatus.INTERNAL_SERVER_ERROR); | |
199 | + }); | |
205 | 200 | } |
201 | + return response; | |
206 | 202 | } |
207 | 203 | |
208 | - private void getResponseCallback(DeferredResult<ResponseEntity> response, Set<EntityType> types, List<String> timeseriesKeys, List<String> attributesKeys) { | |
204 | + private void replyWithResponse(DeferredResult<ResponseEntity> response, Set<EntityType> types, List<String> timeseriesKeys, List<String> attributesKeys) { | |
209 | 205 | ObjectNode json = JacksonUtil.newObjectNode(); |
210 | 206 | addItemsToArrayNode(json.putArray("types"), types); |
211 | 207 | addItemsToArrayNode(json.putArray("timeseriesKeys"), timeseriesKeys); |
212 | 208 | addItemsToArrayNode(json.putArray("attributesKeys"), attributesKeys); |
213 | - | |
214 | 209 | response.setResult(new ResponseEntity(json, HttpStatus.OK)); |
215 | 210 | } |
216 | 211 | |
217 | - private void getEmptyResponseCallback(DeferredResult<ResponseEntity> response) { | |
218 | - getResponseCallback(response, null, null, null); | |
212 | + private void replyWithEmptyResponse(DeferredResult<ResponseEntity> response) { | |
213 | + replyWithResponse(response, Collections.emptySet(), Collections.emptyList(), Collections.emptyList()); | |
219 | 214 | } |
220 | 215 | |
221 | 216 | private void addItemsToArrayNode(ArrayNode arrayNode, Collection<?> collection) { |
... | ... | @@ -224,15 +219,18 @@ public class DefaultEntityQueryService implements EntityQueryService { |
224 | 219 | } |
225 | 220 | } |
226 | 221 | |
227 | - private EntityDataQuery buildEntityDataQuery(AlarmDataQuery query) { | |
228 | - EntityDataSortOrder sortOrder = query.getPageLink().getSortOrder(); | |
229 | - EntityDataSortOrder entitiesSortOrder; | |
230 | - if (sortOrder == null || sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { | |
231 | - entitiesSortOrder = new EntityDataSortOrder(new EntityKey(EntityKeyType.ENTITY_FIELD, ModelConstants.CREATED_TIME_PROPERTY)); | |
232 | - } else { | |
233 | - entitiesSortOrder = sortOrder; | |
234 | - } | |
235 | - EntityDataPageLink edpl = new EntityDataPageLink(maxEntitiesPerAlarmSubscription, 0, null, entitiesSortOrder); | |
236 | - return new EntityDataQuery(query.getEntityFilter(), edpl, query.getEntityFields(), query.getLatestValues(), query.getKeyFilters()); | |
222 | + private void addCallback(ListenableFuture<List<String>> future, Consumer<List<String>> success, Consumer<Throwable> error) { | |
223 | + Futures.addCallback(future, new FutureCallback<List<String>>() { | |
224 | + @Override | |
225 | + public void onSuccess(@Nullable List<String> keys) { | |
226 | + success.accept(keys); | |
227 | + } | |
228 | + | |
229 | + @Override | |
230 | + public void onFailure(Throwable t) { | |
231 | + error.accept(t); | |
232 | + } | |
233 | + }, dbCallbackExecutor); | |
237 | 234 | } |
235 | + | |
238 | 236 | } | ... | ... |
... | ... | @@ -34,7 +34,7 @@ public interface EntityQueryService { |
34 | 34 | |
35 | 35 | PageData<AlarmData> findAlarmDataByQuery(SecurityUser securityUser, AlarmDataQuery query); |
36 | 36 | |
37 | - void getKeysByQueryCallback(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, | |
38 | - boolean isTimeseries, boolean isAttributes, DeferredResult<ResponseEntity> response); | |
37 | + DeferredResult<ResponseEntity> getKeysByQuery(SecurityUser securityUser, TenantId tenantId, EntityDataQuery query, | |
38 | + boolean isTimeseries, boolean isAttributes); | |
39 | 39 | |
40 | 40 | } | ... | ... |