package tc.oc.pgm.filters.parser;
import javax.inject.Inject;
import org.jdom2.Document;
import org.jdom2.Element;
import tc.oc.pgm.features.LegacyFeatureParser;
import tc.oc.pgm.filters.Filter;
import tc.oc.pgm.filters.matcher.StaticFilter;
import tc.oc.pgm.filters.query.IQuery;
import tc.oc.pgm.map.MapModule;
import tc.oc.pgm.map.MapRootParser;
import tc.oc.pgm.regions.RegionParser;
import tc.oc.pgm.utils.XMLUtils;
import tc.oc.pgm.xml.InvalidXMLException;
import tc.oc.pgm.xml.Node;
import tc.oc.pgm.xml.UnrecognizedXMLException;
import tc.oc.pgm.xml.validate.Validation;
import static tc.oc.commons.core.exception.LambdaExceptionUtils.rethrowConsumer;
public class FilterParser extends LegacyFeatureParser<Filter> implements MapModule, MapRootParser {
@Inject protected Document xml;
@Inject protected RegionParser regionParser;
@Inject protected DynamicFilterValidation dynamicFilterValidation;
@Override
public void parse() throws InvalidXMLException {
defineBuiltInFilters();
parseTopLevelFilters();
}
protected void defineBuiltInFilters() throws InvalidXMLException {
features.define("always", new StaticFilter(Filter.QueryResponse.ALLOW));
features.define("never", new StaticFilter(Filter.QueryResponse.DENY));
}
protected void parseTopLevelFilters() throws InvalidXMLException {
// Modern proto treats <filters> and <regions> the same
for(Element el : XMLUtils.getChildren(xml.getRootElement(), "filters", "regions")) {
parseChildren(el).count();
}
}
@Override
protected boolean canIgnore(Element el) throws InvalidXMLException {
return "apply".equals(el.getName()) || super.canIgnore(el);
}
@Override
public boolean isParseable(Element el) throws InvalidXMLException {
return super.isParseable(el) || regionParser.isParseable(el);
}
@Override
public Filter parseElement(Element el) throws InvalidXMLException {
// If we find something unparseable, try parsing it as a region before giving up
if(super.isParseable(el)) {
return super.parseElement(el);
} else if(regionParser.isParseable(el)) {
return regionParser.parseElement(el);
} else {
throw new UnrecognizedXMLException(propertyName(), el);
}
}
@Override
public FilterPropertyBuilder property(Element element) {
return property(element, propertyName());
}
@Override
public FilterPropertyBuilder property(Element el, String name) {
return new FilterPropertyBuilder(el, name);
}
public class FilterPropertyBuilder extends PropertyBuilder<FilterPropertyBuilder> {
public FilterPropertyBuilder(Element element, String name) {
super(element, name);
}
public FilterPropertyBuilder respondsTo(Class<? extends IQuery> queryType) {
validate(RespondsToQueryValidation.get(queryType));
return this;
}
public FilterPropertyBuilder dynamic() {
validateTree(dynamicFilterValidation);
return this;
}
public FilterPropertyBuilder validateTree(Validation<? super Filter> validation) {
validate((filter, node) -> applyValidationToTree(filter, node, validation));
return this;
}
}
private static void applyValidationToTree(Filter filter, Node node, Validation<? super Filter> validation) throws InvalidXMLException {
validation.validate(filter, node);
filter.dependencies(Filter.class).forEach(rethrowConsumer(dep -> applyValidationToTree(dep, node, validation)));
}
}