/* (c) 2014, 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2014 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.data.resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.IValidator;
import org.apache.wicket.validation.ValidationError;
import org.geotools.filter.FilterAttributeExtractor;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.filter.text.ecql.ECQL;
import org.opengis.filter.expression.Expression;
/**
* Validates that a ECQL expression is syntactically valid, and if a set of valid attribute is
* provided, that the expression only uses those attributes
*
* @author Andrea Aime - GeoSolutions
*/
public class ECQLValidator implements IValidator<String> {
private static final long serialVersionUID = 2268953695122233556L;
Set<String> validAttributes;
public ECQLValidator setValidAttributes(String... validAttributes) {
this.validAttributes = new LinkedHashSet<>(Arrays.asList(validAttributes));
return this;
}
public ECQLValidator setValidAttributes(Collection<String> validAttributes) {
this.validAttributes = new LinkedHashSet<>(validAttributes);
return this;
}
private String commaSeparated(Collection<String> invalids) {
StringBuilder string = new StringBuilder();
for (String attribute : invalids) {
string.append(attribute);
string.append(", ");
}
string.setLength(string.length() - 2);
return string.toString();
}
Map<String, Object> map(String... entries) {
Map<String, Object> result = new HashMap<>();
for (int i = 0; i < entries.length; i += 2) {
result.put(entries[i], entries[i + 1]);
}
return result;
}
@Override
public void validate(IValidatable<String> iv) {
// Extraction of the expression for the validation
String expression = iv.getValue();
if (expression == null || expression.isEmpty() || expression.trim().isEmpty()) {
return;
}
Expression ecql = null;
// First check on the Syntax of the expression
try {
ecql = ECQL.toExpression(expression);
} catch (CQLException e) {
ValidationError error = new ValidationError(this);
error.setVariable("expression", expression);
error.setVariable("error", e.getMessage());
error.setMessage("ecql.invalidExpression");
iv.error(error);
}
// Selection of a FilterAttributeExtractor
if (ecql != null && validAttributes != null) {
FilterAttributeExtractor filter = new FilterAttributeExtractor();
ecql.accept(filter, null);
// Extraction of the attributes, and filter out the valid ones
List<String> invalids = new ArrayList<>(Arrays.asList(filter.getAttributeNames()));
invalids.removeAll(validAttributes);
// if and only if an invalid attribute is present
if (!invalids.isEmpty()) {
String invalidList = commaSeparated(invalids);
String validList = commaSeparated(validAttributes);
ValidationError error = new ValidationError(this);
error.setVariable("expression", expression);
error.setVariable("invalidAttributes", invalidList);
error.setVariable("validAttributes", validList);
error.setMessage("ecql.invalidAttributes");
iv.error(error);
}
}
}
}