package com.megatim.fdxcommons.core.impl.db.validators; import static com.megatim.fdxcommons.model.enumeration.Operateur.*; import com.megatim.fdxcommons.model.enumeration.TypeDonnee; import com.megatim.fdxcommons.model.integration.ColumnDefinition; import com.megatim.fdxcommons.model.pojo.BetweenOperatorValues; import com.megatim.fdxcommons.model.pojo.CriteriaEntity; import com.megatim.fdxcommons.tools.exceptions.CommonApplicationValidationException; import java.math.BigDecimal; import java.sql.Timestamp; import java.time.LocalDateTime; import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.enterprise.context.Dependent; import com.megatim.fdxcommons.core.ifaces.db.validators.CriteriaQueryValidator; /** * * @author lenovo */ @Dependent public class CriteriaQueryValidatorImpl implements CriteriaQueryValidator { @Override public List validate(CriteriaEntity criterion, Map columnDefinitionsMap) { List errors = new ArrayList<>(); // int index = 1; // String numeroElt = " : Elément numéro " + index; TypeDonnee typeDonnee = null; if (criterion != null && isNotEmptyCriteria(criterion)) { if (criterion.getSubCriterias().isEmpty()) { if (!validateCriteriaNomColonne(columnDefinitionsMap, criterion)) { errors.add("Colonne '" + criterion.getNomColonne() + "' des critères de sélection est introuvable"); } else if ((typeDonnee = TypeDonnee.fromValeur(columnDefinitionsMap.get(criterion.getNomColonne().toLowerCase()).getTypeDonnee())) == null) { errors.add("Le type de la colonne '" + criterion.getNomColonne() + "est introuvable"); } else if (!validateCriteriaEntityValue(criterion, typeDonnee)) { errors.add("Type de données de la colonne " + criterion.getNomColonne() + " incorrect"); } } else { if (criterion.getCriteriaLogicConnector() == null) { errors.add("Le connecteur logique est absent"); } for (CriteriaEntity c : criterion.getSubCriterias()) { errors.addAll(validate(c, columnDefinitionsMap)); } } } return errors; } private boolean validateCriteriaNomColonne(Map columnDefinitionsMap, CriteriaEntity c) { return c.getNomColonne() != null && !c.getNomColonne().isEmpty() && columnDefinitionsMap.containsKey(c.getNomColonne().toLowerCase()); } private boolean validateCriteriaEntityValue(CriteriaEntity criteriaEntity, TypeDonnee typeDonnee) { switch (criteriaEntity.getOperateur()) { case LIKE: return (criteriaEntity.getCriteriaValue() instanceof String) && columTypeIsString(typeDonnee); case IN: case NOT_IN: return (criteriaEntity.getCriteriaValue() instanceof List) && elementsOfList((List) criteriaEntity.getCriteriaValue(), typeDonnee); case LOWER_OR_EQUALS_THAN: case LOWER_THAN: case GREATER_OR_EQUALS_THAN: case GREATER_THAN: case EQUALS: case NOT_EQUALS: return (criteriaEntity.getCriteriaValue() instanceof Comparable) && criteriaValueHasCorrectType(criteriaEntity.getCriteriaValue(), typeDonnee); case BETWEEN: case NOT_BETWEEN: BetweenOperatorValues betweenOperatorValues = getBetweenOperatorValues(criteriaEntity.getCriteriaValue()); criteriaEntity.setCriteriaValue(betweenOperatorValues); return betweenOperatorValues != null && criteriaValueHasCorrectType(betweenOperatorValues.getLowerBound(), typeDonnee) && criteriaValueHasCorrectType(betweenOperatorValues.getUpperBound(), typeDonnee) && betweenOperatorValuesAreCorrect(betweenOperatorValues, typeDonnee); case IS_NULL: case IS_NOT_NULL: return criteriaEntity.getCriteriaValue() == null; } return false; } @Override public BetweenOperatorValues getBetweenOperatorValues(Object value) { BetweenOperatorValues betweenOperatorValues = null; if (!(value instanceof LinkedHashMap)) { throw new CommonApplicationValidationException("LinkedHashMap est attendu"); } LinkedHashMap map = (LinkedHashMap) value; String lowerBound = null; String upperBound = null; for (String key : map.keySet()) { if (key.equalsIgnoreCase("lowerBound")) { lowerBound = map.get(key); } if (key.equalsIgnoreCase("upperBound")) { upperBound = map.get(key); } } StringBuilder message = new StringBuilder(""); if (lowerBound == null) { message.append("Borne inférieure absente\n"); } if (upperBound == null) { message.append("Borne supérieure absente"); } if (message.length() > 0) { throw new CommonApplicationValidationException(message.toString()); } betweenOperatorValues = new BetweenOperatorValues(lowerBound, upperBound); return betweenOperatorValues; } /** * Vérifier que le borne inférieure est bel et bien inférieure à la borne * supérieure * * @param betweenOperatorValues * @param columnType * @return */ private boolean betweenOperatorValuesAreCorrect(BetweenOperatorValues betweenOperatorValues, TypeDonnee typeDonnee) { boolean result = false; switch (typeDonnee) { case NUMERIQUE: try { Long lowerBound = Long.valueOf(betweenOperatorValues.getLowerBound().toString()); Long upperBound = Long.valueOf(betweenOperatorValues.getUpperBound().toString()); result = lowerBound <= upperBound; if (!result) { throw new CommonApplicationValidationException("La borne inférieure ne peut être supérieure à la borne supérieure"); } } catch (NumberFormatException ex) { } break; case DECIMAL: try { BigDecimal lowerBound = new BigDecimal(betweenOperatorValues.getLowerBound().toString()); BigDecimal upperBound = new BigDecimal(betweenOperatorValues.getUpperBound().toString()); result = lowerBound.compareTo(upperBound) <= 0; if (!result) { throw new CommonApplicationValidationException("La borne inférieure ne peut être supérieure à la borne supérieure"); } } catch (NumberFormatException ex) { } break; case DATE: try { Timestamp lowerBound = Timestamp.valueOf(LocalDateTime.parse(betweenOperatorValues.getLowerBound().toString())); Timestamp upperBound = Timestamp.valueOf(LocalDateTime.parse(betweenOperatorValues.getUpperBound().toString())); result = lowerBound.before(upperBound); if (!result) { throw new CommonApplicationValidationException("La borne inférieure ne peut être supérieure à la borne supérieure"); } } catch (DateTimeParseException ex) { } break; default: throw new CommonApplicationValidationException("L'opérarateur 'BETWEEN' n'est pas valable pour ce type de données " + typeDonnee); } return result; } private boolean elementsOfList(List elements, TypeDonnee typeDonnee) { boolean result = true; for (Object elt : elements) { result = criteriaValueHasCorrectType(elt, typeDonnee); if (!result) { break; } } return result; } private boolean criteriaValueHasCorrectType(Object value, TypeDonnee typeDonnee) { boolean result = false; switch (typeDonnee) { case NUMERIQUE: try { Long.valueOf(value.toString()); result = true; } catch (NumberFormatException ex) { } break; case DECIMAL: try { new BigDecimal(value.toString()); result = true; } catch (Exception ex) { } break; case DATE: try { Timestamp.valueOf(LocalDateTime.parse(value.toString())); result = true; } catch (IllegalArgumentException ex) { } break; case ALPHANUMERIQUE: result = value instanceof String; break; default: throw new CommonApplicationValidationException("Type de données inconnu"); } return result; } private boolean columTypeIsString(TypeDonnee typeDonnee) { return typeDonnee.equals(TypeDonnee.ALPHANUMERIQUE); } private boolean isNotEmptyCriteria(CriteriaEntity c) { return c.getNomColonne() != null && !c.getNomColonne().isEmpty() && c.getOperateur() != null || c.getSubCriterias() != null && !c.getSubCriterias().isEmpty(); } }