Package br.com.caelum.stella.validation

Source Code of br.com.caelum.stella.validation.CPFValidator

package br.com.caelum.stella.validation;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import br.com.caelum.stella.DigitoPara;
import br.com.caelum.stella.MessageProducer;
import br.com.caelum.stella.SimpleMessageProducer;
import br.com.caelum.stella.ValidationMessage;
import br.com.caelum.stella.format.CPFFormatter;
import br.com.caelum.stella.validation.error.CPFError;

/**
* Verifica se uma cadeia (String) é válida para o documento de CPF (Cadastro de
* Pessoa Física).
*
* @author Leonardo Bessa
*/
public class CPFValidator implements Validator<String> {

  public static final Pattern FORMATED = Pattern.compile("(\\d{3})[.](\\d{3})[.](\\d{3})-(\\d{2})");
  public static final Pattern UNFORMATED = Pattern.compile("(\\d{3})(\\d{3})(\\d{3})(\\d{2})");

  private final boolean isFormatted;
  private final boolean isIgnoringRepeatedDigits;
  private final MessageProducer messageProducer;

  /**
   * Construtor padrão de validador de CPF. Este considera, por padrão, que as
   * cadeias não estão formatadas e utiliza um {@linkplain SimpleMessageProducer}
   * para geração de mensagens.
   */
  public CPFValidator() {
    this(new SimpleMessageProducer(), false, false);
  }

  /**
   * Construtor de validador de CPF. O validador utiliza um
   * {@linkplain SimpleMessageProducer} para geração de mensagens. Leva em
   * conta se o valor está ou não formatado.
   *
   * @param isFormatted
   *            considera cadeia no formato de CPF:"ddd.ddd.ddd-dd" onde "d" é
   *            um dígito decimal.
   */
  public CPFValidator(boolean isFormatted) {
    this(new SimpleMessageProducer(), isFormatted, false);
  }

  /**
   * Construtor de validador de CPF. O validador utiliza um
   *
   * @param isFormatted
   *            indica se o CPF está formatado.
   * @param isIgnoringRepeatedDigits
   *            condição para ignorar cadeias de CPF com todos os dígitos
   *            repetidos. {@linkplain SimpleMessageProducer} para geração de
   *            mensagens.
   */
  public CPFValidator(boolean isFormatted, boolean isIgnoringRepeatedDigits) {
    this(new SimpleMessageProducer(), isFormatted, isIgnoringRepeatedDigits);
  }

  /**
   * <p>
   * Construtor do Validador de CPF. Leva em consideração se o valor está
   * formatado.
   * </p>
   * <p>
   * Por padrão o validador criado não aceita cadeias de CPF com todos os
   * dígitos repetidos, quando todas as outras condições de validação são
   * aceitas. Para considerar estes documentos válidos use o construtor
   * {@link #CPFValidator(MessageProducer, boolean, boolean)} com a váriavel
   * {@linkplain #isIgnoringRepeatedDigits} em <code>true</code>.
   * </p>
   *
   * @param messageProducer
   *            produtor de mensagem de erro.
   * @param isFormatted
   *            considera cadeia no formato de CPF: "ddd.ddd.ddd-dd" onde "d"
   *            é um dígito decimal.
   */
  public CPFValidator(MessageProducer messageProducer, boolean isFormatted) {
    this(messageProducer, isFormatted, false);
  }

  /**
   * @param messageProducer
   *            produtor de mensagem de erro.
   * @param isFormatted
   *            condição para considerar cadeia no formato de CPF:
   *            "ddd.ddd.ddd-dd" onde "d" é um dígito decimal.
   * @param isIgnoringRepeatedDigits
   *            condição para ignorar cadeias de CPF com todos os dígitos
   *            repetidos.
   */
  public CPFValidator(MessageProducer messageProducer, boolean isFormatted, boolean isIgnoringRepeatedDigits) {
    this.messageProducer = messageProducer;
    this.isFormatted = isFormatted;
    this.isIgnoringRepeatedDigits = isIgnoringRepeatedDigits;
  }

  /**
   * Valida se a cadeia está de acordo com as regras de um CPF.
   *
   * @see br.com.caelum.stella.validation.Validator#assertValid(java.lang.Object)
   * @return <code>true</code> se a cadeia é válida ou é nula;
   *         <code>false</code> caso contrario.
   */
  private List<ValidationMessage> getInvalidValues(String cpf) {

    List<ValidationMessage> errors = new ArrayList<ValidationMessage>();

    if (cpf != null) {
      if (isFormatted && !FORMATED.matcher(cpf).matches()) {
        errors.add(messageProducer.getMessage(CPFError.INVALID_FORMAT));
      }

      String unformatedCPF = null;
      try {
        unformatedCPF = new CPFFormatter().unformat(cpf);
      } catch (IllegalArgumentException e) {
        errors.add(messageProducer.getMessage(CPFError.INVALID_DIGITS));
        return errors;
      }

      if (unformatedCPF.length() != 11 || !unformatedCPF.matches("[0-9]*")) {
        errors.add(messageProducer.getMessage(CPFError.INVALID_DIGITS));
      }

      if ((!isIgnoringRepeatedDigits) && hasAllRepeatedDigits(unformatedCPF)) {
        errors.add(messageProducer.getMessage(CPFError.REPEATED_DIGITS));
      }

      String cpfSemDigito = unformatedCPF.substring(0, unformatedCPF.length() - 2);
      String digitos = unformatedCPF.substring(unformatedCPF.length() - 2);

      String digitosCalculados = calculaDigitos(cpfSemDigito);

      if (!digitos.equals(digitosCalculados)) {
        errors.add(messageProducer.getMessage(CPFError.INVALID_CHECK_DIGITS));
      }
    }
    return errors;
  }

  /**
   * Faz o cálculo dos digitos usando a lógica de CPF
   *
   * @return String os dois dígitos calculados.
   */
  private String calculaDigitos(String cpfSemDigito) {
    DigitoPara digitoPara = new DigitoPara(cpfSemDigito);
      digitoPara.comMultiplicadoresDeAte(2, 11).complementarAoModulo().trocandoPorSeEncontrar("0",10,11).mod(11);

    String digito1 = digitoPara.calcula();
    digitoPara.addDigito(digito1);
    String digito2 = digitoPara.calcula();
   
    return digito1 + digito2;
  }

  private boolean hasAllRepeatedDigits(String cpf) {
    for (int i = 1; i < cpf.length(); i++) {
      if (cpf.charAt(i) != cpf.charAt(0)) {
        return false;
      }
    }
    return true;
  }

  @Override
  public boolean isEligible(String value) {
    if (value == null) {
      return false;
    }
    boolean result;
    if (isFormatted) {
      result = FORMATED.matcher(value).matches();
    } else {
      result = UNFORMATED.matcher(value).matches();
    }
    return result;
  }

  @Override
  public void assertValid(String cpf) {
    List<ValidationMessage> errors = getInvalidValues(cpf);
    if (!errors.isEmpty()) {
      throw new InvalidStateException(errors);
    }
  }

  @Override
  public List<ValidationMessage> invalidMessagesFor(String cpf) {
    return getInvalidValues(cpf);
  }

}
TOP

Related Classes of br.com.caelum.stella.validation.CPFValidator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.