В мире Java есть несколько хороших способов загрузки контента в корзину S3 — в этой статье мы рассмотрим, что библиотека jclouds предоставляет для этой цели. Чтобы использовать jclouds — в частности, API, обсуждаемые в этой статье, эту простую зависимость Maven следует добавить в pom проекта:
1
2
3
4
5
|
< dependency > < groupId >org.jclouds</ groupId > < artifactId >jclouds-allblobstore</ artifactId > < version >1.5.9</ version > </ dependency > |
1. Загрузка в Amazon S3
Первым шагом для доступа к любому из этих API-интерфейсов является создание BlobStoreContext :
1
2
3
|
BlobStoreContext context = ContextBuilder.newBuilder( 'aws-s3' ).credentials(identity, credentials) .buildView(BlobStoreContext. class ); |
Это представляет собой точку входа в общую службу хранения значений ключей, такую как Amazon S3, но не ограничивается этим. Для более конкретной реализации только S3 контекст может быть создан аналогично:
1
2
3
|
BlobStoreContext context = ContextBuilder.newBuilder( 'aws-s3' ).credentials(identity, credentials) .buildView(S3BlobStoreContext. class ); |
И даже более конкретно:
1
2
3
|
BlobStoreContext context = ContextBuilder.newBuilder( 'aws-s3' ).credentials(identity, credentials) .buildView(AWSS3BlobStoreContext. class ); |
Когда аутентифицированный контекст больше не нужен, его закрытие необходимо для освобождения всех ресурсов — потоков и соединений — связанных с ним.
2. Четыре S3 API jclouds
Библиотека jclouds предоставляет четыре различных API для загрузки контента в корзину S3, начиная от простого, но негибкого до сложного и мощного, и все это получается с помощью BlobStoreContext . Начнем с самого простого.
2.1. Загрузить через API карты
Самый простой способ использовать jclouds для взаимодействия с корзиной S3 — это представить эту корзину как карту. API получается из контекста:
1
|
InputStreamMap bucket = context.createInputStreamMap( 'bucketName' ); |
Затем, чтобы загрузить простой файл HTML:
1
|
bucket.putString( 'index1.html' , '<html><body>hello world1</body></html>' ); |
API InputStreamMap предоставляет несколько других типов операций PUT — файлы, необработанные байты — как для одного, так и для большого количества. В качестве примера можно использовать простой интеграционный тест:
1
2
3
4
5
6
7
8
9
|
@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 — он получен из контекста:
1
|
BlobMap bucket = context.createBlobMap( 'bucketName' ); |
API позволяет клиенту получать доступ к более подробным сведениям более низкого уровня, таким как Content — Length , Content-Type , Content-Encoding , хэш eTag и другие; чтобы загрузить новый контент в корзину:
1
2
3
|
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:
01
02
03
04
05
06
07
08
09
10
11
12
|
@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 не могли загружать контент с помощью многоэтапной загрузки — это делает их плохо подходящими для работы с большими файлами. Это ограничение устраняется следующим API, который мы рассмотрим — синхронным API BlobStore. Это получается из контекста:
1
|
BlobStore blobStore = context.getBlobStore(); |
Чтобы использовать поддержку multipart и загрузить файл на S3:
1
2
3
|
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, а именно — поддержкой нескольких частей. Предыдущий интеграционный тест теперь имеет многочастную поддержку:
01
02
03
04
05
06
07
08
09
10
11
|
@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 аналогичным образом получается из контекста:
1
|
AsyncBlobStore blobStore = context.getAsyncBlobStore(); |
Единственное различие между ними состоит в том, что асинхронный API возвращает ListenableFuture для асинхронной операции PUT :
1
2
3
|
Blob blob = blobStore.blobBuilder( 'index4.html' ). .payload( '<html><body>hello world4</body></html>' ).build(); blobStore.putBlob( 'bucketName' , blob)<strong>.get()</strong>; |
Интеграционный тест, отображающий эту операцию, похож на синхронный:
01
02
03
04
05
06
07
08
09
10
11
12
|
@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 . Мы реализуем операцию загрузки большого файла, динамически рассчитываем оптимальное количество деталей для любого конкретного файла и выполняем загрузку всех деталей параллельно.
Ссылка: Загрузите на S3 библиотеку jclouds от нашего партнера JCG Евгения Параскива в блоге baeldung .