com.formkiq.core.service.AssetServiceS3Default.java Source code

Java tutorial

Introduction

Here is the source code for com.formkiq.core.service.AssetServiceS3Default.java

Source

/*
 * Copyright (C) 2016 FormKiQ Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.formkiq.core.service;

import static com.formkiq.core.service.SystemPropertyService.ASSET_SERVICE_S3;
import static com.formkiq.core.service.SystemPropertyService.S3_ACCESS_KEY;
import static com.formkiq.core.service.SystemPropertyService.S3_ACCESS_SECRET;
import static com.formkiq.core.service.SystemPropertyService.S3_BUCKET_NAME;
import static org.springframework.util.StringUtils.isEmpty;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.transaction.Transactional;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.formkiq.core.dao.SystemDao;

/**
 * S3 implementation of {@link AssetService}.
 *
 */
public class AssetServiceS3Default implements AssetServiceS3, InitializingBean {

    /** Logger. */
    private static final Logger LOG = Logger.getLogger(AssetServiceS3Default.class.getName());

    /** SystemDao. */
    @Autowired
    private SystemDao systemDao;

    /** PlatformTransactionManager. */
    @Autowired
    @Qualifier("transactionManager")
    private PlatformTransactionManager txManager;

    /** Whether environment supports. */
    private boolean isSupported = false;

    /** S3 Access Key. */
    private String s3AccessKey;

    /** S3 Access Secret. */
    private String s3AccessSecret;

    /** S3 Bucket Name. */
    private String s3BucketName;

    /** Amazon S3 Client. */
    private AmazonS3 s3client;

    /**
     * default constructor.
     */
    public AssetServiceS3Default() {
    }

    @Transactional
    @Override
    public void afterPropertiesSet() throws Exception {
        TransactionTemplate tmpl = new TransactionTemplate(this.txManager);
        tmpl.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(final TransactionStatus status) {
                reloadProperties();
            }
        });
    }

    @Override
    public void createBucket(final String name) {

        if (!getS3Connection().doesBucketExist(name)) {
            getS3Connection().createBucket(name);
        }
    }

    @Override
    public void createFolder(final String folder) {

        // create meta-data for your folder and set content-length to 0
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(0);

        // create empty content
        InputStream emptyContent = new ByteArrayInputStream(new byte[0]);

        // create a PutObjectRequest passing the folder name suffixed by /
        PutObjectRequest putObjectRequest = new PutObjectRequest(this.s3BucketName, folder + "/", emptyContent,
                metadata);

        // send request to S3 to create folder
        getS3Connection().putObject(putObjectRequest);
    }

    @Override
    public void deleteObject(final String folder, final String asset) {
        String filename = getFilename(folder, asset);
        getS3Connection().deleteObject(this.s3BucketName, filename);
    }

    @Override
    public boolean doesAssetExist(final String folder, final String asset) {
        String filename = getFilename(folder, asset);
        return getS3Connection().doesObjectExist(this.s3BucketName, filename);
    }

    @SuppressWarnings("resource")
    @Override
    public byte[] findAsset(final String folder, final String asset) throws IOException {

        byte[] bytes = null;
        String filename = getFilename(folder, asset);

        try {
            S3Object object = getS3Connection().getObject(new GetObjectRequest(this.s3BucketName, filename));

            InputStream objectData = object.getObjectContent();

            try {
                bytes = IOUtils.toByteArray(objectData);
            } finally {
                IOUtils.closeQuietly(objectData);
            }

        } catch (SdkClientException e) {
            LOG.log(Level.WARNING, e.getMessage());
        }

        return bytes;
    }

    @Override
    public String getBucketName() {
        return this.s3BucketName;
    }

    /**
     * Get S3 Filename.
     * @param folder {@link String}
     * @param asset {@link String}
     * @return {@link String}
     */
    private String getFilename(final String folder, final String asset) {
        String filename = folder + "/" + asset + ".fkz";
        return filename;
    }

    /**
     * @return {@link AmazonS3}
     */
    private AmazonS3 getS3Connection() {

        if (this.s3client == null) {
            AWSCredentials credentials = new BasicAWSCredentials(this.s3AccessKey, this.s3AccessSecret);
            this.s3client = AmazonS3ClientBuilder.standard()
                    .withCredentials(new AWSStaticCredentialsProvider(credentials)).withRegion(Regions.US_WEST_2) // TODO create aws.properties
                    .build();
        }

        return this.s3client;
    }

    @Override
    public boolean isSupported() {
        return this.isSupported;
    }

    @Override
    public List<Bucket> listBuckets() {
        return getS3Connection().listBuckets();
    }

    @Override
    public void reloadProperties() {

        String prop = this.systemDao.getValue(null, ASSET_SERVICE_S3);
        this.isSupported = Boolean.valueOf(prop).booleanValue();

        if (this.isSupported) {

            this.s3AccessKey = this.systemDao.getValue(null, S3_ACCESS_KEY);

            this.s3AccessSecret = this.systemDao.getValue(null, S3_ACCESS_SECRET);

            this.s3BucketName = this.systemDao.getValue(null, S3_BUCKET_NAME);

            if (isEmpty(this.s3AccessKey) || isEmpty(this.s3AccessSecret) || isEmpty(this.s3BucketName)) {

                this.isSupported = false;
                LOG.log(Level.WARNING, "required system properties " + S3_ACCESS_KEY + ", " + S3_ACCESS_SECRET
                        + ", " + S3_BUCKET_NAME);
            }
        }
    }

    @Override
    public void saveAsset(final String folder, final String asset, final byte[] bytes) {

        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);

        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(bytes.length);
        metadata.setContentType("application/zip");

        try {

            String filename = getFilename(folder, asset);

            AmazonS3 connection = getS3Connection();

            PutObjectRequest req = new PutObjectRequest(this.s3BucketName, filename, bis, metadata);

            connection.putObject(req);

            LOG.log(Level.FINE, "saving " + filename + " to " + S3_BUCKET_NAME);

        } finally {

            IOUtils.closeQuietly(bis);
        }
    }
}