All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jsqlparser.util.validation.validator.AbstractValidator Maven / Gradle / Ivy

Go to download

JSqlParser parses an SQL statement and translate it into a hierarchy of Java classes. The generated hierarchy can be navigated using the Visitor Pattern.

The newest version!
/*-
 * #%L
 * JSQLParser library
 * %%
 * Copyright (C) 2004 - 2020 JSQLParser
 * %%
 * Dual licensed under GNU LGPL 2.1 or Apache License 2.0
 * #L%
 */
package net.sf.jsqlparser.util.validation.validator;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.feature.Feature;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.util.validation.ValidationCapability;
import net.sf.jsqlparser.util.validation.ValidationContext;
import net.sf.jsqlparser.util.validation.ValidationException;
import net.sf.jsqlparser.util.validation.Validator;
import net.sf.jsqlparser.util.validation.feature.FeatureContext;
import net.sf.jsqlparser.util.validation.feature.FeatureSetValidation;
import net.sf.jsqlparser.util.validation.metadata.DatabaseMetaDataValidation;
import net.sf.jsqlparser.util.validation.metadata.MetadataContext;
import net.sf.jsqlparser.util.validation.metadata.Named;
import net.sf.jsqlparser.util.validation.metadata.NamedObject;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * A abstract base for a Validation
 *
 * @param  the type of statement this DeParser supports
 * @author gitmotte
 */
public abstract class AbstractValidator implements Validator {

    private final Map> errors = new HashMap<>();
    private final Map>, AbstractValidator> validatorForwards =
            new HashMap<>();
    private ValidationContext context = new ValidationContext();

    public > T getValidator(Class type) {
        return type.cast(validatorForwards.computeIfAbsent(type, this::newObject));
    }

    private > E newObject(Class type) {
        try {
            E e = type.cast(type.getConstructor().newInstance());
            e.setContext(context());
            return e;
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                | InvocationTargetException | NoSuchMethodException | SecurityException e) {
            throw new IllegalStateException(
                    "Type " + type + " cannot be constructed by empty constructor!");
        }
    }

    protected Consumer getMessageConsumer(ValidationCapability c) {
        return s -> putError(c, s);
    }

    protected ValidationContext context() {
        return context(true);
    }

    protected ValidationContext context(boolean reInit) {
        return context.reinit(reInit);
    }

    /**
     * adds an error for this {@link ValidationCapability}
     *
     * @param capability
     * @param error
     */
    protected void putError(ValidationCapability capability, ValidationException error) {
        errors.computeIfAbsent(capability, k -> new HashSet<>()).add(error);
    }

    @Override
    public final Map> getValidationErrors() {
        Map> map = new HashMap<>();
        map.putAll(errors);
        for (AbstractValidator v : validatorForwards.values()) {
            for (Entry> e : v.getValidationErrors()
                    .entrySet()) {
                Set set = map.get(e.getKey());
                if (set == null) {
                    map.put(e.getKey(), e.getValue());
                } else {
                    set.addAll(e.getValue());
                }
            }
        }
        return map;
    }

    public Collection getCapabilities() {
        return context().getCapabilities();
    }

    @Override
    public final void setContext(ValidationContext context) {
        this.context = context;
    }

    protected  void validateOptional(E element, Consumer elementConsumer) {
        if (element != null) {
            elementConsumer.accept(element);
        }
    }

    protected > void validateOptionalList(List elementList,
            Supplier validatorSupplier, BiConsumer elementConsumer) {
        if (isNotEmpty(elementList)) {
            V validator = validatorSupplier.get();
            elementList.forEach(e -> elementConsumer.accept(e, validator));
        }
    }

    protected void validateOptionalExpression(Expression expression) {
        validateOptional(expression, e -> e.accept(getValidator(ExpressionValidator.class), null));
    }

    protected void validateOptionalExpression(Expression expression, ExpressionValidator v) {
        validateOptional(expression, e -> e.accept(v, null));
    }

    protected void validateOptionalExpressions(List expressions) {
        validateOptionalList(expressions, () -> getValidator(ExpressionValidator.class),
                (o, v) -> o.accept(v, null));
    }

    protected void validateOptionalFromItems(FromItem... fromItems) {
        validateOptionalFromItems(Arrays.asList(fromItems));
    }

    protected void validateOptionalFromItems(List fromItems) {
        validateOptionalList(fromItems, () -> getValidator(SelectValidator.class),
                this::validateOptionalFromItem);
    }

    protected void validateOptionalOrderByElements(List orderByElements) {
        validateOptionalList(orderByElements, () -> getValidator(OrderByValidator.class),
                (o, v) -> o.accept(v, null));
    }

    protected void validateOptionalFromItem(FromItem fromItem) {
        validateOptional(fromItem, i -> i.accept(getValidator(SelectValidator.class), null));
    }

    protected void validateOptionalFromItem(FromItem fromItem, SelectValidator v) {
        validateOptional(fromItem, i -> i.accept(v, null));
    }

    /**
     * Iterates through all {@link ValidationCapability} and validates the feature with
     * {@link #validateFeature(ValidationCapability, Feature)}
     *
     * @param feature
     */
    protected void validateFeature(Feature feature) {
        for (ValidationCapability c : getCapabilities()) {
            validateFeature(c, feature);
        }
    }

    /**
     * Iterates through all {@link ValidationCapability} and validates
     * 
    *
  • the name with {@link #validateName(ValidationCapability, NamedObject, String)}
  • *
  • the feature with {@link #validateFeature(ValidationCapability, Feature)}
  • *
* * @param feature * @param namedObject * @param fqn - fully qualified name of named object */ protected void validateFeatureAndName(Feature feature, NamedObject namedObject, String fqn) { validateFeatureAndNameWithAlias(feature, namedObject, fqn, null); } /** * Iterates through all {@link ValidationCapability} and validates *
    *
  • the name with {@link #validateName(ValidationCapability, NamedObject, String)}
  • *
  • the feature with {@link #validateFeature(ValidationCapability, Feature)}
  • *
* * @param feature * @param namedObject * @param fqn - fully qualified name of named object * @param alias */ protected void validateFeatureAndNameWithAlias(Feature feature, NamedObject namedObject, String fqn, String alias) { for (ValidationCapability c : getCapabilities()) { validateFeature(c, feature); validateNameWithAlias(c, namedObject, fqn, alias, true); } } /** * Iterates through all {@link ValidationCapability} and validates for the name with * {@link #validateName(ValidationCapability, NamedObject, String)} * * @param namedObject * @param fqn - fully qualified name of named object */ protected void validateName(NamedObject namedObject, String fqn) { validateNameWithAlias(namedObject, fqn, null); } /** * Iterates through all {@link ValidationCapability} and validates for the name with * {@link #validateName(ValidationCapability, NamedObject, String)} * * @param namedObject * @param fqn - fully qualified name of named object * @param alias */ protected void validateNameWithAlias(NamedObject namedObject, String fqn, String alias) { for (ValidationCapability c : getCapabilities()) { validateNameWithAlias(c, namedObject, fqn, alias, true); } } /** * Validates the feature if given {@link ValidationCapability} is a {@link FeatureSetValidation} * and condition is true * * @param capability * @param condition * @param feature */ protected void validateFeature(ValidationCapability capability, boolean condition, Feature feature) { if (condition) { validateFeature(capability, feature); } } /** * validates for the feature if given elements is not empty - see * {@link #isNotEmpty(Collection)} * * @param capability * @param elements * @param feature */ protected void validateOptionalFeature(ValidationCapability capability, List elements, Feature feature) { validateFeature(capability, isNotEmpty(elements), feature); } /** * Validates for the feature if given element is not null * * @param capability * @param element * @param feature */ protected void validateOptionalFeature(ValidationCapability capability, Object element, Feature feature) { validateFeature(capability, element != null, feature); } /** * Validates if given {@link ValidationCapability} is a {@link FeatureSetValidation} * * @param capability * @param feature */ protected void validateFeature(ValidationCapability capability, Feature feature) { if (capability instanceof FeatureSetValidation) { capability.validate(context().put(FeatureContext.feature, feature), getMessageConsumer(capability)); } } /** * Validates if given {@link ValidationCapability} is a {@link DatabaseMetaDataValidation} * * @param capability * @param namedObject * @param fqn - fully qualified name of named object * @param alias */ protected void validateNameWithAlias(ValidationCapability capability, NamedObject namedObject, String fqn, String alias) { validateNameWithAlias(capability, namedObject, fqn, alias, true); } /** * @param capability * @param namedObject * @param fqn - fully qualified name of named object */ protected void validateName(ValidationCapability capability, NamedObject namedObject, String fqn) { validateNameWithAlias(capability, namedObject, fqn, null, true); } /** * Validates if given {@link ValidationCapability} is a {@link DatabaseMetaDataValidation} * * @param capability * @param namedObject * @param fqn - fully qualified name of named object * @param alias * @param exists - true, check for existence, false, check for * non-existence */ protected void validateNameWithAlias(ValidationCapability capability, NamedObject namedObject, String fqn, String alias, boolean exists, NamedObject... parents) { if (capability instanceof DatabaseMetaDataValidation) { capability .validate( context() .put(MetadataContext.named, new Named(namedObject, fqn).setAlias(alias) .setParents(Arrays.asList(parents))) // .put(MetadataContext.exists, exists), getMessageConsumer(capability)); } } /** * @param capability * @param namedObject * @param fqn - fully qualified name of named object * @param exists * @param parents */ protected void validateName(ValidationCapability capability, NamedObject namedObject, String fqn, boolean exists, NamedObject... parents) { validateNameWithAlias(capability, namedObject, fqn, null, exists, parents); } /** * @param capability * @param name */ protected void validateOptionalColumnName(ValidationCapability capability, String name) { validateOptionalName(capability, NamedObject.column, name, null, true); } /** * @param capability * @param name * @param alias */ protected void validateOptionalColumnNameWithAlias(ValidationCapability capability, String name, String alias) { validateOptionalName(capability, NamedObject.column, name, alias, true); } /** * @param capability * @param columnNames * @param parents */ protected void validateOptionalColumnNames(ValidationCapability capability, List columnNames, NamedObject... parents) { validateOptionalColumnNames(capability, columnNames, true, parents); } /** * @param capability * @param columnNames * @param exists * @param parents */ protected void validateOptionalColumnNames(ValidationCapability capability, List columnNames, boolean exists, NamedObject... parents) { if (columnNames != null) { columnNames.forEach(n -> validateOptionalName(capability, NamedObject.column, n, null, exists, parents)); } } /** * @param capability * @param namedObject * @param name * @param alias * @param parents */ protected void validateOptionalNameWithAlias(ValidationCapability capability, NamedObject namedObject, String name, String alias, NamedObject... parents) { validateOptionalName(capability, namedObject, name, alias, true, parents); } /** * @param capability * @param namedObject * @param name * @param parents */ protected void validateOptionalName(ValidationCapability capability, NamedObject namedObject, String name, NamedObject... parents) { validateOptionalNameWithAlias(capability, namedObject, name, (String) null, parents); } /** * @param capability * @param namedObject * @param name * @param alias * @param exists * @param parents */ protected void validateOptionalName(ValidationCapability capability, NamedObject namedObject, String name, String alias, boolean exists, NamedObject... parents) { if (name != null) { validateNameWithAlias(capability, namedObject, name, alias, exists, parents); } } protected boolean isNotEmpty(Collection c) { return c != null && !c.isEmpty(); } protected boolean isNotEmpty(String c) { return c != null && !c.isEmpty(); } }