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

com.supwisdom.spreadsheet.mapper.validation.engine.CellGroupValidationEngine Maven / Gradle / Ivy

package com.supwisdom.spreadsheet.mapper.validation.engine;

import com.supwisdom.spreadsheet.mapper.m2f.excel.ExcelMessageWriteStrategies;
import com.supwisdom.spreadsheet.mapper.model.core.Cell;
import com.supwisdom.spreadsheet.mapper.model.core.Row;
import com.supwisdom.spreadsheet.mapper.model.meta.FieldMeta;
import com.supwisdom.spreadsheet.mapper.model.meta.SheetMeta;
import com.supwisdom.spreadsheet.mapper.model.msg.Message;
import com.supwisdom.spreadsheet.mapper.model.msg.MessageBean;
import com.supwisdom.spreadsheet.mapper.validation.validator.Dependant;
import com.supwisdom.spreadsheet.mapper.validation.validator.cell.CellValidator;
import com.supwisdom.spreadsheet.mapper.validation.validator.unioncell.UnionCellValidator;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 针对{@link Dependant}的两个实现{@link CellValidator}、{@link UnionCellValidator}的校验引擎。
 * Created by hanwen on 2017/1/6.
 */
public class CellGroupValidationEngine {

  private static final Logger LOGGER = LoggerFactory.getLogger(CellGroupValidationEngine.class);

  private final List cellValidators;

  private final SheetMeta sheetMeta;

  // group -> validators
  private transient LinkedHashMap> cellValidatorGroups = new LinkedHashMap<>();

  // group -> dependsOn
  private transient LinkedHashMap> dependencyTree = new LinkedHashMap<>();

  // group -> validator -> columns
  private transient Map>> group2Validator2Columns = new HashMap<>();

  private transient Map result = new HashMap<>();

  private transient List errorMessages = new ArrayList<>();

  private enum ValidateResult {
    PASS, FAIL, SKIP
  }

  public CellGroupValidationEngine(SheetMeta sheetMeta, List cellValidators) {

    if (cellValidators != null) {
      this.cellValidators = new ArrayList<>(cellValidators);
    } else {
      this.cellValidators = Collections.emptyList();
    }
    this.sheetMeta = sheetMeta;

  }

  /**
   * 初始化工作,主要是计算哪些field对应哪些CellValidator/UnionCellValidator
   */
  public void initialize() {

    this.cellValidatorGroups = buildCellValidatorGroups(cellValidators);
    this.dependencyTree = buildDependencyTree(cellValidatorGroups);
    assertNoMissingGroup(dependencyTree);
    assertNoCyclic(dependencyTree);
    this.group2Validator2Columns = buildGroup2Validator2Columns(cellValidatorGroups);

  }

  /**
   * 构建 CellValidator 分组
   *
   * @param cellValidators {@link CellValidator}或{@link UnionCellValidator}
   * @return 分组
   */
  protected LinkedHashMap> buildCellValidatorGroups(List cellValidators) {

    LinkedHashMap> group2Validators = new LinkedHashMap<>();

    for (Dependant cellValidator : cellValidators) {

      String group = cellValidator.getGroup();
      if (!group2Validators.containsKey(group)) {
        group2Validators.put(group, new ArrayList());
      }
      group2Validators.get(group).add(cellValidator);

    }

    return group2Validators;
  }

  /**
   * 构建分组依赖树
   *
   * @param group2Validators Validator分组
   * @return 依赖关系
   */
  protected LinkedHashMap> buildDependencyTree(
      LinkedHashMap> group2Validators) {

    LinkedHashMap> groupDependencies = new LinkedHashMap<>();

    for (Map.Entry> entry : group2Validators.entrySet()) {
      String key = entry.getKey();
      groupDependencies.put(key, new LinkedHashSet());

      for (Dependant dependant : entry.getValue()) {

        Set dependsOn = dependant.getDependsOn();
        if (CollectionUtils.isNotEmpty(dependsOn)) {

          groupDependencies.get(key).addAll(dependsOn);
        }
      }
    }

    return groupDependencies;

  }

  /**
   * 断言不存在丢失的group
   *
   * @param dependencyTree 依赖关系
   */
  protected void assertNoMissingGroup(LinkedHashMap> dependencyTree) {

    Set allGroups = dependencyTree.keySet();

    for (Map.Entry> entry : dependencyTree.entrySet()) {
      String group = entry.getKey();
      Set dependsOn = entry.getValue();

      Collection missingGroups = CollectionUtils.subtract(dependsOn, allGroups);
      if (!missingGroups.isEmpty()) {

        throw new CellGroupValidationEngineException(
            "Group[" + group + "] depends on missing group(s)[" + StringUtils.join(missingGroups, ',') + "]");
      }
    }

  }

  /**
   * 断言不存在循环依赖
   *
   * @param dependencyTree 依赖关系
   */
  protected void assertNoCyclic(LinkedHashMap> dependencyTree) {

    GraphCyclicChecker graphCyclicChecker = new GraphCyclicChecker(dependencyTree);
    if (graphCyclicChecker.cycling()) {
      throw new CellGroupValidationEngineException(
          "Cyclic group dependency found: " + StringUtils.join(graphCyclicChecker.getCycle(), "->"));
    }

  }

  protected Map>> buildGroup2Validator2Columns(
      LinkedHashMap> cellValidatorGroups) {

    Map>> group2validator2columns = new HashMap<>();

    for (Map.Entry> entry : cellValidatorGroups.entrySet()) {

      String group = entry.getKey();
      List validators = entry.getValue();

      Map> validator2columns = new HashMap<>();
      group2validator2columns.put(group, validator2columns);

      for (Dependant validator : validators) {

        List columnIndices = new ArrayList<>(0);

        if (CellValidator.class.isAssignableFrom(validator.getClass())) {

          Integer columnIndex = getValidateColumnIndex(sheetMeta, (CellValidator) validator);
          if (columnIndex != null) {
            columnIndices.add(columnIndex);
          }

        } else if (UnionCellValidator.class.isAssignableFrom(validator.getClass())) {

          LinkedHashSet indices = getValidateColumnIndices(sheetMeta, (UnionCellValidator) validator);
          if (indices != null) {
            columnIndices.addAll(indices);
          }

        }

        validator2columns.put(validator, columnIndices);

      }

    }

    return group2validator2columns;
  }

  private Integer getValidateColumnIndex(SheetMeta sheetMeta, CellValidator validator) {

    String matchField = validator.getMatchField();
    FieldMeta fieldMeta = sheetMeta.getUniqueFieldMeta(matchField);
    if (fieldMeta == null) {
      LOGGER.debug("Couldn't find field [{}] for CellValidator [{}]", matchField, validator.getClass().getName());
      return null;
    }

    return fieldMeta.getColumnIndex();

  }

  private LinkedHashSet getValidateColumnIndices(SheetMeta sheetMeta, UnionCellValidator validator) {

    LinkedHashSet columnIndices = new LinkedHashSet<>(validator.getMatchFields().size());
    for (String matchField : validator.getMatchFields()) {
      FieldMeta fieldMeta = sheetMeta.getUniqueFieldMeta(matchField);
      if (fieldMeta == null) {
        LOGGER
            .debug("Couldn't find field [{}] for UnionCellValidator [{}]", matchField, validator.getClass().getName());
        return null;
      }
      columnIndices.add(fieldMeta.getColumnIndex());
    }
    return columnIndices;

  }

  public boolean validate(Row row, SheetMeta sheetMeta) {

    for (String group : dependencyTree.keySet()) {
      if (!result.containsKey(group)) {
        validateGroup(row, sheetMeta, group);
      }
    }

    return !result.values().contains(ValidateResult.FAIL);
  }

  public List getErrorMessages() {
    return errorMessages;
  }

  public void clearResults() {
    this.errorMessages.clear();
    this.result.clear();
  }

  private void validateGroup(Row row, SheetMeta sheetMeta, String group) {

    LinkedHashSet upstreamGroups = dependencyTree.get(group);

    // 上游group没有校验过的话,先校验上游group
    for (String upstreamGroup : upstreamGroups) {
      if (!result.containsKey(upstreamGroup)) {
        validateGroup(row, sheetMeta, upstreamGroup);
      }
    }

    // 判断上游group是否通过,如果没有通过则跳过
    for (String upstreamGroup : upstreamGroups) {
      if (result.get(upstreamGroup) == ValidateResult.SKIP) {
        LOGGER.debug("Skip validation group [{}] because upstream group [{}] skip", group, upstreamGroup);
        result.put(group, ValidateResult.SKIP);
        return;
      }
      if (result.get(upstreamGroup) == ValidateResult.FAIL) {
        LOGGER.debug("Skip validation group [{}] because upstream group [{}] failure", group, upstreamGroup);
        result.put(group, ValidateResult.SKIP);
        return;
      }
    }

    // 执行本group校验
    List dependants = cellValidatorGroups.get(group);

    LOGGER.debug("Start validation group [{}] {} validator(s).", group, dependants.size());

    boolean groupSucceeded = true;
    for (Dependant dependant : dependants) {

      List columnIndices = group2Validator2Columns.get(group).get(dependant);

      // group内的validator按顺序执行,只要有一个失败了,那么后面的就不会再执行了
      groupSucceeded = groupSucceeded && validateCell(row, sheetMeta, dependant, columnIndices);
      if (!groupSucceeded) {
        LOGGER.debug("validation group [{}] validation failed on [{}]", group, dependant.getClass().getName());
        break;
      }
    }
    result.put(group, groupSucceeded ? ValidateResult.PASS : ValidateResult.FAIL);

  }

  private boolean validateCell(Row row, SheetMeta sheetMeta, Dependant dependant, List columnIndices) {

    if (UnionCellValidator.class.isAssignableFrom(dependant.getClass())) {

      return executeValidator(columnIndices, sheetMeta, row, (UnionCellValidator) dependant);

    } else if (CellValidator.class.isAssignableFrom(dependant.getClass())) {

      return executeValidator(columnIndices, sheetMeta, row, (CellValidator) dependant);

    }

    LOGGER.debug("Unsupported Validator [{}]", dependant.getClass().getName());
    return false;
  }

  private boolean executeValidator(List columnIndices, SheetMeta sheetMeta, Row row,
      UnionCellValidator validator) {

    if (CollectionUtils.isEmpty(columnIndices)) {
      LOGGER.debug("Skip UnionCellValidator [{}]", validator.getClass().getName());
      return true;
    }

    List cells = new ArrayList<>();
    List fieldMetas = new ArrayList<>();

    for (Integer columnIndex : columnIndices) {
      cells.add(row.getCell(columnIndex));
      fieldMetas.add(sheetMeta.getFieldMeta(columnIndex));
    }

    boolean result = validator.validate(cells, fieldMetas);

    if (!result) {

      String errorMessage = StringUtils.defaultIfBlank(validator.getErrorMessage(), "Invalid");
      for (FieldMeta fieldMeta : fieldMetas) {
        errorMessages.add(
            new MessageBean(ExcelMessageWriteStrategies.COMMENT, StringUtils.defaultIfBlank(errorMessage, "Invalid"), row.getSheet().getIndex(),
                row.getIndex(),
                fieldMeta.getColumnIndex()));
      }

    }

    return result;

  }

  private boolean executeValidator(List columnIndices, SheetMeta sheetMeta, Row row,
      CellValidator validator) {

    if (CollectionUtils.isEmpty(columnIndices)) {
      LOGGER.debug("Skip CellValidator [{}]", validator.getClass().getName());
      return true;
    }

    int columnIndex = columnIndices.get(0);

    Cell cell = row.getCell(columnIndex);
    FieldMeta fieldMeta = sheetMeta.getFieldMeta(columnIndex);

    boolean result = validator.validate(cell, fieldMeta);

    if (!result) {

      String errorMessage = StringUtils.defaultIfBlank(validator.getErrorMessage(), "Invalid");
      errorMessages.add(
          new MessageBean(ExcelMessageWriteStrategies.COMMENT, errorMessage,
              row.getSheet().getIndex(), row.getIndex(), fieldMeta.getColumnIndex()));

    }

    return result;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy