package tc.oc.pgm.xml.validate; import java.util.Arrays; import java.util.Collection; import java.util.function.Function; import javax.annotation.Nullable; import com.google.common.reflect.TypeToken; import tc.oc.commons.core.reflect.TypeParameterCache; import tc.oc.pgm.xml.InvalidXMLException; import tc.oc.pgm.xml.Node; import static tc.oc.commons.core.exception.LambdaExceptionUtils.rethrowConsumer; /** * A validation that can be applied to any {@link T} instance */ @FunctionalInterface public interface Validation<T> { TypeParameterCache<Validation, Object> CACHE_T = new TypeParameterCache<>(Validation.class, "T"); static TypeToken<?> type(Class<? extends Validation> validation) { return CACHE_T.resolve(validation); } default TypeToken<T> type() { return (TypeToken<T>) type((Class<Validation<T>>) getClass()); } void validate(T value, @Nullable Node node) throws InvalidXMLException; default Validatable bind(T value, @Nullable Node node) { return ((Validatable) () -> validate(value, node)).offeringNode(node); } default LocatedValidation<T> bind(@Nullable Node node) { return ((LocatedValidation<T>) value -> validate(value, node)).offeringNode(node); } default Validation<T> findingNode(Function<T, Node> finder) { return (value, node) -> { if(node == null) { node = finder.apply(value); } try { validate(value, node); } catch(InvalidXMLException e) { e.offerNode(node); throw e; } }; } static <T> Validation<T> all(Validation<? super T>... validations) { return all(Arrays.asList(validations)); } static <T> Validation<T> all(Collection<? extends Validation<? super T>> validations) { return (value, node) -> validations.forEach(rethrowConsumer(validation -> validation.validate(value, node))); } }