// Path: pipeline-application/src/main/java/com/smoketurner/pipeline/application/convert/AmazonS3ObjectConverter.java
// public class AmazonS3ObjectConverter extends Converter<S3EventNotificationRecord, AmazonS3Object> {
// 
//   @Override
//   protected AmazonS3Object doForward(S3EventNotificationRecord a) {
//     final S3Entity s3 = a.getS3();
//     final S3ObjectEntity object = s3.getObject();
//     return new AmazonS3Object(
//         a.getAwsRegion(),
//         s3.getBucket().getName(),
//         object.getKey(),
//         object.getSizeAsLong(),
//         object.geteTag(),
//         object.getVersionId());
//   }
// 
//   @Override
//   protected S3EventNotificationRecord doBackward(AmazonS3Object b) {
//     final S3BucketEntity bucket = new S3BucketEntity(b.getBucketName(), null, null);
//     final S3ObjectEntity object =
//         new S3ObjectEntity(
//             b.getKey(), b.getSize(), b.getETag().orElse(null), b.getVersionId().orElse(null), null);
//     final S3Entity s3 = new S3Entity(null, bucket, object, null);
//     return new S3EventNotificationRecord(null, null, null, null, null, null, null, s3, null);
//   }
// }
// 
// Path: pipeline-application/src/main/java/com/smoketurner/pipeline/application/exceptions/AmazonS3ConstraintException.java
// public class AmazonS3ConstraintException extends Exception {
// 
//   private static final long serialVersionUID = 1L;
// 
//   public AmazonS3ConstraintException() {
//     super();
//   }
// 
//   public AmazonS3ConstraintException(final Throwable cause) {
//     super(cause);
//   }
// 
//   public AmazonS3ConstraintException(final String message) {
//     super(message);
//   }
// 
//   public AmazonS3ConstraintException(final String message, final Throwable cause) {
//     super(message, cause);
//   }
// }
// 
// Path: pipeline-application/src/main/java/com/smoketurner/pipeline/application/exceptions/AmazonS3ZeroSizeException.java
// public class AmazonS3ZeroSizeException extends Exception {
// 
//   private static final long serialVersionUID = 1L;
// 
//   public AmazonS3ZeroSizeException() {
//     super();
//   }
// 
//   public AmazonS3ZeroSizeException(final Throwable cause) {
//     super(cause);
//   }
// 
//   public AmazonS3ZeroSizeException(final String message) {
//     super(message);
//   }
// 
//   public AmazonS3ZeroSizeException(final String message, final Throwable cause) {
//     super(message, cause);
//   }
// }


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.event.S3EventNotification.S3EventNotificationRecord;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.google.common.base.Strings;
import com.smoketurner.pipeline.application.convert.AmazonS3ObjectConverter;
import com.smoketurner.pipeline.application.exceptions.AmazonS3ConstraintException;
import com.smoketurner.pipeline.application.exceptions.AmazonS3ZeroSizeException;
import java.io.IOException;
import java.util.Collections;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/*
 * Copyright © 2019 Smoke Turner, LLC (github@smoketurner.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.smoketurner.pipeline.application.core;


public class AmazonS3Downloader {

  private static final Logger LOGGER = LoggerFactory.getLogger(AmazonS3Downloader.class);
  private static final String GZIP_ENCODING = "gzip";
  private static final String GZIP_EXTENSION = ".gz";
  private final AmazonS3ObjectConverter converter = new AmazonS3ObjectConverter();
  private final AmazonS3 s3;

  /**
   * Constructor
   *
   * @param s3 Amazon S3 client
   */
  public AmazonS3Downloader(@Nonnull final AmazonS3 s3) {
    this.s3 = Objects.requireNonNull(s3);
  }

  /**
   * Retrieves a file from S3
   *
   * @param record S3 event notification record to download
   * @return S3 object
   * @throws AmazonS3ConstraintException if the etag constraints weren't met
   * @throws AmazonS3ZeroSizeException if the file size of the object is zero
   */
  public S3Object fetch(@Nonnull final S3EventNotificationRecord record)
      throws AmazonS3ConstraintException, AmazonS3ZeroSizeException {
    final AmazonS3Object object = converter.convert(Objects.requireNonNull(record));

    final GetObjectRequest request = new GetObjectRequest(object.getBucketName(), object.getKey());
    object.getVersionId().ifPresent(request::setVersionId);
    object
        .getETag()
        .ifPresent(etag -> request.setMatchingETagConstraints(Collections.singletonList(etag)));

    LOGGER.debug("Fetching key: {}/{}", object.getBucketName(), object.getKey());

    final S3Object download;
    try {
      download = s3.getObject(request);
    } catch (AmazonServiceException e) {
      LOGGER.error("Service error while fetching object from S3", e);
      throw e;
    } catch (AmazonClientException e) {
      LOGGER.error("Client error while fetching object from S3", e);
      throw e;
    }

    if (download == null) {
// Path: pipeline-application/src/main/java/com/smoketurner/pipeline/application/convert/AmazonS3ObjectConverter.java
// public class AmazonS3ObjectConverter extends Converter<S3EventNotificationRecord, AmazonS3Object> {
// 
//   @Override
//   protected AmazonS3Object doForward(S3EventNotificationRecord a) {
//     final S3Entity s3 = a.getS3();
//     final S3ObjectEntity object = s3.getObject();
//     return new AmazonS3Object(
//         a.getAwsRegion(),
//         s3.getBucket().getName(),
//         object.getKey(),
//         object.getSizeAsLong(),
//         object.geteTag(),
//         object.getVersionId());
//   }
// 
//   @Override
//   protected S3EventNotificationRecord doBackward(AmazonS3Object b) {
//     final S3BucketEntity bucket = new S3BucketEntity(b.getBucketName(), null, null);
//     final S3ObjectEntity object =
//         new S3ObjectEntity(
//             b.getKey(), b.getSize(), b.getETag().orElse(null), b.getVersionId().orElse(null), null);
//     final S3Entity s3 = new S3Entity(null, bucket, object, null);
//     return new S3EventNotificationRecord(null, null, null, null, null, null, null, s3, null);
//   }
// }
// 
// Path: pipeline-application/src/main/java/com/smoketurner/pipeline/application/exceptions/AmazonS3ConstraintException.java
// public class AmazonS3ConstraintException extends Exception {
// 
//   private static final long serialVersionUID = 1L;
// 
//   public AmazonS3ConstraintException() {
//     super();
//   }
// 
//   public AmazonS3ConstraintException(final Throwable cause) {
//     super(cause);
//   }
// 
//   public AmazonS3ConstraintException(final String message) {
//     super(message);
//   }
// 
//   public AmazonS3ConstraintException(final String message, final Throwable cause) {
//     super(message, cause);
//   }
// }
// 
// Path: pipeline-application/src/main/java/com/smoketurner/pipeline/application/exceptions/AmazonS3ZeroSizeException.java
// public class AmazonS3ZeroSizeException extends Exception {
// 
//   private static final long serialVersionUID = 1L;
// 
//   public AmazonS3ZeroSizeException() {
//     super();
//   }
// 
//   public AmazonS3ZeroSizeException(final Throwable cause) {
//     super(cause);
//   }
// 
//   public AmazonS3ZeroSizeException(final String message) {
//     super(message);
//   }
// 
//   public AmazonS3ZeroSizeException(final String message, final Throwable cause) {
//     super(message, cause);
//   }
// }


// Path: pipeline-application/src/main/java/com/smoketurner/pipeline/application/core/AmazonS3Downloader.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.event.S3EventNotification.S3EventNotificationRecord;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.google.common.base.Strings;
import com.smoketurner.pipeline.application.convert.AmazonS3ObjectConverter;
import com.smoketurner.pipeline.application.exceptions.AmazonS3ConstraintException;
import com.smoketurner.pipeline.application.exceptions.AmazonS3ZeroSizeException;
import java.io.IOException;
import java.util.Collections;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/*
 * Copyright © 2019 Smoke Turner, LLC (github@smoketurner.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.smoketurner.pipeline.application.core;


public class AmazonS3Downloader {

  private static final Logger LOGGER = LoggerFactory.getLogger(AmazonS3Downloader.class);
  private static final String GZIP_ENCODING = "gzip";
  private static final String GZIP_EXTENSION = ".gz";
  private final AmazonS3ObjectConverter converter = new AmazonS3ObjectConverter();
  private final AmazonS3 s3;

  /**
   * Constructor
   *
   * @param s3 Amazon S3 client
   */
  public AmazonS3Downloader(@Nonnull final AmazonS3 s3) {
    this.s3 = Objects.requireNonNull(s3);
  }

  /**
   * Retrieves a file from S3
   *
   * @param record S3 event notification record to download
   * @return S3 object
   * @throws AmazonS3ConstraintException if the etag constraints weren't met
   * @throws AmazonS3ZeroSizeException if the file size of the object is zero
   */
  public S3Object fetch(@Nonnull final S3EventNotificationRecord record)
      throws AmazonS3ConstraintException, AmazonS3ZeroSizeException {
    final AmazonS3Object object = converter.convert(Objects.requireNonNull(record));

    final GetObjectRequest request = new GetObjectRequest(object.getBucketName(), object.getKey());
    object.getVersionId().ifPresent(request::setVersionId);
    object
        .getETag()
        .ifPresent(etag -> request.setMatchingETagConstraints(Collections.singletonList(etag)));

    LOGGER.debug("Fetching key: {}/{}", object.getBucketName(), object.getKey());

    final S3Object download;
    try {
      download = s3.getObject(request);
    } catch (AmazonServiceException e) {
      LOGGER.error("Service error while fetching object from S3", e);
      throw e;
    } catch (AmazonClientException e) {
      LOGGER.error("Client error while fetching object from S3", e);
      throw e;
    }

    if (download == null) {
      LOGGER.error(