class EncryptionKeyRotator {

  public void rotate() {
    final long start = System.currentTimeMillis();
    LOGGER.info("Starting encryption key rotation.");
    int rotatedRecordCount = 0;

    final long startingNotRotatedRecordCount = encryptedValueDataService
      .countAllByCanaryUuid(keySet.getActive().getUuid());

    final List<UUID> inactiveCanaries = keySet.getInactiveUuids();
    Slice<EncryptedValue> valuesEncryptedByOldKey = encryptedValueDataService
      .findByCanaryUuids(inactiveCanaries);
    while (valuesEncryptedByOldKey.hasContent()) {
      for (final EncryptedValue value : valuesEncryptedByOldKey.getContent()) {
        try {
          encryptedValueDataService.rotate(value);
          rotatedRecordCount++;
        } catch (final KeyNotFoundException e) {
          LOGGER.error("key not found for value, unable to rotate");
        }
      }
      valuesEncryptedByOldKey = encryptedValueDataService.findByCanaryUuids(inactiveCanaries);
    }

    final long finish = System.currentTimeMillis();
    final long duration = finish - start;
    final long endingNotRotatedRecordCount = startingNotRotatedRecordCount - rotatedRecordCount;

    if (rotatedRecordCount == 0 && endingNotRotatedRecordCount == 0) {
      LOGGER.info("Found no records in need of encryption key rotation.");
    } else {
      LOGGER.info("Finished encryption key rotation in " + duration + " milliseconds. Details:");
      LOGGER.info("  Successfully rotated " + rotatedRecordCount + " item(s)");
      LOGGER.info("  Skipped " + endingNotRotatedRecordCount
        + " item(s) due to missing master encryption key(s).");
    }

    encryptionKeyCanaryMapper.delete(inactiveCanaries);
  }

  @Autowired  EncryptionKeyRotator(
    final EncryptedValueDataService encryptedValueDataService,
    final EncryptionKeyCanaryMapper encryptionKeyCanaryMapper,
    final EncryptionKeySet keySet
  );

}