Zusammenfassung S3-API per Java ansteuern

Heute ein Tutorial für alle Java Liebhaber da draußen. An dieser Stelle erfährst du, wie du den S3-kompatiblen Object Storage von gridscale mittels Java ansprichst. Das von uns bereitgestellte Code-Sample bildet die Grundfunktionalitäten Upload, Download, Namensanpassung und Zugriffsrechteverwaltung ab.

gridscale S3 Object Storage ist komplett Amazon S3 kompatibel, dementsprechend greifen wir im Code auf die AWS SDK Libraries für Java zurück. Unser Beispielprogramm und seine Abhängigkeiten werden von dem Build-Management Tool Apache Maven mit einer pom.xml verwaltet.

Java Quellcode herunterladen und vorbereiten

Wir haben in unserem BitBucket ein wenig Quellcode abgelegt, den du in deinem Beispiel verwenden kannst. Clone dazu zunächst einmal unser BitBucket Repository mit dem Java S3-Code Beispiel.

Wenn du dann ein neues Maven Projekt erstellt hast, kannst du die Umgebungsvariablen setzen, um auf eine S3-API zuzugreifen. Wenn du gerne den gridscale Object Storage mit kompatibler S3-API verwenden möchtest, leg dir über die grafische Benutzeroberfläche von gridscale am besten vorher kurz einen S3 Access Key und einen S3 Secret an. Solltest du noch keinen Account bei gridscale haben, leg dir fix einen an. Für einen einfachen Test der hier beschriebenen Schritte werden dir keine Kosten entstehen.

Konfiguration speichern und Beispiel ausführen

Nachdem du den Code ausgeführt hast, wirst du im Dialog dazu aufgefordert die Pre-Signed URL zu klicken. Durch klicken der URL wird deine Datei final in deinen Object Storage übertragen. Am Ende des Beispiels wirst du weiterhin gefragt, ob die soeben übertragenen Dateien wieder gelöscht werden sollen. Wenn du die Datei nicht löscht, verbleibt sie auf dem Objekt Storage und je nach Anbieter könnten dir hierfür dann marginale Kosten entstehen.

package io.gridscale.s3example;


import com.amazonaws.ClientConfiguration;
import com.amazonaws.HttpMethod;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;


public class Main {

    public static void main(String[] args) throws IOException {

        for (int j = 0; j < 2; j++) {

            // file to upload
            String filePath = "example/logo.png";

            // bucket target - needs to exist!
            String bucketName = "karl";

            // object key
            String keyName = "s3test_" + j;

            // S3 Endpoint for gridscale
            String endpoint = "https://gos3.io";

            // these values come from the object storage settings in the gridscale panel
            String accessKey = System.getenv("GRIDSCALE_S3_ACCESS_KEY");
            String secret = System.getenv("GRIDSCALE_S3_SECRET");

            if (accessKey == null || secret == null) {
                System.out.println("Please define GRIDSCALE_S3_ACCESS_KEY and GRIDSCALE_S3_SECRET in your environment.");
                System.exit(-1);
            }

            BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secret);

            ClientConfiguration clientConfiguration = new ClientConfiguration();
            clientConfiguration.setSignerOverride("S3SignerType");
            
            // Connection Object
            AmazonS3 objectStorageClient = AmazonS3ClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
                    .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endpoint,
                            Regions.DEFAULT_REGION.getName()))
                    .withClientConfiguration(clientConfiguration)
                    .build();


            File file = new File(filePath);
            long contentLength = file.length();
            long partSize = 5 * 1024 * 1024; // Set part size to 5 MB.

            // Create a list of ETag objects. You retrieve ETags for each object part uploaded,
            // then, after each individual part has been uploaded, pass the list of ETags to
            // the request to complete the upload.
            List partETags = new ArrayList();

            // Initiate the multipart upload.
            InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, keyName);
            InitiateMultipartUploadResult initResponse = objectStorageClient.initiateMultipartUpload(initRequest);

            // Upload the file parts.
            long filePosition = 0;
            for (int i = 1; filePosition < contentLength; i++) {
                // Because the last part could be less than 5 MB, adjust the part size as needed.
                partSize = Math.min(partSize, (contentLength - filePosition));

                // Create the request to upload a part.
                UploadPartRequest uploadRequest = new UploadPartRequest()
                        .withBucketName(bucketName)
                        .withKey(keyName)
                        .withUploadId(initResponse.getUploadId())
                        .withPartNumber(i)
                        .withFileOffset(filePosition)
                        .withFile(file)
                        .withPartSize(partSize);

                // Upload the part and add the response's ETag to our list.
                UploadPartResult uploadResult = objectStorageClient.uploadPart(uploadRequest);
                partETags.add(uploadResult.getPartETag());

                filePosition += partSize;
            }

            // Set the presigned URL to expire after one hour.
            java.util.Date expiration = new java.util.Date();
            long expTimeMillis = expiration.getTime();
            expTimeMillis += 1000 * 60 * 60;
            expiration.setTime(expTimeMillis);

            // Complete the multipart upload.
            CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(bucketName, keyName,
                    initResponse.getUploadId(), partETags);
            objectStorageClient.completeMultipartUpload(compRequest);

            GeneratePresignedUrlRequest generatePresignedUrlRequest =
                    new GeneratePresignedUrlRequest(bucketName, keyName)
                            .withMethod(HttpMethod.POST) // Change this to 'GET' if you want to Download
                            .withExpiration(expiration);
            URL url = objectStorageClient.generatePresignedUrl(generatePresignedUrlRequest);

            System.out.println("Please click on the link in the next 12 seconds" + "\n" + "Pre-Signed URL: " + url.toString());

            try {
                TimeUnit.SECONDS.sleep(12);

                // Set ACLs to file
                AccessControlList acl = objectStorageClient.getObjectAcl(bucketName, keyName);

                acl.getGrantsAsList().clear();

                // change '.Read' to whatever Property you want to set the acl to
                acl.grantPermission(new CanonicalGrantee(acl.getOwner().getId()), Permission.Read);

                // set ACLs to file
                objectStorageClient.setObjectAcl(bucketName, keyName, acl);

                // Delete
                if (JOptionPane.showInputDialog(null, "Do you want to delete this example now?" +
                        " y/n?").toLowerCase().equals("y")) {
                    objectStorageClient.deleteObject(new DeleteObjectRequest(bucketName, keyName));
                    System.out.println("File " + keyName + "got removed from Bucket " + bucketName);
                } else {
                    System.out.println("File successfully created in " + bucketName);
                }
            
            } catch (InterruptedException e) {
                e.printStackTrace();

            } catch (SdkClientException e) {
                e.printStackTrace();

            }

        }
    }
}

Fazit

Auch wenn dieses Tutorial eher kurz war, hilft es dir hoffentlich dennoch mit einfachem Beispielcode eine S3-Api zu nutzen – egal ob den gridscale Object Storage oder den Object Storage des Marktführers Amazon Web Services. Weitere Informationen findest du auch in der gridscale Kurzanleitung: S3-kompatiabler Object Storage.