001/*
002 * Copyright 2020-2021 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.api.model.crawler;
017
018import java.util.List;
019import java.util.Objects;
020import java.util.StringJoiner;
021
022import com.fasterxml.jackson.annotation.JsonCreator;
023import com.fasterxml.jackson.annotation.JsonProperty;
024
025/**
026 * A container class used to capture the information necessary for a generic validation report.
027 * <p/>
028 * This is written with the intention to capture the information about e.g. the sample core or the taxon core of a
029 * DwC-A.
030 * <p/>
031 * Generic validation includes information about the number of records checked, whether all records where checked
032 * (implementations often cannot check everything) and information about the validity of primary keys.
033 */
034public class GenericValidationReport {
035  // the number of records checked in the validation
036  private final int checkedRecords;
037
038  // false if we had to stop at an implementation imposed limit (e.g. due to memory restrictions)
039  private final boolean allRecordsChecked;
040
041  // a sample of duplicate ids which are expected to be unique (i.e. primary keys)
042  private final List<String> duplicateIds;
043
044  // a sample of data file line numbers with records missing a core identifier
045  private final List<Integer> rowNumbersMissingId;
046
047  // if the archive is not valid this will hold a readable reason
048  private String invalidationReason;
049
050  // is this archive valid
051  private final boolean valid;
052
053  @JsonCreator
054  public GenericValidationReport(
055    @JsonProperty("checkedRecords") int checkedRecords,
056    @JsonProperty("allRecordsChecked") boolean allRecordsChecked,
057    @JsonProperty("duplicateIds") List<String> duplicateIds,
058    @JsonProperty("rowNumbersMissingId") List<Integer> rowNumbersMissingId
059  ) {
060    this.checkedRecords = checkedRecords;
061    this.allRecordsChecked = allRecordsChecked;
062    this.duplicateIds = Objects.requireNonNull(duplicateIds, "duplicateIds cannot be null");
063    this.rowNumbersMissingId = Objects.requireNonNull(rowNumbersMissingId, "rowNumbersMissingId cannot be null");
064    this.valid = validate();
065  }
066
067  private boolean validate() {
068    if (!duplicateIds.isEmpty()) {
069      invalidationReason = "Non unique core ids";
070      return false;
071    }
072    if (!rowNumbersMissingId.isEmpty()) {
073      invalidationReason = "Missing core ids";
074      return false;
075    }
076    return true;
077  }
078
079  public int getCheckedRecords() {
080    return checkedRecords;
081  }
082
083  public boolean isAllRecordsChecked() {
084    return allRecordsChecked;
085  }
086
087  public List<String> getDuplicateIds() {
088    return duplicateIds;
089  }
090
091  public List<Integer> getRowNumbersMissingId() {
092    return rowNumbersMissingId;
093  }
094
095  public String getInvalidationReason() {
096    return invalidationReason;
097  }
098
099  public boolean isValid() {
100    return valid;
101  }
102
103  @Override
104  public boolean equals(Object o) {
105    if (this == o) {
106      return true;
107    }
108    if (o == null || getClass() != o.getClass()) {
109      return false;
110    }
111    GenericValidationReport that = (GenericValidationReport) o;
112    return checkedRecords == that.checkedRecords &&
113      allRecordsChecked == that.allRecordsChecked &&
114      valid == that.valid &&
115      Objects.equals(duplicateIds, that.duplicateIds) &&
116      Objects.equals(rowNumbersMissingId, that.rowNumbersMissingId) &&
117      Objects.equals(invalidationReason, that.invalidationReason);
118  }
119
120  @Override
121  public int hashCode() {
122    return Objects.hash(checkedRecords, allRecordsChecked, duplicateIds, rowNumbersMissingId,
123      invalidationReason, valid);
124  }
125
126  @Override
127  public String toString() {
128    return new StringJoiner(", ", GenericValidationReport.class.getSimpleName() + "[", "]")
129      .add("checkedRecords=" + checkedRecords)
130      .add("allRecordsChecked=" + allRecordsChecked)
131      .add("duplicateIds=" + duplicateIds)
132      .add("rowNumbersMissingId=" + rowNumbersMissingId)
133      .add("invalidationReason='" + invalidationReason + "'")
134      .add("valid=" + valid)
135      .toString();
136  }
137}