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

com.emv.qrcode.validators.cpm.CommonDataTemplateValidator Maven / Gradle / Ivy

There is a newer version: 0.1.2
Show newest version
package com.emv.qrcode.validators.cpm;

import static br.com.fluentvalidator.function.FunctionBuilder.of;
import static br.com.fluentvalidator.predicate.ComparablePredicate.betweenInclusive;
import static br.com.fluentvalidator.predicate.ComparablePredicate.equalTo;
import static br.com.fluentvalidator.predicate.ComparablePredicate.lessThanOrEqual;
import static br.com.fluentvalidator.predicate.LogicalPredicate.not;
import static br.com.fluentvalidator.predicate.ObjectPredicate.nullValue;
import static br.com.fluentvalidator.predicate.StringPredicate.stringEmptyOrNull;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;

import com.emv.qrcode.core.model.cpm.BERTLV;
import com.emv.qrcode.core.model.cpm.BERTag;
import com.emv.qrcode.model.cpm.ApplicationTemplate;
import com.emv.qrcode.model.cpm.CommonDataTemplate;
import com.emv.qrcode.model.cpm.ConsumerPresentedMode;

import br.com.fluentvalidator.AbstractValidator;
import br.com.fluentvalidator.context.Error;
import br.com.fluentvalidator.handler.HandlerInvalidField;
import br.com.fluentvalidator.predicate.PredicateBuilder;

// @formatter:off
class CommonDataTemplateValidator extends AbstractValidator {

  private final Function cpm = fn -> getPropertyOnContext("cpm", ConsumerPresentedMode.class);

  @Override
  public void rules() {

    failFastRule();

    ruleFor(cdt -> cdt)
      .must(validateDuplicateTags())
        .handlerInvalidField(new HandlerInvalidDuplicateTags())
        .critical();

    ruleFor("ApplicationDefinitionFileName", CommonDataTemplate::getApplicationDefinitionFileName)
      .must(not(stringEmptyOrNull(BERTLV::getStringValue)))
        .when(not(nullValue()))
        .withMessage("ApplicationDefinitionFileName value must be present")
        .withAttempedValue(of(BERTLV::getStringValue))
      .must(betweenInclusive(BERTLV::getLength, 5, 16))
        .when(not(nullValue()))
        .withMessage("ApplicationDefinitionFileName value size must be between five and sixteen")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("ApplicationLabel", CommonDataTemplate::getApplicationLabel)
      .must(betweenInclusive(BERTLV::getLength, 1, 16))
        .when(not(nullValue()))
        .withMessage("ApplicationLabel value size must be between five and sixteen")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("ApplicationPAN", CommonDataTemplate::getApplicationPAN)
      .must(lessThanOrEqual(BERTLV::getLength, 10))
        .when(not(nullValue()))
        .withMessage("ApplicationPAN value size must be less than or equal ten")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("ApplicationVersionNumber", CommonDataTemplate::getApplicationVersionNumber)
      .must(equalTo(BERTLV::getLength, 2))
        .when(not(nullValue()))
        .withMessage("ApplicationVersionNumber value size must be equal two")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("CardholderName", CommonDataTemplate::getCardholderName)
      .must(betweenInclusive(BERTLV::getLength, 2, 26))
        .when(not(nullValue()))
        .withMessage("CardholderName value size must be between two and twenty-six")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("Last4DigitsOfPAN", CommonDataTemplate::getLast4DigitsOfPAN)
      .must(equalTo(BERTLV::getLength, 2))
        .when(not(nullValue()))
        .withMessage("Last4DigitsOfPAN value size must be equal two")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("LanguagePreference", CommonDataTemplate::getLanguagePreference)
      .must(betweenInclusive(BERTLV::getLength, 2, 8))
        .when(not(nullValue()))
        .withMessage("LanguagePreference value size must be between two and eight")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("Track2EquivalentData", CommonDataTemplate::getTrack2EquivalentData)
      .must(lessThanOrEqual(BERTLV::getLength, 19))
        .when(not(nullValue()))
        .withMessage("Track2EquivalentData value size must be less than or equal nineteen")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("TokenRequestorID", CommonDataTemplate::getTokenRequestorID)
      .must(equalTo(BERTLV::getLength, 6))
        .when(not(nullValue()))
        .withMessage("TokenRequestorID value size must be equal six")
        .withAttempedValue(of(BERTLV::getStringValue));

    ruleFor("PaymentAccountReference", CommonDataTemplate::getPaymentAccountReference)
      .must(equalTo(BERTLV::getLength, 29))
        .when(not(nullValue()))
        .withMessage("PaymentAccountReference value size must be equal twenty-nine")
        .withAttempedValue(of(BERTLV::getStringValue));

  }

  private final class HandlerInvalidDuplicateTags implements HandlerInvalidField {
    @Override
    public Collection handle(final CommonDataTemplate attemptedValue) {
      final ConsumerPresentedMode consumerPresentedMode = cpm.apply(attemptedValue);

      final Set tags = new HashSet<>();
      final Set errors = new HashSet<>();

      for (final ApplicationTemplate applicationTemplate : consumerPresentedMode.getApplicationTemplates()) {
        tags.addAll(applicationTemplate.getAdditionalDataMap().keySet());
      }

      for (final Entry entry : attemptedValue.getAdditionalDataMap().entrySet()) {
        final BERTag tag = entry.getKey();
        final BERTLV value = entry.getValue();
        if (tags.contains(tag)) {
          errors.add(Error.create("tag", "Duplicate definition tag on CommonDataTemplate", tag.toString(), value.getStringValue()));
        }
      }

      return new LinkedList<>(errors);
    }
  }

  private Predicate validateDuplicateTags() {
    return PredicateBuilder.from(not(nullValue())).and(cdt -> {
      final ConsumerPresentedMode consumerPresentedMode = cpm.apply(cdt);

      final Set tags = new HashSet<>();

      for (final ApplicationTemplate applicationTemplate : consumerPresentedMode.getApplicationTemplates()) {
        tags.addAll(applicationTemplate.getAdditionalDataMap().keySet());
      }

      for (final BERTag tag : cdt.getAdditionalDataMap().keySet()) {
        if (tags.contains(tag)) {
          return false;
        }
      }

      return true;
    });
  }

}
// @formatter:on




© 2015 - 2025 Weber Informatics LLC | Privacy Policy