Added support to use only one zone type instead of two + minor validation fixes
This commit is contained in:
		
							parent
							
								
									82cca8c665
								
							
						
					
					
						commit
						ede9fd5e05
					
				@ -18,6 +18,7 @@ package org.thingsboard.server.service.cf.ctx.state;
 | 
				
			|||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
 | 
					import com.fasterxml.jackson.databind.node.ObjectNode;
 | 
				
			||||||
import com.google.common.util.concurrent.Futures;
 | 
					import com.google.common.util.concurrent.Futures;
 | 
				
			||||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
					import com.google.common.util.concurrent.ListenableFuture;
 | 
				
			||||||
 | 
					import lombok.AllArgsConstructor;
 | 
				
			||||||
import lombok.Data;
 | 
					import lombok.Data;
 | 
				
			||||||
import org.thingsboard.common.util.JacksonUtil;
 | 
					import org.thingsboard.common.util.JacksonUtil;
 | 
				
			||||||
import org.thingsboard.common.util.geo.Coordinates;
 | 
					import org.thingsboard.common.util.geo.Coordinates;
 | 
				
			||||||
@ -31,12 +32,13 @@ import java.util.HashMap;
 | 
				
			|||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.ALLOWED_ZONES_ARGUMENT_KEY;
 | 
				
			||||||
import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.ENTITY_ID_LATITUDE_ARGUMENT_KEY;
 | 
					import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.ENTITY_ID_LATITUDE_ARGUMENT_KEY;
 | 
				
			||||||
import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.ENTITY_ID_LONGITUDE_ARGUMENT_KEY;
 | 
					import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.ENTITY_ID_LONGITUDE_ARGUMENT_KEY;
 | 
				
			||||||
import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.RESTRICTED_ZONES_ARGUMENT_KEY;
 | 
					import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.RESTRICTED_ZONES_ARGUMENT_KEY;
 | 
				
			||||||
import static org.thingsboard.server.common.data.cf.configuration.GeofencingCalculatedFieldConfiguration.ALLOWED_ZONES_ARGUMENT_KEY;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Data
 | 
					@Data
 | 
				
			||||||
 | 
					@AllArgsConstructor
 | 
				
			||||||
public class GeofencingCalculatedFieldState implements CalculatedFieldState {
 | 
					public class GeofencingCalculatedFieldState implements CalculatedFieldState {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private List<String> requiredArguments;
 | 
					    private List<String> requiredArguments;
 | 
				
			||||||
@ -46,9 +48,8 @@ public class GeofencingCalculatedFieldState implements CalculatedFieldState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private long latestTimestamp = -1;
 | 
					    private long latestTimestamp = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public GeofencingCalculatedFieldState() {
 | 
					    public GeofencingCalculatedFieldState() {
 | 
				
			||||||
        this(List.of(ENTITY_ID_LATITUDE_ARGUMENT_KEY, ENTITY_ID_LONGITUDE_ARGUMENT_KEY, ALLOWED_ZONES_ARGUMENT_KEY, RESTRICTED_ZONES_ARGUMENT_KEY));
 | 
					        this(new ArrayList<>(), new HashMap<>(), false, -1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public GeofencingCalculatedFieldState(List<String> argNames) {
 | 
					    public GeofencingCalculatedFieldState(List<String> argNames) {
 | 
				
			||||||
@ -112,8 +113,12 @@ public class GeofencingCalculatedFieldState implements CalculatedFieldState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public ListenableFuture<List<CalculatedFieldResult>> performCalculation(CalculatedFieldCtx ctx) {
 | 
					    public ListenableFuture<List<CalculatedFieldResult>> performCalculation(CalculatedFieldCtx ctx) {
 | 
				
			||||||
        List<CalculatedFieldResult> savedZonesStatesResults = updateGeofencingZonesState(ctx, false);
 | 
					        double latitude = (double) arguments.get(ENTITY_ID_LATITUDE_ARGUMENT_KEY).getValue();
 | 
				
			||||||
        List<CalculatedFieldResult> restrictedZonesStatesResults = updateGeofencingZonesState(ctx, true);
 | 
					        double longitude = (double) arguments.get(ENTITY_ID_LONGITUDE_ARGUMENT_KEY).getValue();
 | 
				
			||||||
 | 
					        Coordinates entityCoordinates = new Coordinates(latitude, longitude);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        List<CalculatedFieldResult> savedZonesStatesResults = updateGeofencingZonesState(ctx, entityCoordinates, false);
 | 
				
			||||||
 | 
					        List<CalculatedFieldResult> restrictedZonesStatesResults = updateGeofencingZonesState(ctx, entityCoordinates, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List<CalculatedFieldResult> allZoneStatesResults =
 | 
					        List<CalculatedFieldResult> allZoneStatesResults =
 | 
				
			||||||
                new ArrayList<>(savedZonesStatesResults.size() + restrictedZonesStatesResults.size());
 | 
					                new ArrayList<>(savedZonesStatesResults.size() + restrictedZonesStatesResults.size());
 | 
				
			||||||
@ -137,15 +142,15 @@ public class GeofencingCalculatedFieldState implements CalculatedFieldState {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private List<CalculatedFieldResult> updateGeofencingZonesState(CalculatedFieldCtx ctx, boolean restricted) {
 | 
					    private List<CalculatedFieldResult> updateGeofencingZonesState(CalculatedFieldCtx ctx, Coordinates entityCoordinates, boolean restricted) {
 | 
				
			||||||
        var results = new ArrayList<CalculatedFieldResult>();
 | 
					 | 
				
			||||||
        double latitude = (double) arguments.get(ENTITY_ID_LATITUDE_ARGUMENT_KEY).getValue();
 | 
					 | 
				
			||||||
        double longitude = (double) arguments.get(ENTITY_ID_LONGITUDE_ARGUMENT_KEY).getValue();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Coordinates entityCoordinates = new Coordinates(latitude, longitude);
 | 
					 | 
				
			||||||
        String zoneKey = restricted ? RESTRICTED_ZONES_ARGUMENT_KEY : ALLOWED_ZONES_ARGUMENT_KEY;
 | 
					        String zoneKey = restricted ? RESTRICTED_ZONES_ARGUMENT_KEY : ALLOWED_ZONES_ARGUMENT_KEY;
 | 
				
			||||||
        GeofencingArgumentEntry zonesEntry = (GeofencingArgumentEntry) arguments.get(zoneKey);
 | 
					        GeofencingArgumentEntry zonesEntry = (GeofencingArgumentEntry) arguments.get(zoneKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (zonesEntry == null) {
 | 
				
			||||||
 | 
					            return List.of();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var results = new ArrayList<CalculatedFieldResult>();
 | 
				
			||||||
        for (var zoneEntry : zonesEntry.getZoneStates().entrySet()) {
 | 
					        for (var zoneEntry : zonesEntry.getZoneStates().entrySet()) {
 | 
				
			||||||
            GeofencingZoneState state = zoneEntry.getValue();
 | 
					            GeofencingZoneState state = zoneEntry.getValue();
 | 
				
			||||||
            String event = state.evaluate(entityCoordinates);
 | 
					            String event = state.evaluate(entityCoordinates);
 | 
				
			||||||
 | 
				
			|||||||
@ -83,6 +83,9 @@ public class GeofencingZoneState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public String evaluate(Coordinates entityCoordinates) {
 | 
					    public String evaluate(Coordinates entityCoordinates) {
 | 
				
			||||||
        boolean inside = perimeterDefinition.checkMatches(entityCoordinates);
 | 
					        boolean inside = perimeterDefinition.checkMatches(entityCoordinates);
 | 
				
			||||||
 | 
					        // TODO: maybe handle this.inside == null as ENTERED or OUTSIDE.
 | 
				
			||||||
 | 
					        //  Since if this.inside == null then we don't have a state for this zone yet
 | 
				
			||||||
 | 
					        //  and logically say that we are OUTSIDE instead of LEFT.
 | 
				
			||||||
        if (this.inside == null || this.inside != inside) {
 | 
					        if (this.inside == null || this.inside != inside) {
 | 
				
			||||||
            this.inside = inside;
 | 
					            this.inside = inside;
 | 
				
			||||||
            return inside ? GpsGeofencingEvents.ENTERED : GpsGeofencingEvents.LEFT;
 | 
					            return inside ? GpsGeofencingEvents.ENTERED : GpsGeofencingEvents.LEFT;
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ import lombok.Data;
 | 
				
			|||||||
import lombok.EqualsAndHashCode;
 | 
					import lombok.EqualsAndHashCode;
 | 
				
			||||||
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
 | 
					import org.thingsboard.server.common.data.cf.CalculatedFieldType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.thingsboard.server.common.data.cf.configuration.CFArgumentDynamicSourceType.RELATION_QUERY;
 | 
					import static org.thingsboard.server.common.data.cf.configuration.CFArgumentDynamicSourceType.RELATION_QUERY;
 | 
				
			||||||
@ -32,13 +33,18 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
 | 
				
			|||||||
    public static final String ALLOWED_ZONES_ARGUMENT_KEY = "allowedZones";
 | 
					    public static final String ALLOWED_ZONES_ARGUMENT_KEY = "allowedZones";
 | 
				
			||||||
    public static final String RESTRICTED_ZONES_ARGUMENT_KEY = "restrictedZones";
 | 
					    public static final String RESTRICTED_ZONES_ARGUMENT_KEY = "restrictedZones";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final Set<String> requiredKeys = Set.of(
 | 
					    private static final Set<String> allowedKeys = Set.of(
 | 
				
			||||||
            ENTITY_ID_LATITUDE_ARGUMENT_KEY,
 | 
					            ENTITY_ID_LATITUDE_ARGUMENT_KEY,
 | 
				
			||||||
            ENTITY_ID_LONGITUDE_ARGUMENT_KEY,
 | 
					            ENTITY_ID_LONGITUDE_ARGUMENT_KEY,
 | 
				
			||||||
            ALLOWED_ZONES_ARGUMENT_KEY,
 | 
					            ALLOWED_ZONES_ARGUMENT_KEY,
 | 
				
			||||||
            RESTRICTED_ZONES_ARGUMENT_KEY
 | 
					            RESTRICTED_ZONES_ARGUMENT_KEY
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final Set<String> requiredKeys = Set.of(
 | 
				
			||||||
 | 
					            ENTITY_ID_LATITUDE_ARGUMENT_KEY,
 | 
				
			||||||
 | 
					            ENTITY_ID_LONGITUDE_ARGUMENT_KEY
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public CalculatedFieldType getType() {
 | 
					    public CalculatedFieldType getType() {
 | 
				
			||||||
        return CalculatedFieldType.GEOFENCING;
 | 
					        return CalculatedFieldType.GEOFENCING;
 | 
				
			||||||
@ -47,44 +53,72 @@ public class GeofencingCalculatedFieldConfiguration extends BaseCalculatedFieldC
 | 
				
			|||||||
    // TODO: update validate method in PE version.
 | 
					    // TODO: update validate method in PE version.
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void validate() {
 | 
					    public void validate() {
 | 
				
			||||||
        if (arguments == null || arguments.size() != 4) {
 | 
					        if (arguments == null) {
 | 
				
			||||||
            throw new IllegalArgumentException("Geofencing calculated field configuration must contain exactly 4 arguments: " + requiredKeys);
 | 
					            throw new IllegalArgumentException("Geofencing calculated field arguments are empty!");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check key count
 | 
				
			||||||
 | 
					        if (arguments.size() < 3 || arguments.size() > 4) {
 | 
				
			||||||
 | 
					            throw new IllegalArgumentException("Geofencing calculated field must contain 3 or 4 arguments: " + allowedKeys);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check for unsupported argument keys
 | 
				
			||||||
 | 
					        for (String key : arguments.keySet()) {
 | 
				
			||||||
 | 
					            if (!allowedKeys.contains(key)) {
 | 
				
			||||||
 | 
					                throw new IllegalArgumentException("Unsupported argument key: '" + key + "'. Allowed keys: " + allowedKeys);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check required fields: latitude and longitude
 | 
				
			||||||
        for (String requiredKey : requiredKeys) {
 | 
					        for (String requiredKey : requiredKeys) {
 | 
				
			||||||
            Argument argument = arguments.get(requiredKey);
 | 
					            if (!arguments.containsKey(requiredKey)) {
 | 
				
			||||||
            if (argument == null) {
 | 
					 | 
				
			||||||
                throw new IllegalArgumentException("Missing required argument: " + requiredKey);
 | 
					                throw new IllegalArgumentException("Missing required argument: " + requiredKey);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Ensure at least one of the zone types is configured
 | 
				
			||||||
 | 
					        boolean hasAllowedZones = arguments.containsKey(ALLOWED_ZONES_ARGUMENT_KEY);
 | 
				
			||||||
 | 
					        boolean hasRestrictedZones = arguments.containsKey(RESTRICTED_ZONES_ARGUMENT_KEY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!hasAllowedZones && !hasRestrictedZones) {
 | 
				
			||||||
 | 
					            throw new IllegalArgumentException("Geofencing calculated field must contain at least one of the following arguments: 'allowedZones' or 'restrictedZones'");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (Map.Entry<String, Argument> entry : arguments.entrySet()) {
 | 
				
			||||||
 | 
					            String argumentKey = entry.getKey();
 | 
				
			||||||
 | 
					            Argument argument = entry.getValue();
 | 
				
			||||||
 | 
					            if (argument == null) {
 | 
				
			||||||
 | 
					                throw new IllegalArgumentException("Missing required argument: " + argumentKey);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            ReferencedEntityKey refEntityKey = argument.getRefEntityKey();
 | 
					            ReferencedEntityKey refEntityKey = argument.getRefEntityKey();
 | 
				
			||||||
            if (refEntityKey == null || refEntityKey.getType() == null) {
 | 
					            if (refEntityKey == null || refEntityKey.getType() == null) {
 | 
				
			||||||
                throw new IllegalArgumentException("Missing or invalid reference entity key for argument: " + requiredKey);
 | 
					                throw new IllegalArgumentException("Missing or invalid reference entity key for argument: " + argumentKey);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            switch (requiredKey) {
 | 
					
 | 
				
			||||||
                case ENTITY_ID_LATITUDE_ARGUMENT_KEY, ENTITY_ID_LONGITUDE_ARGUMENT_KEY -> {
 | 
					            switch (argumentKey) {
 | 
				
			||||||
 | 
					                case ENTITY_ID_LATITUDE_ARGUMENT_KEY,
 | 
				
			||||||
 | 
					                     ENTITY_ID_LONGITUDE_ARGUMENT_KEY -> {
 | 
				
			||||||
                    if (!ArgumentType.TS_LATEST.equals(refEntityKey.getType())) {
 | 
					                    if (!ArgumentType.TS_LATEST.equals(refEntityKey.getType())) {
 | 
				
			||||||
                        throw new IllegalArgumentException("Argument: '" + requiredKey + "' must be set to " + ArgumentType.TS_LATEST + " type!");
 | 
					                        throw new IllegalArgumentException("Argument '" + argumentKey + "' must be of type TS_LATEST.");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    var dynamicSource = argument.getRefDynamicSource();
 | 
					                    if (argument.getRefDynamicSource() != null) {
 | 
				
			||||||
                    if (dynamicSource != null) {
 | 
					                        throw new IllegalArgumentException("Dynamic source is not allowed for argument: '" + argumentKey + "'.");
 | 
				
			||||||
                        String test = "test";
 | 
					 | 
				
			||||||
                        throw new IllegalArgumentException("Dynamic source configuration is forbidden for '" + requiredKey + "' argument. " +
 | 
					 | 
				
			||||||
                                                           "Only '" + ALLOWED_ZONES_ARGUMENT_KEY + "' and '" + RESTRICTED_ZONES_ARGUMENT_KEY + "' " +
 | 
					 | 
				
			||||||
                                                           "may use dynamic source configuration.");
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                case ALLOWED_ZONES_ARGUMENT_KEY, RESTRICTED_ZONES_ARGUMENT_KEY -> {
 | 
					                case ALLOWED_ZONES_ARGUMENT_KEY,
 | 
				
			||||||
 | 
					                     RESTRICTED_ZONES_ARGUMENT_KEY -> {
 | 
				
			||||||
                    if (!ArgumentType.ATTRIBUTE.equals(refEntityKey.getType())) {
 | 
					                    if (!ArgumentType.ATTRIBUTE.equals(refEntityKey.getType())) {
 | 
				
			||||||
                        throw new IllegalArgumentException("Argument: '" + requiredKey + "' must be set to " + ArgumentType.ATTRIBUTE + " type!");
 | 
					                        throw new IllegalArgumentException("Argument '" + argumentKey + "' must be of type ATTRIBUTE.");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    var dynamicSource = argument.getRefDynamicSource();
 | 
					                    var dynamicSource = argument.getRefDynamicSource();
 | 
				
			||||||
                    if (dynamicSource == null) {
 | 
					                    if (dynamicSource == null) {
 | 
				
			||||||
                        continue;
 | 
					                        continue;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (!RELATION_QUERY.equals(dynamicSource)) {
 | 
					                    if (!RELATION_QUERY.equals(dynamicSource)) {
 | 
				
			||||||
                        throw new IllegalArgumentException("Only relation query dynamic source is supported for argument: " + requiredKey);
 | 
					                        throw new IllegalArgumentException("Only relation query dynamic source is supported for argument: '" + argumentKey + "'.");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    if (argument.getRefDynamicSourceConfiguration() == null) {
 | 
					                    if (argument.getRefDynamicSourceConfiguration() == null) {
 | 
				
			||||||
                        throw new IllegalArgumentException("Missing dynamic source configuration for: " + requiredKey);
 | 
					                        throw new IllegalArgumentException("Missing dynamic source configuration for argument: '" + argumentKey + "'.");
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    argument.getRefDynamicSourceConfiguration().validate();
 | 
					                    argument.getRefDynamicSourceConfiguration().validate();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,7 @@ public class RelationQueryDynamicSourceConfiguration implements CfArgumentDynami
 | 
				
			|||||||
    private boolean fetchLastLevelOnly;
 | 
					    private boolean fetchLastLevelOnly;
 | 
				
			||||||
    private EntitySearchDirection direction;
 | 
					    private EntitySearchDirection direction;
 | 
				
			||||||
    private String relationType;
 | 
					    private String relationType;
 | 
				
			||||||
    private List<EntityType> profiles;
 | 
					    private List<EntityType> entityTypes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public CFArgumentDynamicSourceType getType() {
 | 
					    public CFArgumentDynamicSourceType getType() {
 | 
				
			||||||
@ -56,7 +56,7 @@ public class RelationQueryDynamicSourceConfiguration implements CfArgumentDynami
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean isSimpleRelation() {
 | 
					    public boolean isSimpleRelation() {
 | 
				
			||||||
        return maxLevel == 1 && (profiles == null || profiles.isEmpty());
 | 
					        return maxLevel == 1 && (entityTypes == null || entityTypes.isEmpty());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@ -66,7 +66,7 @@ public class RelationQueryDynamicSourceConfiguration implements CfArgumentDynami
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        var entityRelationsQuery = new EntityRelationsQuery();
 | 
					        var entityRelationsQuery = new EntityRelationsQuery();
 | 
				
			||||||
        entityRelationsQuery.setParameters(new RelationsSearchParameters(rootEntityId, direction, maxLevel, fetchLastLevelOnly));
 | 
					        entityRelationsQuery.setParameters(new RelationsSearchParameters(rootEntityId, direction, maxLevel, fetchLastLevelOnly));
 | 
				
			||||||
        entityRelationsQuery.setFilters(Collections.singletonList(new RelationEntityTypeFilter(relationType, profiles)));
 | 
					        entityRelationsQuery.setFilters(Collections.singletonList(new RelationEntityTypeFilter(relationType, entityTypes)));
 | 
				
			||||||
        return entityRelationsQuery;
 | 
					        return entityRelationsQuery;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -70,8 +70,8 @@ public class CalculatedFieldDataValidator extends DataValidator<CalculatedField>
 | 
				
			|||||||
        if (maxArgumentsPerCF <= 0) {
 | 
					        if (maxArgumentsPerCF <= 0) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (CalculatedFieldType.GEOFENCING.equals(calculatedField.getType()) && maxArgumentsPerCF < 4) {
 | 
					        if (CalculatedFieldType.GEOFENCING.equals(calculatedField.getType()) && maxArgumentsPerCF < 3) {
 | 
				
			||||||
            throw new DataValidationException("Geofencing calculated field requires 4 arguments, but the system limit is " +
 | 
					            throw new DataValidationException("Geofencing calculated field requires at least 3 arguments, but the system limit is " +
 | 
				
			||||||
                                              maxArgumentsPerCF + ". Contact your administrator to increase the limit."
 | 
					                                              maxArgumentsPerCF + ". Contact your administrator to increase the limit."
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user