Загрузить на S3 с библиотекой jclouds

В мире Java есть несколько хороших способов загрузки контента в корзину S3 - в этой статье мы рассмотрим, что the библиотека jclouds предоставляет для этой цели.

Чтобы использовать jclouds - в частности, API, обсуждаемые в этой статье, этот https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.jclouds%22%20AND%20a%3A%22jclouds- allblobstore% 22[простая зависимость Maven]должен быть добавлен в pom проекта:

<dependency>
   <groupId>org.jclouds</groupId>
   <artifactId>jclouds-allblobstore</artifactId>
   <version>1.5.10</version>
</dependency>

1. Загрузка в Amazon S3

Первым шагом для доступа к любому из этих API-интерфейсов является создание BlobStoreContext :

BlobStoreContext context =
  ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
    .buildView(BlobStoreContext.class);

Это представляет собой точку входа в общую службу хранения значений ключей, такую ​​как Amazon S3, но не ограничивается этим.

Для более конкретной реализации только S3 контекст может быть создан аналогично:

BlobStoreContext context =
  ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
    .buildView(S3BlobStoreContext.class);

И даже более конкретно:

BlobStoreContext context =
  ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
    .buildView(AWSS3BlobStoreContext.class);

Когда аутентифицированный контекст больше не нужен, закрывая , требуется освободить все ресурсы - потоки и соединения - связанные с ним

2. Четыре S3 API jclouds

Библиотека jclouds предоставляет четыре различных API для загрузки контента в корзину S3, начиная от простого, но негибкого до сложного и мощного, и все это получается через BlobStoreContext . Давайте начнем с самого простого.

2.1. Загрузка через API Map

Самый простой способ использовать jclouds для взаимодействия с корзиной S3 - это представить эту корзину как карту. API получается из контекста:

InputStreamMap bucket = context.createInputStreamMap("bucketName");

Затем, чтобы загрузить простой файл HTML:

bucket.putString("index1.html", "<html><body>hello world1</body></html>");

API InputStreamMap предоставляет несколько других типов операций PUT - файлы, необработанные байты - как для одного, так и для большого количества.

В качестве примера можно использовать простой интеграционный тест:

@Test
public void whenFileIsUploadedToS3WithMapApi__thenNoExceptions() {
   BlobStoreContext context =
      ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
         .buildView(AWSS3BlobStoreContext.class);

   InputStreamMap bucket = context.createInputStreamMap("bucketName");

   bucket.putString("index1.html", "<html><body>hello world1</body></html>");
   context.close();
}

2.2. Загрузить через BlobMap

Использование простого API-интерфейса карты просто, но в конечном итоге ограничено - например, невозможно передать метаданные о загружаемом контенте. Когда требуется больше гибкости и настройки, этого упрощенного подхода к загрузке данных на S3 через карту больше не достаточно.

Следующий API, который мы рассмотрим, это API-интерфейс Blob Map - он получается из контекста:

BlobMap bucket = context.createBlobMap("bucketName");

API позволяет клиенту получать доступ к более подробным сведениям более низкого уровня, таким как Content Length , Content-Type , Content-Encoding , eTag hash и другие; чтобы загрузить новый контент в корзину:

Blob blob = bucket.blobBuilder().name("index2.html").
   payload("<html><body>hello world2</body></html>").
      contentType("text/html").calculateMD5().build();

API также позволяет устанавливать различные полезные нагрузки в запросе на создание.

Простой интеграционный тест для загрузки базового HTML-файла в S3 через API-интерфейс Blob Map:

@Test
public void whenFileIsUploadedToS3WithBlobMap__thenNoExceptions() throws IOException {
   BlobStoreContext context =
      ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
         .buildView(AWSS3BlobStoreContext.class);

   BlobMap bucket = context.createBlobMap("bucketName");

   Blob blob = bucket.blobBuilder().name("index2.html").
      payload("<html><body>hello world2</body></html>").
         contentType("text/html").calculateMD5().build();
   bucket.put(blob.getMetadata().getName(), blob);

   context.close();
}

2.3. Загрузить через BlobStore

Предыдущие API не могли загружать контент с помощью multipart upload - это делает их плохо подходящими для работы с большими файлами. Это ограничение устранено следующим API-интерфейсом, который мы собираемся рассмотреть - синхронным API BlobStore.

Это получается из контекста:

BlobStore blobStore = context.getBlobStore();

Чтобы использовать поддержку multipart и загрузить файл на S3:

Blob blob = blobStore.blobBuilder("index3.html").
   payload("<html><body>hello world3</body></html>").contentType("text/html").build();
blobStore.putBlob("bucketName", blob, PutOptions.Builder.multipart());

Компоновщик полезной нагрузки - тот же самый, который использовался API BlobMap , поэтому та же самая гибкость в определении информации метаданных более низкого уровня о большом двоичном объекте доступна здесь. Разница в том, что PutOptions поддерживается операцией PUT API, а именно multipart support .

В предыдущем интеграционном тесте теперь включена поддержка нескольких частей:

@Test
public void whenFileIsUploadedToS3WithBlobStore__thenNoExceptions() {
   BlobStoreContext context =
      ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
         .buildView(AWSS3BlobStoreContext.class);

   BlobStore blobStore = context.getBlobStore();

   Blob blob = blobStore.blobBuilder("index3.html").
      payload("<html><body>hello world3</body></html>").contentType("text/html").build();
   blobStore.putBlob("bucketName", blob, PutOptions.Builder.multipart());
   context.close();
}

2.4. Загрузить через AsyncBlobStore

В то время как предыдущий API BlobStore был синхронным, существует также асинхронный API для BlobStore - AsyncBlobStore . API аналогичным образом получается из контекста:

AsyncBlobStore blobStore = context.getAsyncBlobStore();

Единственное различие между ними состоит в том, что асинхронный API возвращает ListenableFuture для асинхронной операции PUT :

Blob blob = blobStore.blobBuilder("index4.html").
   .payload("<html><body>hello world4</body></html>").build();
blobStore.putBlob("bucketName", blob)<strong>.get()</strong>;

Интеграционный тест, отображающий эту операцию, похож на синхронный:

@Test
public void whenFileIsUploadedToS3WithBlobStore__thenNoExceptions() {
   BlobStoreContext context =
      ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
         .buildView(AWSS3BlobStoreContext.class);

   BlobStore blobStore = context.getBlobStore();

   Blob blob = blobStore.blobBuilder("index4.html").
      payload("<html><body>hello world4</body></html>").contentType("text/html").build();
   Future<String> putOp = blobStore.putBlob("bucketName", blob, PutOptions.Builder.multipart());
   putOp.get();
   context.close();
}

3. Заключение

В этой статье мы проанализировали четыре API , которые предоставляет библиотека jclouds для загрузки контента в Amazon S3. Эти четыре API являются универсальными и работают также с другими службами хранения ключей-значений, такими как, например, Microsoft Azure Storage.

В следующей статье мы рассмотрим специфичный для Amazon API S3, доступный в jclouds - AWSS3Client . Мы реализуем операцию загрузки большого файла, динамически рассчитываем оптимальное количество деталей для любого конкретного файла и выполняем загрузку всех деталей параллельно.