All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.expediagroup.beekeeper.cleanup.aws.S3Client Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) ${license.git.copyrightYears} Expedia, Inc.
 *
 * 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.expediagroup.beekeeper.cleanup.aws;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.DeleteObjectsResult;
import com.amazonaws.services.s3.model.ListObjectsV2Request;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3ObjectSummary;

public class S3Client {

  private static final int REQUEST_CHUNK_SIZE = 1000;
  private static final Logger log = LoggerFactory.getLogger(S3Client.class);
  private final AmazonS3 amazonS3;
  private final boolean dryRunEnabled;

  public S3Client(AmazonS3 amazonS3, boolean dryRunEnabled) {
    this.amazonS3 = amazonS3;
    this.dryRunEnabled = dryRunEnabled;
  }

  void deleteObject(String bucket, String key) {
    if (dryRunEnabled) {
      log.info("Dry run - deleting: \"{}/{}\"", bucket, key);
    } else {
      log.info("Deleting \"{}/{}\"", bucket, key);
      amazonS3.deleteObject(bucket, key);
    }
  }

  List listObjects(String bucket, String key) {
    List objectSummaries = new ArrayList<>();
    ListObjectsV2Result listObjectsV2Result;
    String continuationToken = null;
    do {
      ListObjectsV2Request request = new ListObjectsV2Request()
          .withBucketName(bucket)
          .withPrefix(key)
          .withEncodingType("url")
          .withContinuationToken(continuationToken);
      listObjectsV2Result = amazonS3.listObjectsV2(request);
      objectSummaries.addAll(listObjectsV2Result.getObjectSummaries());
      continuationToken = listObjectsV2Result.getNextContinuationToken();
    } while (listObjectsV2Result.isTruncated());
    return objectSummaries;
  }

  List deleteObjects(String bucket, List keys) {
    if (keys.isEmpty()) {
      return Collections.emptyList();
    }
    if (!dryRunEnabled) {
      log.info("Attempting to delete a total of {} objects, from [{}] to [{}]", keys.size(), keys.get(0),
          keys.get(keys.size() - 1));
      DeleteObjectsResult deleteObjectsResult = new DeleteObjectsResult(new ArrayList<>());
      DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucket);
      int totalKeys = keys.size();
      int indexStart;
      int indexEnd = 0;
      while (indexEnd < totalKeys) {
        indexStart = indexEnd;
        indexEnd = nextIndexEnd(indexStart, REQUEST_CHUNK_SIZE, totalKeys);
        deleteObjectsRequest.withKeys(keys.subList(indexStart, indexEnd).toArray(String[]::new));
        deleteObjectsResult.getDeletedObjects().addAll(
            amazonS3.deleteObjects(deleteObjectsRequest).getDeletedObjects());
      }
      log.info("Successfully deleted {} objects", keys.size());
      return deleteObjectsResult.getDeletedObjects()
          .stream()
          .map(DeleteObjectsResult.DeletedObject::getKey)
          .collect(Collectors.toList());
    } else {
      return keys.stream()
          .peek(key -> log.info("Dry run - deleting: \"{}/{}\"", bucket, key))
          .collect(Collectors.toList());
    }
  }

  boolean doesObjectExist(String bucket, String key) {
    return amazonS3.doesObjectExist(bucket, key);
  }

  ObjectMetadata getObjectMetadata(String bucket, String key) {
    return amazonS3.getObjectMetadata(bucket, key);
  }

  boolean isEmpty(String bucket, String key, String leafKey) {
    List objectsLeftAtPath = amazonS3.listObjectsV2(bucket, key + "/").getObjectSummaries();
    if (!dryRunEnabled) {
      return objectsLeftAtPath.size() == 0;
    } else {
      String leafKeySentinel = leafKey + S3SentinelFilesCleaner.SENTINEL_SUFFIX;

      for (S3ObjectSummary s3ObjectSummary : objectsLeftAtPath) {
        String currentKey = s3ObjectSummary.getKey();
        if (!currentKey.startsWith(leafKey + "/") && !currentKey.equals(leafKeySentinel)) {
          return false;
        }
      }
      return true;
    }
  }

  private int nextIndexEnd(final int indexStart, final int chunkSize, final int totalKeys) {
    int calculatedNextIndexEnd = indexStart + chunkSize;
    return Math.min(calculatedNextIndexEnd, totalKeys);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy