Enterprise Java

Getting Started with the Java S3Proxy Library

S3Proxy is an open-source and highly customizable proxy server that enables developers to emulate Amazon S3 storage locally. It provides an S3-compatible API that allows us to test and develop applications requiring object storage without depending on an actual AWS S3 environment. With S3Proxy, we can integrate backend storage systems like local filesystems or databases and access them using the same S3 API calls your application uses in production. This article explores how to use the S3Proxy library to run S3Proxy in a local environment.

1. How S3Proxy Works

S3Proxy acts as a middleware between our application and various storage backends by emulating the Amazon S3 API. When our application sends S3-compatible requests (such as uploading or retrieving objects), S3Proxy intercepts these requests and translates them into operations supported by the configured storage backend. This allows us to interact with local or cloud-based storage systems using familiar S3 commands and tools.

Here is an explanation of how S3Proxy works:

  • API Emulation: S3Proxy listens for requests using the S3 API (e.g., PUT, GET, DELETE) over HTTP or HTTPS. It interprets these requests and maps them to the underlying storage backend.
  • Backend Configuration: Storage backends like local filesystems, Google Cloud Storage, OpenStack Swift, Microsoft Azure Blob Storage, or Ceph RADOS Gateway are configured in the s3proxy.conf file. S3Proxy translates S3 operations into backend-specific actions.
  • Request Handling: Incoming S3 requests, such as uploading files (PUT object) or fetching files (GET object), are processed by S3Proxy. For instance, an upload request might write the file to the local filesystem if it is configured as the backend.
  • Security and Access Control: S3Proxy can be configured with credentials to authenticate requests, ensuring only authorized access. For example, it can use static credentials or mimic AWS authentication to validate requests.
  • Local Development and Testing: By running S3Proxy locally, developers can emulate S3 interactions without needing access to AWS. Applications interact with S3Proxy as if it were a live S3 service, enabling seamless testing and debugging.

1.1 Example Workflow

Here is an example of how S3Proxy processes a file upload request when the local filesystem is used as the backend:

  • Application: The application sends a PUT request to S3Proxy with the object data.
  • S3Proxy: It receives the request and verifies the credentials if authentication is enabled.
  • Translation: S3Proxy translates the PUT request into a file write operation in the specified directory of the local filesystem.

2. Using S3Proxy in Java Applications

To use S3Proxy in your Java project, include the following Maven dependency:

        <dependency>
            <groupId>org.gaul</groupId>
            <artifactId>s3proxy</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
            <version>2.28.23</version>
        </dependency>

S3Proxy (org.gaul:s3proxy) offers a locally hosted endpoint that emulates the Amazon S3 API, while the AWS SDK for S3 (software.amazon.awssdk:s3) provides the tools to interact with this endpoint as though it were a real S3 service, making this combination ideal for local development and testing without needing an AWS account.

2.1 Sample Java Code for Using S3Proxy

The following code example demonstrates how to configure and use S3Proxy along with AWS SDK’s S3Client to interact with it.

public class S3ProxyExample {

    public static void main(String[] args) throws Exception {
        // Configure the backend BlobStore
        Properties properties = new Properties();
        properties.setProperty("jclouds.filesystem.basedir", "/tmp/s3proxy");

        BlobStoreContext context = ContextBuilder
                .newBuilder("filesystem")
                .credentials("identity", "credential")
                .overrides(properties)
                .build(BlobStoreContext.class);
        BlobStore blobStore = context.getBlobStore();

        // Configure and start S3Proxy
        S3Proxy s3Proxy = S3Proxy.builder()
                .blobStore(blobStore)
                .endpoint(URI.create("http://127.0.0.1:8080"))
                .build();
        s3Proxy.start();

        // Wait for S3Proxy to start
        while (!s3Proxy.getState().equals(AbstractLifeCycle.STARTED)) {
            Thread.sleep(100);
        }
        System.out.println("S3Proxy started at: " + s3Proxy.getState());

        // Configure S3Client
        S3Client s3Client = S3Client.builder()
                .endpointOverride(URI.create("http://127.0.0.1:8080"))
                .region(Region.US_EAST_1)
                .credentialsProvider(StaticCredentialsProvider.create(
                        AwsBasicCredentials.create("access", "secret")))
                .build();

        // Perform S3 Operations
        String bucketName = "test-bucket";
        s3Client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build());
        System.out.println("Bucket created: " + bucketName);

        String key = "example.txt";
        String content = "Hello, S3Proxy!";
        s3Client.putObject(PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build(),
                RequestBody.fromBytes(content.getBytes()));
        System.out.println("File uploaded: " + key);

        // Verify the upload
        List<S3Object> summaries = s3Client.listObjects(request
                -> request.bucket(bucketName)
        ).contents();
        summaries.forEach(summary -> System.out.println("File in bucket: " + summary.key()));

        String downloadedContent = s3Client.getObject(
                GetObjectRequest.builder()
                        .bucket(bucketName)
                        .key(key)
                        .build(),
                ResponseTransformer.toBytes()).asUtf8String();
        System.out.println("Downloaded content: " + downloadedContent);

        // Shutdown the proxy
        s3Proxy.stop();
        System.out.println("S3Proxy stopped.");
    }
}

The following section provides a detailed explanation and overview of the example code above:

Configure the Backend BlobStore

Properties properties = new Properties();
properties.setProperty("jclouds.filesystem.basedir", "/tmp/s3proxy");

BlobStoreContext context = ContextBuilder
        .newBuilder("filesystem")
        .credentials("identity", "credential")
        .overrides(properties)
        .build(BlobStoreContext.class);
BlobStore blobStore = context.getBlobStore();

The purpose of this step is to configure a BlobStore to serve as the storage backend for S3Proxy. The key configuration includes setting jclouds.filesystem.basedir to specify the local directory (/tmp/s3proxy) for storing objects. Using ContextBuilder, a BlobStoreContext is created for the “filesystem” provider with dummy credentials (identity and credential). As a result, a BlobStore instance is created to interact with the backend storage.

Start S3Proxy

S3Proxy s3Proxy = S3Proxy.builder()
        .blobStore(blobStore)
        .endpoint(URI.create("http://127.0.0.1:8080"))
        .build();
s3Proxy.start();

while (!s3Proxy.getState().equals(AbstractLifeCycle.STARTED)) {
    Thread.sleep(100);
}
System.out.println("S3Proxy started at: " + s3Proxy.getState());

The purpose of this step is to configure and launch the S3Proxy server. Using S3Proxy.builder(), the server is set up to utilize the previously initialized BlobStore and bind it to the specified endpoint (http://127.0.0.1:8080). The s3Proxy.start() method is then called to start the server.

Configure the S3Client

S3Client s3Client = S3Client.builder()
        .endpointOverride(URI.create("http://127.0.0.1:8080"))
        .region(Region.US_EAST_1)
        .credentialsProvider(StaticCredentialsProvider.create(
                AwsBasicCredentials.create("access", "secret")))
        .build();

In the above code fragment, an S3Client instance is created to work with the S3Proxy endpoint. It is configured with the local S3Proxy address (endpointOverride), simple static credentials (“access” and “secret”), and an AWS region (though not strictly needed for S3Proxy). This setup provides a fully configured S3Client for performing S3 operations.

Perform S3 Operations

String bucketName = "test-bucket";
s3Client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build());

String key = "example.txt";
String content = "Hello, S3Proxy!";
s3Client.putObject(PutObjectRequest.builder()
        .bucket(bucketName)
        .key(key)
        .build(),
        RequestBody.fromBytes(content.getBytes()));

List<S3Object> summaries = s3Client.listObjects(request
        -> request.bucket(bucketName)
).contents();

String downloadedContent = s3Client.getObject(
        GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build(),
        ResponseTransformer.toBytes()).asUtf8String();
System.out.println("Downloaded content: " + downloadedContent);

In the above code fragment, we demonstrate how to interact with the S3Proxy server using the S3Client. First, a bucket named test-bucket is created to serve as a storage container. Next, a file named example.txt is uploaded to the bucket with the content "Hello, S3Proxy!". The bucket’s contents are then listed, displaying all stored files. Finally, the uploaded file is downloaded, and its content is retrieved to verify that it matches the original data, ensuring the upload and retrieval processes were successful.

These operations highlight how S3Proxy can replicate typical S3 functionality for development and testing purposes.

3. Conclusion

In this article, we explored how to set up and use S3Proxy, a Java library that mimics Amazon S3 functionality locally for development and testing. We walked through configuring a BlobStore backend, starting the S3Proxy server, and performing basic S3 operations such as creating a bucket, uploading files, listing bucket contents, and downloading files using S3Client. This setup enables us to test and build S3-compatible applications without incurring AWS costs or requiring an active internet connection.

Beyond Amazon S3 compatibility, S3Proxy also supports other storage backends, including Google Cloud Storage, OpenStack Swift, Microsoft Azure Blob Storage, and Ceph RADOS Gateway, making it a versatile solution for integrating and testing with various storage systems.

4. Download the Source Code

This article explored the Java S3Proxy library.

Download
You can download the full source code of this example here: Java s3proxy library

Omozegie Aziegbe

Omos Aziegbe is a technical writer and web/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button