fix unresolved dynamic values in queryService on api request
This commit is contained in:
		
							parent
							
								
									0266a9703c
								
							
						
					
					
						commit
						6b5966a579
					
				@ -29,12 +29,16 @@ import org.springframework.http.ResponseEntity;
 | 
				
			|||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
import org.springframework.util.CollectionUtils;
 | 
					import org.springframework.util.CollectionUtils;
 | 
				
			||||||
import org.springframework.web.context.request.async.DeferredResult;
 | 
					import org.springframework.web.context.request.async.DeferredResult;
 | 
				
			||||||
 | 
					import org.thingsboard.common.util.KvUtil;
 | 
				
			||||||
import org.thingsboard.server.common.data.EntityType;
 | 
					import org.thingsboard.server.common.data.EntityType;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
					import org.thingsboard.server.common.data.id.EntityId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					import org.thingsboard.server.common.data.id.TenantId;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.kv.AttributeKvEntry;
 | 
				
			||||||
import org.thingsboard.server.common.data.page.PageData;
 | 
					import org.thingsboard.server.common.data.page.PageData;
 | 
				
			||||||
import org.thingsboard.server.common.data.query.AlarmData;
 | 
					import org.thingsboard.server.common.data.query.AlarmData;
 | 
				
			||||||
import org.thingsboard.server.common.data.query.AlarmDataQuery;
 | 
					import org.thingsboard.server.common.data.query.AlarmDataQuery;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.query.ComplexFilterPredicate;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.query.DynamicValue;
 | 
				
			||||||
import org.thingsboard.server.common.data.query.EntityCountQuery;
 | 
					import org.thingsboard.server.common.data.query.EntityCountQuery;
 | 
				
			||||||
import org.thingsboard.server.common.data.query.EntityData;
 | 
					import org.thingsboard.server.common.data.query.EntityData;
 | 
				
			||||||
import org.thingsboard.server.common.data.query.EntityDataPageLink;
 | 
					import org.thingsboard.server.common.data.query.EntityDataPageLink;
 | 
				
			||||||
@ -42,6 +46,10 @@ import org.thingsboard.server.common.data.query.EntityDataQuery;
 | 
				
			|||||||
import org.thingsboard.server.common.data.query.EntityDataSortOrder;
 | 
					import org.thingsboard.server.common.data.query.EntityDataSortOrder;
 | 
				
			||||||
import org.thingsboard.server.common.data.query.EntityKey;
 | 
					import org.thingsboard.server.common.data.query.EntityKey;
 | 
				
			||||||
import org.thingsboard.server.common.data.query.EntityKeyType;
 | 
					import org.thingsboard.server.common.data.query.EntityKeyType;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.query.FilterPredicateType;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.query.KeyFilter;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.query.KeyFilterPredicate;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.query.SimpleKeyFilterPredicate;
 | 
				
			||||||
import org.thingsboard.server.dao.alarm.AlarmService;
 | 
					import org.thingsboard.server.dao.alarm.AlarmService;
 | 
				
			||||||
import org.thingsboard.server.dao.attributes.AttributesService;
 | 
					import org.thingsboard.server.dao.attributes.AttributesService;
 | 
				
			||||||
import org.thingsboard.server.dao.entity.EntityService;
 | 
					import org.thingsboard.server.dao.entity.EntityService;
 | 
				
			||||||
@ -52,6 +60,7 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
 | 
				
			|||||||
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
 | 
					import org.thingsboard.server.service.executors.DbCallbackExecutorService;
 | 
				
			||||||
import org.thingsboard.server.service.security.AccessValidator;
 | 
					import org.thingsboard.server.service.security.AccessValidator;
 | 
				
			||||||
import org.thingsboard.server.service.security.model.SecurityUser;
 | 
					import org.thingsboard.server.service.security.model.SecurityUser;
 | 
				
			||||||
 | 
					import org.thingsboard.server.service.subscription.TbAttributeSubscriptionScope;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
@ -59,7 +68,9 @@ import java.util.Collections;
 | 
				
			|||||||
import java.util.LinkedHashMap;
 | 
					import java.util.LinkedHashMap;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.Optional;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					import java.util.concurrent.ExecutionException;
 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
import java.util.stream.Collectors;
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,9 +104,81 @@ public class DefaultEntityQueryService implements EntityQueryService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public PageData<EntityData> findEntityDataByQuery(SecurityUser securityUser, EntityDataQuery query) {
 | 
					    public PageData<EntityData> findEntityDataByQuery(SecurityUser securityUser, EntityDataQuery query) {
 | 
				
			||||||
 | 
					        if (query.getKeyFilters() != null) {
 | 
				
			||||||
 | 
					            resolveDynamicValuesInPredicates(
 | 
				
			||||||
 | 
					                    query.getKeyFilters().stream()
 | 
				
			||||||
 | 
					                            .map(KeyFilter::getPredicate)
 | 
				
			||||||
 | 
					                            .collect(Collectors.toList()),
 | 
				
			||||||
 | 
					                    securityUser
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return entityService.findEntityDataByQuery(securityUser.getTenantId(), securityUser.getCustomerId(), query);
 | 
					        return entityService.findEntityDataByQuery(securityUser.getTenantId(), securityUser.getCustomerId(), query);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void resolveDynamicValuesInPredicates(List<KeyFilterPredicate> predicates, SecurityUser user) {
 | 
				
			||||||
 | 
					        predicates.forEach(predicate -> {
 | 
				
			||||||
 | 
					            if (predicate.getType() == FilterPredicateType.COMPLEX) {
 | 
				
			||||||
 | 
					                resolveDynamicValuesInPredicates(
 | 
				
			||||||
 | 
					                        ((ComplexFilterPredicate) predicate).getPredicates(),
 | 
				
			||||||
 | 
					                        user
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                setResolvedValue(user, (SimpleKeyFilterPredicate<?>) predicate);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void setResolvedValue(SecurityUser user, SimpleKeyFilterPredicate<?> predicate) {
 | 
				
			||||||
 | 
					        DynamicValue<?> dynamicValue = predicate.getValue().getDynamicValue();
 | 
				
			||||||
 | 
					        if (dynamicValue != null && dynamicValue.getResolvedValue() == null) {
 | 
				
			||||||
 | 
					            resolveDynamicValue(dynamicValue, user, predicate.getType());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private <T> void resolveDynamicValue(DynamicValue<T> dynamicValue, SecurityUser user, FilterPredicateType predicateType) {
 | 
				
			||||||
 | 
					        EntityId entityId;
 | 
				
			||||||
 | 
					        switch (dynamicValue.getSourceType()) {
 | 
				
			||||||
 | 
					            case CURRENT_TENANT:
 | 
				
			||||||
 | 
					                entityId = user.getTenantId();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case CURRENT_CUSTOMER:
 | 
				
			||||||
 | 
					                entityId = user.getCustomerId();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case CURRENT_USER:
 | 
				
			||||||
 | 
					                entityId = user.getId();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                throw new RuntimeException("Not supported operation for source type: {" + dynamicValue.getSourceType() + "}");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Optional<AttributeKvEntry> valueOpt = attributesService.find(user.getTenantId(), entityId,
 | 
				
			||||||
 | 
					                    TbAttributeSubscriptionScope.SERVER_SCOPE.name(), dynamicValue.getSourceAttribute()).get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (valueOpt.isPresent()) {
 | 
				
			||||||
 | 
					                AttributeKvEntry entry = valueOpt.get();
 | 
				
			||||||
 | 
					                Object resolved = null;
 | 
				
			||||||
 | 
					                switch (predicateType) {
 | 
				
			||||||
 | 
					                    case STRING:
 | 
				
			||||||
 | 
					                        resolved = KvUtil.getStringValue(entry);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case NUMERIC:
 | 
				
			||||||
 | 
					                        resolved = KvUtil.getDoubleValue(entry);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case BOOLEAN:
 | 
				
			||||||
 | 
					                        resolved = KvUtil.getBoolValue(entry);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    case COMPLEX:
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dynamicValue.setResolvedValue((T) resolved);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (InterruptedException | ExecutionException e) {
 | 
				
			||||||
 | 
					            throw new RuntimeException(e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public PageData<AlarmData> findAlarmDataByQuery(SecurityUser securityUser, AlarmDataQuery query) {
 | 
					    public PageData<AlarmData> findAlarmDataByQuery(SecurityUser securityUser, AlarmDataQuery query) {
 | 
				
			||||||
        EntityDataQuery entityDataQuery = this.buildEntityDataQuery(query);
 | 
					        EntityDataQuery entityDataQuery = this.buildEntityDataQuery(query);
 | 
				
			||||||
 | 
				
			|||||||
@ -84,6 +84,10 @@
 | 
				
			|||||||
            <artifactId>awaitility</artifactId>
 | 
					            <artifactId>awaitility</artifactId>
 | 
				
			||||||
            <scope>test</scope>
 | 
					            <scope>test</scope>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.thingsboard.common</groupId>
 | 
				
			||||||
 | 
					            <artifactId>data</artifactId>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
    </dependencies>
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <build>
 | 
					    <build>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copyright © 2016-2022 The Thingsboard Authors
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package org.thingsboard.common.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.kv.KvEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class KvUtil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static String getStringValue(KvEntry entry) {
 | 
				
			||||||
 | 
					        switch (entry.getDataType()) {
 | 
				
			||||||
 | 
					            case LONG:
 | 
				
			||||||
 | 
					                return entry.getLongValue().map(String::valueOf).orElse(null);
 | 
				
			||||||
 | 
					            case DOUBLE:
 | 
				
			||||||
 | 
					                return entry.getDoubleValue().map(String::valueOf).orElse(null);
 | 
				
			||||||
 | 
					            case BOOLEAN:
 | 
				
			||||||
 | 
					                return entry.getBooleanValue().map(String::valueOf).orElse(null);
 | 
				
			||||||
 | 
					            case STRING:
 | 
				
			||||||
 | 
					                return entry.getStrValue().orElse("");
 | 
				
			||||||
 | 
					            case JSON:
 | 
				
			||||||
 | 
					                return entry.getJsonValue().orElse("");
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static Double getDoubleValue(KvEntry entry) {
 | 
				
			||||||
 | 
					        switch (entry.getDataType()) {
 | 
				
			||||||
 | 
					            case LONG:
 | 
				
			||||||
 | 
					                return entry.getLongValue().map(Long::doubleValue).orElse(null);
 | 
				
			||||||
 | 
					            case DOUBLE:
 | 
				
			||||||
 | 
					                return entry.getDoubleValue().orElse(null);
 | 
				
			||||||
 | 
					            case BOOLEAN:
 | 
				
			||||||
 | 
					                return entry.getBooleanValue().map(e -> e ? 1.0 : 0).orElse(null);
 | 
				
			||||||
 | 
					            case STRING:
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    return Double.parseDouble(entry.getStrValue().orElse(""));
 | 
				
			||||||
 | 
					                } catch (RuntimeException e) {
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case JSON:
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    return Double.parseDouble(entry.getJsonValue().orElse(""));
 | 
				
			||||||
 | 
					                } catch (RuntimeException e) {
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static Boolean getBoolValue(KvEntry entry) {
 | 
				
			||||||
 | 
					        switch (entry.getDataType()) {
 | 
				
			||||||
 | 
					            case LONG:
 | 
				
			||||||
 | 
					                return entry.getLongValue().map(e -> e != 0).orElse(null);
 | 
				
			||||||
 | 
					            case DOUBLE:
 | 
				
			||||||
 | 
					                return entry.getDoubleValue().map(e -> e != 0).orElse(null);
 | 
				
			||||||
 | 
					            case BOOLEAN:
 | 
				
			||||||
 | 
					                return entry.getBooleanValue().orElse(null);
 | 
				
			||||||
 | 
					            case STRING:
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    return Boolean.parseBoolean(entry.getStrValue().orElse(""));
 | 
				
			||||||
 | 
					                } catch (RuntimeException e) {
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            case JSON:
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    return Boolean.parseBoolean(entry.getJsonValue().orElse(""));
 | 
				
			||||||
 | 
					                } catch (RuntimeException e) {
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user