Usando o cliente Java do JetS3t com o Amazon S3

Usando o cliente Java do JetS3t com o Amazon S3

1. Visão geral

Neste tutorial, usaremos a bibliotecaJetS3t comAmazon S3.

Simplificando, vamos criar intervalos, gravar dados neles, ler dados de volta, copiá-los e, em seguida, listá-los e excluí-los.

2. Configuração JetS3t

2.1. Dependência do Maven

Primeiro, precisamos adicionar a biblioteca NATS eApache HttpClient ao nossopom.xml:


    org.lucee
    jets3t
    0.9.4.0006L


    org.apache.httpcomponents
    httpclient
    4.5.5

O Maven Central temlatest version of the JetS3t libraryelatest version of HttpClient. A fonte para JetS3t pode ser encontradahere.

UsaremosApache Commons Codec para um de nossos testes, então vamos adicionar isso ao nossopom.xml too:


    org.lucee
    commons-codec
    1.10.L001

O Maven Central tem a versão mais recentehere.

2.2. Chaves Amazon AWS

We’ll need AWS Access Keys to connect to the S3 storage service. Uma conta gratuita pode ser criadahere.

Depois de termos uma conta, precisamos criar um conjunto desecurity keys.. Há documentação sobre usuários e chaves de acesso disponíveishere.

JetS3t usando o registro do Apache Commons, então vamos usá-lo também quando quisermos imprimir informações sobre o que estamos fazendo.

3. Conectando-se a um Armazenamento Simples

Agora que temos uma chave de acesso e chave secreta da AWS, podemos nos conectar ao armazenamento S3.

3.1. Conectando-se ao AWS

Primeiro, criamos as credenciais da AWS e depois as usamos para conectar-se ao serviço:

AWSCredentials awsCredentials
  = new AWSCredentials("access key", "secret key");
s3Service = new RestS3Service(awsCredentials);

RestS3Serviceis our connection to Amazon S3.Ele usaHttpClientpara se comunicar com S3 por meio de REST.

3.2. Verificando a conexão

Podemos verificar se nos conectamos com sucesso ao serviço listando os intervalos:

S3Bucket[] myBuckets = s3Service.listAllBuckets();

Dependendo se já criamos ou não intervalos antes, o array pode estar vazio, mas se a operação não lançar uma exceção, temos uma conexão válida.

4. Gerenciamento de Buckets

Com uma conexão com o Amazon S3, podemos criar buckets para armazenar nossos dados. S3 é um sistema de armazenamento de objetos. Os dados são carregados como objetos e armazenados em buckets.

Como todos os buckets S3 compartilham o mesmo namespace global, cada um deve ter um nome exclusivo.

4.1. Criando um Bucket

Vamos tentar criar um nome de intervalo “mybucket“:

S3Bucket bucket = s3Service.createBucket("mybucket");

Isso falha com uma exceção:

org.jets3t.service.S3ServiceException: Service Error Message.
  -- ResponseCode: 409, ResponseStatus: Conflict, XML Error Message:
  
  BucketAlreadyExists The requested bucket name is not available.
  The bucket namespace is shared by all users of the system.
  Please select a different name and try again.
  mybucket 07BE34FF3113ECCF
at org.jets3t.service.S3Service.createBucket(S3Service.java:1586)

O nome “mybucket”, previsivelmente, já está sendo usado. Para o resto do tutorial, vamos inventar nossos nomes.

Vamos tentar novamente com um nome diferente:

S3Bucket bucket = s3Service.createBucket("myuniquename");
log.info(bucket);

Com um nome exclusivo, a chamada é bem-sucedida e vemos informações sobre nosso bucket:

[INFO] JetS3tClient - S3Bucket
[name=myuniquename,location=US,creationDate=Sat Mar 31 16:47:47 EDT 2018,owner=null]

4.2. Excluindo um Bucket

Excluir um bucket é tão fácil quanto criá-lo, exceto por uma coisa; buckets must be empty before they can be removed!

s3Service.deleteBucket("myuniquename");

Isso lançará uma exceção para um balde que não está vazio.

4.3. Especificando a região do intervalo

Buckets can be created in a specific data center.Para JetS3t, o padrão é Northern Virginia, nos Estados Unidos, ou “us-east-1”.

Podemos substituir isso especificando uma região diferente:

S3Bucket euBucket
  = s3Service.createBucket("eu-bucket", S3Bucket.LOCATION_EUROPE);
S3Bucket usWestBucket = s3Service
  .createBucket("us-west-bucket", S3Bucket.LOCATION_US_WEST);
S3Bucket asiaPacificBucket = s3Service
  .createBucket("asia-pacific-bucket", S3Bucket.LOCATION_ASIA_PACIFIC);

O JetS3t possui uma extensa lista de regiões definidas como constantes.

5. Upload, download e exclusão de dados

Quando tivermos um balde, podemos adicionar objetos a ele. Os baldes têm o objetivo de ser de longa duração e não há limite rígido para o tamanho ou número de objetos que um balde pode conter.

Os dados são enviados para S3 criandoS3Objects.We can upload data a from an InputStream,but JetS3t also provides convenience methods for Stringsand*Files*.

5.1. StringData

Vamos dar uma olhada emStrings primeiro:

S3Object stringObject = new S3Object("object name", "string object");
s3Service.putObject("myuniquebucket", stringObject);

Semelhante a depósitos, os objetos têm nomes,however, object names only live inside their buckets, so we don’t have to worry about them being globally unique.

Criamos o objeto passando um nome e os dados para o construtor. Então nós o armazenamos computObject.

Quando usamos este método para armazenarStringswith JetS3t, ele define o tipo de conteúdo correto para nós.

Vamos consultar S3 para obter informações sobre nosso objeto e olhar para o tipo de conteúdo:

StorageObject objectDetailsOnly
  = s3Service.getObjectDetails("myuniquebucket", "my string");
log.info("Content type: " + objectDetailsOnly.getContentType() + " length: "
  + objectDetailsOnly.getContentLength());

ObjectDetailsOnly()recupera os metadados dos objetos sem baixá-los. Quando registramos o tipo de conteúdo, vemos:

[INFO] JetS3tClient - Content type: text/plain; charset=utf-8 length: 9

O JetS3t identificou os dados como texto e definiu o tamanho para nós.

Vamos baixar os dados e compará-los com o que carregamos:

S3Object downloadObject =
  s3Service.getObject("myuniquebucket, "string object");
String downloadString = new BufferedReader(new InputStreamReader(
  object.getDataInputStream())).lines().collect(Collectors.joining("\n"));

assertTrue("string object".equals(downloadString));

Os dados são recuperados no mesmo uso deS3Objectwe para carregá-los, com os bytes disponíveis em umDataInputStream.

5.2. Dados de arquivo

O processo de envio de arquivos é semelhante aStrings:

File file = new File("src/test/resources/test.jpg");
S3Object fileObject = new S3Object(file);
s3Service.putObject("myuniquebucket", fileObject);

QuandoS3Objects são passados ​​aFile, eles derivam seu nome do nome base dos arquivos que contêm:

[INFO] JetS3tClient - File object name is test.jpg

JetS3t takes the File and uploads it for us.Ele tentará carregar ummime.types file do classpath e usá-lo para identificar o tipo de arquivo e o tipo de conteúdo enviado apropriadamente.

Se recuperarmos as informações do objeto do upload do arquivo e obtermos o tipo de conteúdo que vemos:

[INFO] JetS3tClient - Content type:application/octet-stream

Vamos baixar nosso arquivo para um novo e comparar o conteúdo:

String getFileMD5(String filename) throws IOException {
    try (FileInputStream fis = new FileInputStream(new File(filename))) {
        return DigestUtils.md5Hex(fis);
    }
}

S3Object fileObject = s3Service.getObject("myuniquebucket", "test.jpg");
File newFile = new File("/tmp/newtest.jpg");
Files.copy(fileObject.getDataInputStream(), newFile.toPath(),
  StandardCopyOption.REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/newtest.jpg");
assertTrue(origMD5.equals(newMD5));

Semelhante aStrings, swe baixou o objeto e usouDataInputStream para criar um novo arquivo. Em seguida, calculamos um hash MD5 para os dois arquivos e os comparamos.

5.3. Streaming Data

Quando carregamos objetos diferentes deStringsorFiles,, temos um pouco mais de trabalho a fazer:

ArrayList numbers = new ArrayList<>();
// adding elements to the ArrayList

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(bytes);
objectOutputStream.writeObject(numbers);

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes.toByteArray());

S3Object streamObject = new S3Object("stream");
streamObject.setDataInputStream(byteArrayInputStream);
streamObject.setContentLength(byteArrayInputStream.available());
streamObject.setContentType("binary/octet-stream");

s3Service.putObject(BucketName, streamObject);

Precisamos definir nosso tipo e tamanho do conteúdo antes de fazer o upload.

Recuperar esse fluxo significa reverter o processo:

S3Object newStreamObject = s3Service.getObject(BucketName, "stream");

ObjectInputStream objectInputStream = new ObjectInputStream(
  newStreamObject.getDataInputStream());
ArrayList newNumbers = (ArrayList) objectInputStream
  .readObject();

assertEquals(2, (int) newNumbers.get(0));
assertEquals(3, (int) newNumbers.get(1));
assertEquals(5, (int) newNumbers.get(2));
assertEquals(7, (int) newNumbers.get(3));

Para diferentes tipos de dados, a propriedade do tipo de conteúdo pode ser usada para selecionar um método diferente para decodificar o objeto.

6. Copiar, mover e renomear dados

6.1. Copiando objetos

Os objetos podem ser copiados dentro do S3, sem recuperá-los.

Vamos copiar nosso arquivo de teste da seção 5.2 e verificar o resultado:

S3Object targetObject = new S3Object("testcopy.jpg");
s3Service.copyObject(
  BucketName, "test.jpg",
  "myuniquebucket", targetObject, false);
S3Object newFileObject = s3Service.getObject(
  "myuniquebucket", "testcopy.jpg");

File newFile = new File("src/test/resources/testcopy.jpg");
Files.copy(
  newFileObject.getDataInputStream(),
  newFile.toPath(),
  REPLACE_EXISTING);
String origMD5 = getFileMD5("src/test/resources/test.jpg");
String newMD5 = getFileMD5("src/test/resources/testcopy.jpg");

assertTrue(origMD5.equals(newMD5));

Podemos copiar objetos dentro do mesmo balde ou entre dois diferentes.

Se o último argumento for verdadeiro, o objeto copiado receberá novos metadados. Caso contrário, ele reterá os metadados do objeto de origem.

Se quisermos modificar os metadados, podemos definir o sinalizador como true:

targetObject = new S3Object("testcopy.jpg");
targetObject.addMetadata("My_Custom_Field", "Hello, World!");
s3Service.copyObject(
  "myuniquebucket", "test.jpg",
  "myuniquebucket", targetObject, true);

6.2. Objetos Móveis

Objects can be moved to another S3 bucket in the same region.Uma operação de movimentação é uma operação de cópia e exclusão.

Se a operação de cópia falhar, o objeto de origem não é excluído. Se a operação de exclusão falhar, o objeto ainda existirá na origem e também no local de destino.

Mover um objeto é semelhante a copiá-lo:

s3Service.moveObject(
  "myuniquebucket",
  "test.jpg",
  "myotheruniquebucket",
  new S3Object("spidey.jpg"),
  false);

6.3. Renomeando Objetos

JetS3t has a convenience method for renaming objects. Para alterar o nome de um objeto, simplesmente o chamamos com um novoS3Object:

s3Service.renameObject(
  "myuniquebucket", "test.jpg", new S3Object("spidey.jpg"));

7. Conclusão

Neste tutorial, usamos o JetS3t para conectar-se ao Amazon S3. Criamos e excluímos buckets. Em seguida, adicionamos diferentes tipos de dados aos buckets e recuperamos os dados. Para finalizar, copiamos e movemos nossos dados.

Amostras de código, como sempre, podem ser encontradasover on GitHub.