Amazon S3 Resource Locator Example - skremp/pictura-io GitHub Wiki

As of PicturaIO 1.1.2 it is possible to connect to an existing Amazon S3 bucket with its own credentials and a custom resource locator. To handle this, we have to provide a S3ResourceLocator which will convert a requested image resource path to an java.net.URL object and a java.net.URLStreamHandler to handle the new URL protocol s3. If this is done, the io.pictura.servlet.ImageRequestProcessor can reading files from Amazon S3 directly in a java.net.URL object without any change or modification of the core request processor.

S3 Resource Locator

Our own io.pictura.servlet.ResourceLocator to create a valid java.net.URL object from a requested resource (source image) path.

package io.pictura.servlet.s3;

import io.pictura.servlet.ResourceLocator;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;

public class S3ResourceLocator implements ResourceLocator {

    // Custom  Amazon S3 Credentials
    private static final String ACCESS_KEY = ...;
    private static final String SECRET_KEY = ...;

    private static final String BUCKET = ...;

    // Register the new protocol handler package
    static {
        String pkgs = System.getProperty("java.protocol.handler.pkgs");
        if (pkgs == null || pkgs.isEmpty()) {
            System.setProperty("java.protocol.handler.pkgs", 
                "io.pictura.net.protocol");
        } else if (!pkgs.contains("io.pictura.net.protocol")) {
            System.setProperty("java.protocol.handler.pkgs", 
                pkgs + "|io.pictura.net.protocol");
        }
    }

    @Override
    public URL getResource(String path) throws MalformedURLException {
        if (path != null && !path.isEmpty()) {
            String str = path.toLowerCase(Locale.ENGLISH);
            if (str.startsWith("s3://") && str.length() > 5) {
                return new URL("s3://" + ACCESS_KEY + ":" + SECRET_KEY + 
                    "@" + BUCKET + ".s3.amazonaws.com/" + path.substring(5));
            }
        }
        return null;
    }
}

S3 Handler Class

A custom java.net.URLStreamHandler to handle connections to Amazon S3 URL's so we are able to reading files from Amazon S3 directly in a java.net.URL object.

package io.pictura.net.protocol.s3;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import org.jets3t.service.S3ServiceException;
import org.jets3t.service.impl.rest.httpclient.RestS3Service;
import org.jets3t.service.model.S3Bucket;
import org.jets3t.service.model.S3Object;
import org.jets3t.service.security.AWSCredentials;

public final class Handler extends URLStreamHandler {
    
    @Override
    protected URLConnection openConnection(URL u) throws IOException {

        // "s3://<access-key>:<secret-key>@<bucket>.s3.amazonaws.com/<filename>"

        return new URLConnection(u) {

            @Override
            public InputStream getInputStream() throws IOException {
                String accessKey = null;
                String secretKey = null;

                if (url.getUserInfo() != null) {
                    String[] credentials = url.getUserInfo().split("[:]");
                    accessKey = credentials[0];
                    secretKey = credentials[1];
                }

                String bucket = url.getHost().substring(0, url.getHost().indexOf("."));
                String key = url.getPath().substring(1);

                InputStream is = null;
                try {
                    RestS3Service s3Service = new RestS3Service(
                        new AWSCredentials(accessKey, secretKey));
                    S3Object s3obj = s3Service.getObject(
                        new S3Bucket(bucket), key);
                    is = s3obj.getDataInputStream();
                } catch (S3ServiceException e) {
                    throw new IOException(e);
                }                
                return is;
            }

            @Override
            public void connect() throws IOException { }
        };
    }
}

Resource Locator Registration

Now, we can register our custom Amazon S3 resource locator as described in the PicturaIO Image Servlet API Reference, like:

<web-app ...>
...
    <servlet>
        ...
        <init-param>
            <param-name>resourceLocators</param-name>
            <param-value>
                io.pictura.servlet.s3.S3ResourceLocator,
                io.pictura.servlet.HttpResourceLocator,
                io.pictura.servlet.FileResourceLocator
            </param-value>
        </init-param>
    </servlet>
...
</web-app>
⚠️ **GitHub.com Fallback** ⚠️