Repository: corona-warn-app/cwa-server
File: services/submission/src/main/java/app/coronawarn/server/services/submission/checkins/EventCheckinDataFilter.java (Java)

Code before:
  /**
   * Creates am instance.
   */
  public EventCheckinDataFilter(SubmissionServiceConfig submissionServiceConfig,
      PreDistributionTrlValueMappingProvider trlValueMappingProvider) {
    this.submissionServiceConfig = submissionServiceConfig;
    this.trlValueMappingProvider = trlValueMappingProvider;
  }

  /**
   * Return a filtered list of checkin data based on the following criteria:
   * <li>Filter out checkins with TRL values that are mapped to 0 ( as per Risk calculation paramters app config) </li>
   * <li>Filter out checkins which have checkout time in the past further than 15 days (app config)</li>
   * <li>Filter out checkins which are in the future</li>
   * <li>Filter out checkins which have trace location signatures that can not be verified</li>.
   */
  public List<CheckIn> filter(List<CheckIn> checkins) {
    AtomicInteger checkinsPickedAfterTrlFiltering = new AtomicInteger();
    AtomicInteger checkinsPickedAfterOldFiltering = new AtomicInteger();
    AtomicInteger checkinsPickedAfterFutureFiltering = new AtomicInteger();
    var filtered = checkins.stream()
        .filter(this::filterOutZeroTransmissionRiskLevel)
        .peek(k -> checkinsPickedAfterTrlFiltering.incrementAndGet())
        .filter(this::filterOutOldCheckins)
        .peek(k -> checkinsPickedAfterOldFiltering.incrementAndGet())
        .filter(this::filterOutFutureCheckins)
        .peek(k -> checkinsPickedAfterFutureFiltering.incrementAndGet())
        .collect(Collectors.toList());

    logger.debug("Filtering of {} checkins started", checkins.size());
    logger.debug("{} checkins remaining after filtering out zero TRLs", checkinsPickedAfterOldFiltering.get());
    logger.debug("{} checkins remaining after filtering out old checkins", checkinsPickedAfterFutureFiltering.get());
    logger.debug("{} checkins remaining after filtering out future checkins", checkinsPickedAfterFutureFiltering.get());

    return filtered;
  }


  boolean filterOutZeroTransmissionRiskLevel(CheckIn checkin) {
    return !mapsTo(checkin.getTransmissionRiskLevel(), 0.0d);
  }

  boolean filterOutOldCheckins(CheckIn checkin) {
    Integer acceptableTimeframeInDays = submissionServiceConfig.getAcceptedEventDateThresholdDays();
    int threshold = TEN_MINUTE_INTERVAL_DERIVATION.apply(LocalDateTime.ofInstant(Instant.now(), UTC)
        .minusDays(acceptableTimeframeInDays).toEpochSecond(UTC));
    return threshold < checkin.getEndIntervalNumber();
  }

  boolean filterOutFutureCheckins(CheckIn checkin) {
    int threshold = TEN_MINUTE_INTERVAL_DERIVATION

Review comment (bug):
Peek is not intended for code with side-effects and this will most likely break in Java 9 (see [here](https://stackoverflow.com/a/48221925)). Although it doesn't look as nice as your full-on stream solution, you should probably consider something like this:

```Java
int checkinsBeforeFiltering = checkins.size();

var List<CheckIn> filtered = checkins.stream().filter(this::filterOutZeroTransmissionRiskLevel).collect(Collectors.toList());
int checkinsPickedAfterTrlFiltering = filtered.size();

filtered = checkins.stream().filter(this::filterOutOldCheckins).collect(Collectors.toList());
int checkinsPickedAfterOldFiltering = filtered.size();

filtered = checkins.stream().filter(this::filterOutFutureCheckins).collect(Collectors.toList());
int checkinsPickedAfterFutureFiltering = filtered.size();
```


Code after:
   * Creates am instance.
   */
  public EventCheckinDataFilter(SubmissionServiceConfig submissionServiceConfig,
      PreDistributionTrlValueMappingProvider trlValueMappingProvider) {
    this.submissionServiceConfig = submissionServiceConfig;
    this.trlValueMappingProvider = trlValueMappingProvider;
  }

  /**
   * Return a filtered list of checkin data based on the following criteria:
   * <li>Filter out checkins with TRL values that are mapped to 0 ( as per Risk calculation paramters app config) </li>
   * <li>Filter out checkins which have checkout time in the past further than 15 days (app config)</li>
   * <li>Filter out checkins which are in the future</li>
   * <li>Filter out checkins which have trace location signatures that can not be verified</li>.
   */
  public List<CheckIn> filter(List<CheckIn> checkins) {
    AtomicInteger checkinsPickedAfterTrlFiltering = new AtomicInteger();
    AtomicInteger checkinsPickedAfterOldFiltering = new AtomicInteger();
    AtomicInteger checkinsPickedAfterFutureFiltering = new AtomicInteger();
    final var filtered = checkins.stream()
        .filter(this::filterOutZeroTransmissionRiskLevel)
        .peek(k -> checkinsPickedAfterTrlFiltering.incrementAndGet())
        .filter(this::filterOutOldCheckins)
        .peek(k -> checkinsPickedAfterOldFiltering.incrementAndGet())
        .filter(this::filterOutFutureCheckins)
        .peek(k -> checkinsPickedAfterFutureFiltering.incrementAndGet())
        .collect(Collectors.toList());

    logger.debug("Filtering of {} checkins started", checkins.size());
    logger.debug("{} checkins remaining after filtering out zero TRLs", checkinsPickedAfterOldFiltering.get());
    logger.debug("{} checkins remaining after filtering out old checkins", checkinsPickedAfterFutureFiltering.get());
    logger.debug("{} checkins remaining after filtering out future checkins", checkinsPickedAfterFutureFiltering.get());

    return filtered;
  }


  boolean filterOutZeroTransmissionRiskLevel(CheckIn checkin) {
    return !mapsTo(checkin.getTransmissionRiskLevel(), 0.0d);
  }

  boolean filterOutOldCheckins(CheckIn checkin) {
    Integer acceptableTimeframeInDays = submissionServiceConfig.getAcceptedEventDateThresholdDays();
    int threshold = TEN_MINUTE_INTERVAL_DERIVATION.apply(LocalDateTime.ofInstant(Instant.now(), UTC)
        .minusDays(acceptableTimeframeInDays).toEpochSecond(UTC));
    return threshold < checkin.getEndIntervalNumber();
  }

  boolean filterOutFutureCheckins(CheckIn checkin) {
    int threshold = TEN_MINUTE_INTERVAL_DERIVATION
        .apply(LocalDateTime.ofInstant(Instant.now(), UTC).toEpochSecond(UTC));