use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class RSQLFilterDialect method parseTypedExpression.
@Override
public Map<String, FilterExpression> parseTypedExpression(String path, MultivaluedMap<String, String> filterParams, String apiVersion) throws ParseException {
Map<String, FilterExpression> expressionByType = new HashMap<>();
for (MultivaluedMap.Entry<String, List<String>> entry : filterParams.entrySet()) {
String paramName = entry.getKey();
List<String> paramValues = entry.getValue();
Matcher matcher = TYPED_FILTER_PATTERN.matcher(paramName);
if (matcher.find()) {
String typeName = matcher.group(1);
if (paramValues.size() != 1) {
throw new ParseException("Exactly one RSQL expression must be defined for type : " + typeName);
}
Type entityType = dictionary.getEntityClass(typeName, apiVersion);
if (entityType == null) {
throw new ParseException(INVALID_QUERY_PARAMETER + paramName);
}
String expressionText = paramValues.get(0);
FilterExpression filterExpression = parseFilterExpression(expressionText, entityType, true);
expressionByType.put(typeName, filterExpression);
} else {
throw new ParseException(INVALID_QUERY_PARAMETER + paramName);
}
}
return expressionByType;
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class RSQLFilterDialect method parseGlobalExpression.
@Override
public FilterExpression parseGlobalExpression(String path, MultivaluedMap<String, String> filterParams, String apiVersion) throws ParseException {
if (filterParams.size() != 1) {
throw new ParseException(SINGLE_PARAMETER_ONLY);
}
MultivaluedMap.Entry<String, List<String>> entry = CollectionUtils.get(filterParams, 0);
String queryParamName = entry.getKey();
if (!"filter".equals(queryParamName)) {
throw new ParseException(INVALID_QUERY_PARAMETER + queryParamName);
}
List<String> queryParamValues = entry.getValue();
if (queryParamValues.size() != 1) {
throw new ParseException(SINGLE_PARAMETER_ONLY);
}
String queryParamValue = queryParamValues.get(0);
/*
* Extract the last collection in the URL.
*/
String normalizedPath = JsonApiParser.normalizePath(path);
String[] pathComponents = normalizedPath.split("/");
String lastPathComponent = pathComponents.length > 0 ? pathComponents[pathComponents.length - 1] : "";
/*
* TODO - create a visitor which extracts the type/class of the last path component.
* This works today by virtue that global filter expressions are only used for root collections
* and NOT nested associations.
*/
Type entityType = dictionary.getEntityClass(lastPathComponent, apiVersion);
if (entityType == null) {
throw new ParseException("No such collection: " + lastPathComponent);
}
return parseFilterExpression(queryParamValue, entityType, true);
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class DefaultFilterDialect method getPath.
/**
* Parses [ author, books, publisher, name ] into [(author, books), (book, publisher), (publisher, name)].
*
* @param keyParts [ author, books, publisher, name ]
* @param apiVersion The client requested version.
* @return [(author, books), (book, publisher), (publisher, name)]
* @throws ParseException if the filter cannot be parsed
*/
private Path getPath(final String[] keyParts, String apiVersion) throws ParseException {
if (keyParts == null || keyParts.length <= 0) {
throw new ParseException("Invalid filter expression");
}
List<Path.PathElement> path = new ArrayList<>();
Type<?>[] types = new Type[keyParts.length];
String type = keyParts[0];
types[0] = dictionary.getEntityClass(type, apiVersion);
if (types[0] == null) {
throw new ParseException("Unknown entity in filter: " + type);
}
/* Extract all the paths for the associations */
for (int i = 1; i < keyParts.length; ++i) {
final String field = keyParts[i];
final Type<?> entityClass = types[i - 1];
final Type<?> fieldType = ("id".equals(field.toLowerCase(Locale.ENGLISH))) ? dictionary.getIdType(entityClass) : dictionary.getParameterizedType(entityClass, field);
if (fieldType == null) {
throw new ParseException("Unknown field in filter: " + field);
}
types[i] = fieldType;
}
/* Build all the Predicate path elements */
for (int i = 0; i < types.length - 1; ++i) {
Type typeClass = types[i];
String fieldName = keyParts[i + 1];
Type fieldClass = types[i + 1];
Path.PathElement pathElement = new Path.PathElement(typeClass, fieldClass, fieldName);
path.add(pathElement);
}
return new Path(path);
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class PermissionExpressionBuilder method buildAnyFieldFilterExpression.
/**
* Build an expression representing any field on an entity.
*
* @param forType Resource class
* @param requestScope requestScope
* @return Expressions
*/
public FilterExpression buildAnyFieldFilterExpression(Type<?> forType, RequestScope requestScope, Set<String> requestedFields) {
Class<? extends Annotation> annotationClass = ReadPermission.class;
ParseTree classPermissions = entityDictionary.getPermissionsForClass(forType, annotationClass);
FilterExpression entityFilter = filterExpressionFromParseTree(classPermissions, forType, requestScope);
// case where the permissions does not have ANY filterExpressionCheck
if (entityFilter == FALSE_USER_CHECK_EXPRESSION || entityFilter == NO_EVALUATION_EXPRESSION || entityFilter == TRUE_USER_CHECK_EXPRESSION) {
entityFilter = null;
}
FilterExpression allFieldsFilterExpression = entityFilter;
List<String> fields = entityDictionary.getAllExposedFields(forType).stream().filter(field -> requestedFields == null || requestedFields.contains(field)).collect(Collectors.toList());
for (String field : fields) {
ParseTree fieldPermissions = entityDictionary.getPermissionsForField(forType, field, annotationClass);
FilterExpression fieldExpression = filterExpressionFromParseTree(fieldPermissions, forType, requestScope);
if (fieldExpression == null && entityFilter == null) {
// this field will be visible across all instances
return null;
}
if (fieldExpression == null || fieldExpression == FALSE_USER_CHECK_EXPRESSION) {
// In either case this field is not useful for filtering when loading records
continue;
}
if (fieldExpression == NO_EVALUATION_EXPRESSION || fieldExpression == TRUE_USER_CHECK_EXPRESSION) {
// When the expression is TRUE_USER_CHECK_EXPRESSION all records can be loaded
return null;
}
if (allFieldsFilterExpression != null) {
allFieldsFilterExpression = new OrFilterExpression(allFieldsFilterExpression, fieldExpression);
} else {
allFieldsFilterExpression = fieldExpression;
}
}
return allFieldsFilterExpression;
}
use of com.yahoo.elide.core.type.Type in project elide by yahoo.
the class ActivePermissionExecutor method checkPermissions.
/**
* First attempts to check user permissions (by looking in the cache and if not present by executing user
* permissions). If user permissions don't short circuit the check, run the provided expression executor.
*
* @param <A> type parameter
* @param resourceClass Resource class
* @param annotationClass Annotation class
* @param fields Set of all field names that is being accessed
* @param expressionSupplier Builds a permission expression.
* @param expressionExecutor Evaluates the expression (post user check evaluation)
*/
protected <A extends Annotation> ExpressionResult checkPermissions(Type<?> resourceClass, Class<A> annotationClass, Set<String> fields, Supplier<Expression> expressionSupplier, Optional<Function<Expression, ExpressionResult>> expressionExecutor) {
// If the user check has already been evaluated before, return the result directly and save the building cost
ImmutableSet<String> immutableFields = fields == null ? null : ImmutableSet.copyOf(fields);
ExpressionResult expressionResult = userPermissionCheckCache.get(Triple.of(annotationClass, resourceClass, immutableFields));
if (expressionResult == PASS) {
return expressionResult;
}
Expression expression = expressionSupplier.get();
if (expressionResult == null) {
expressionResult = executeExpressions(expression, annotationClass, Expression.EvaluationMode.USER_CHECKS_ONLY);
userPermissionCheckCache.put(Triple.of(annotationClass, resourceClass, immutableFields), expressionResult);
if (expressionResult == PASS) {
return expressionResult;
}
}
return expressionExecutor.map(executor -> executor.apply(expression)).orElse(expressionResult);
}
Aggregations