Commit dfb82bf28fb13ed7cf590eb37366487e7a6a80da

Authored by YevhenBondarenko
1 parent f63b4b1f

findEntityTimeseriesAndAttributesKeysByQuery improvements

... ... @@ -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 }
... ...