Utilisation du client Java JetS3t avec Amazon S3

1. Vue d'ensemble

Dans ce didacticiel, nous utiliserons la bibliothèque JetS3t avec Amazon S3.

En termes simples, nous allons créer des buckets, y écrire des données, les lire, les copier, puis les lister et les supprimer.

2. Configuration de JetS3t

2.1. Dépendance de Maven

Tout d'abord, nous devons ajouter la bibliothèque NATS et Apache HttpClient à notre pom.xml :

 org.lucee jets3t 0.9.4.0006L   org.apache.httpcomponents httpclient 4.5.5  

Maven Central dispose de la dernière version de la bibliothèque JetS3t et de la dernière version de HttpClient. La source de JetS3t peut être trouvée ici.

Nous utiliserons Apache Commons Codec pour l'un de nos tests, nous allons donc l'ajouter à notre pom.xml également:

 org.lucee commons-codec 1.10.L001  

Maven Central a la dernière version ici.

2.2. Clés Amazon AWS

Nous aurons besoin des clés d'accès AWS pour nous connecter au service de stockage S3. Un compte gratuit peut être créé ici.

Une fois que nous avons un compte, nous devons créer un ensemble de clés de sécurité. Une documentation sur les utilisateurs et les clés d'accès est disponible ici.

JetS3t utilisant la journalisation Apache Commons, nous l'utilisons donc également lorsque nous voulons imprimer des informations sur ce que nous faisons.

3. Connexion à un stockage simple

Maintenant que nous avons une clé d'accès AWS et une clé secrète, nous pouvons nous connecter au stockage S3.

3.1. Connexion à AWS

Tout d'abord, nous créons les informations d'identification AWS, puis nous les utilisons pour nous connecter au service:

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

RestS3Service est notre connexion à Amazon S3. Il utilise HttpClient pour communiquer avec S3 via REST.

3.2. Vérification de la connexion

Nous pouvons vérifier que nous nous sommes bien connectés au service en répertoriant les buckets:

S3Bucket[] myBuckets = s3Service.listAllBuckets(); 

Selon que nous avons déjà créé des buckets ou non, le tableau peut être vide, mais si l'opération ne lève pas d'exception, nous avons une connexion valide.

4. Gestion des godets

Avec une connexion à Amazon S3, nous pouvons créer des compartiments pour stocker nos données. S3 est un système de stockage d'objets. Les données sont téléchargées sous forme d'objets et stockées dans des buckets.

Étant donné que tous les compartiments S3 partagent le même espace de noms global, chacun doit avoir un nom unique.

4.1. Créer un bucket

Essayons de créer un nom de bucket " mybucket ":

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

Cela échoue avec une exception:

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)

Le nom « mybucket » est, comme on pouvait s'y attendre , déjà pris. Pour le reste du didacticiel, nous inventerons nos noms.

Essayons à nouveau avec un nom différent:

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

Avec un nom unique, l'appel réussit et nous voyons des informations sur notre bucket:

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

4.2. Supprimer un bucket

Supprimer un bucket est aussi simple que de le créer, sauf pour une chose; les seaux doivent être vides avant de pouvoir être retirés!

s3Service.deleteBucket("myuniquename"); 

Cela lèvera une exception pour un compartiment qui n'est pas vide.

4.3. Spécification de la région du compartiment

Les buckets peuvent être créés dans un centre de données spécifique. Pour JetS3t, la valeur par défaut est la Virginie du Nord aux États-Unis, ou «us-east-1».

Nous pouvons remplacer cela en spécifiant une région différente:

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); 

JetS3t a une longue liste de régions définies comme constantes.

5. Télécharger, télécharger et supprimer des données

Une fois que nous avons un seau, nous pouvons y ajouter des objets. Les seaux sont conçus pour durer longtemps et il n'y a pas de limite stricte sur la taille ou le nombre d'objets qu'un seau peut contenir.

Data is uploaded to S3 by creating S3Objects.We can upload data a from an InputStream,but JetS3t also provides convenience methods for Stringsand Files.

5.1. StringData

Let's take a look at Stringsfirst:

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

Similar to buckets, objects have names, however, object names only live inside their buckets, so we don't have to worry about them being globally unique.

We create the object by passing a name and the data to the constructor. Then we store it with putObject.

When we use this method to store Stringswith JetS3t, it sets the correct content type for us.

Let's query S3 for information about our object and look at the content type:

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

ObjectDetailsOnly()retrieves the objects metadata without downloading it. When we log the content type we see:

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

JetS3t identified the data as text and set the length for us.

Let's download the data and compare it to what we uploaded:

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));

Data is retrieved in the same S3Objectwe use to upload it, with the bytes available in a DataInputStream.

5.2. File Data

The process for uploading files is similar to Strings:

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

When S3Objectsare passed a File they derive their name from the base name of the files they contain:

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

JetS3t takes the File and uploads it for us.It will attempt to load a mime.types filefrom the classpath and use it to identify the type of file and sent content type appropriately.

If we retrieve the object info of our file upload and get the content type we see:

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

Let's download our file to a new one and compare the contents:

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));

Similar to Stringswe downloaded the object and used the DataInputStream to create a new file. Then we calculated an MD5 hash for both files and compared them.

5.3. Streaming Data

When we upload objects other than Stringsor Files,we have a bit more work to do:

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); 

We need to set our content type and length before uploading.

Retrieving this stream means reversing the process:

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)); 

For different data types, the content type property can be used to select a different method for decoding the object.

6. Copying, Moving and Renaming Data

6.1. Copying Objects

Objects can be copied inside S3, without retrieving them.

Let's copy our test file from section 5.2, and verify the result:

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)); 

We can copy objects inside the same bucket, or between two different ones.

If the last argument is true, the copied object will receive new metadata. Otherwise, it will retain the source object's metadata.

If we want to modify the metadata, we can set the flag to true:

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

6.2. Moving Objects

Objects can be moved to another S3 bucket in the same region.A move operation is a copy then a delete operation.

Si l'opération de copie échoue, l'objet source n'est pas supprimé. Si l'opération de suppression échoue, l'objet existera toujours dans la source et également dans l'emplacement de destination.

Déplacer un objet ressemble à le copier:

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

6.3. Renommer des objets

JetS3t a une méthode pratique pour renommer les objets. Pour changer le nom d'un objet, nous l'appelons simplement avec un nouveau S3Object :

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

7. Conclusion

Dans ce didacticiel, nous avons utilisé JetS3t pour nous connecter à Amazon S3. Nous avons créé et supprimé des buckets. Ensuite, nous avons ajouté différents types de données aux buckets et récupéré les données. Pour conclure, nous avons copié et déplacé nos données.

Des exemples de code, comme toujours, peuvent être trouvés sur GitHub.