/**
   * Applies a list of change criteria groups to an origin entry. Note that the returned value, if
   * not null, is a reference to the same instance as the origin entry passed in (i.e. intentional
   * side effect)
   *
   * @param entry origin entry
   * @param matchCriteriaOnly if true and no criteria match, then this method will return null
   * @param changeCriteriaGroups list of change criteria groups to apply
   * @return the passed in entry instance, or null (see above)
   */
  public static OriginEntryFull applyCriteriaToEntry(
      OriginEntryFull entry,
      boolean matchCriteriaOnly,
      List<CorrectionChangeGroup> changeCriteriaGroups) {
    if (matchCriteriaOnly && !doesEntryMatchAnyCriteriaGroups(entry, changeCriteriaGroups)) {
      return null;
    }

    for (CorrectionChangeGroup ccg : changeCriteriaGroups) {
      int matches = 0;
      for (CorrectionCriteria cc : ccg.getCorrectionCriteria()) {
        if (entryMatchesCriteria(cc, entry)) {
          matches++;
        }
      }

      // If they all match, change it
      if (matches == ccg.getCorrectionCriteria().size()) {
        for (CorrectionChange change : ccg.getCorrectionChange()) {
          // Change the row
          entry.setFieldValue(change.getCorrectionFieldName(), change.getCorrectionFieldValue());
        }
      }
    }
    return entry;
  }
 /**
  * When a document is about to be saved, this will check if it is valid, meaning that the field
  * name and value are both blank
  *
  * @param correctionCriteria validated correction criteria
  * @return true if correction change is valid for saving (i.e. correction change is null or
  *     correction field name and field value are blank)
  */
 public static boolean validCorrectionChangeForSaving(CorrectionChange correctionChange) {
   return correctionChange == null
       || (StringUtils.isBlank(correctionChange.getCorrectionFieldName())
           && StringUtils.isBlank(correctionChange.getCorrectionFieldValue()));
 }