MinioStorageService.java

package api.services.storage;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.errors.ErrorResponseException;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException;
import io.minio.errors.InvalidResponseException;
import io.minio.errors.ServerException;
import io.minio.errors.XmlParserException;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import api.exceptions.StorageException;

/**
 * {@link MinioStorageService}.
 */
@Slf4j
@Service
@Profile("prod")
public class MinioStorageService implements SimpleStorageService {
    @Autowired
    private MinioClient minioClient;

    @Value("${s3.bucket.name:main}")
    private String defaultBucket;

    /**
     * Initialize the Minio storage system.
     */
    @PostConstruct
    public void init() {
        createBucket(defaultBucket);
    }

    @Override
    public void uploadObject(String key, InputStream stream, long size) {
        uploadObject(defaultBucket, key, stream, size);
    }

    private void uploadObject(String bucket, String key, InputStream stream, long size) {
        validateKey(key);
        if (size < 0) {
            throw new IllegalArgumentException("Size must not be negative.");
        }

        try {
            minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(key).stream(stream, size, -1).build());
        } catch (InvalidKeyException | ErrorResponseException | InsufficientDataException | InternalException
            | InvalidResponseException | NoSuchAlgorithmException | ServerException | XmlParserException
            | IllegalArgumentException | IOException e) {
            throw new StorageException(e);
        }
        log.info("S3 object uploaded: " + bucket + "/" + key);
    }

    @Override
    public InputStream downloadObject(String key) {
        return downloadObject(defaultBucket, key);
    }

    private InputStream downloadObject(String bucket, String key) {
        validateKey(key);
        try {
            return minioClient.getObject(GetObjectArgs.builder().bucket(bucket).object(key).build());
        } catch (InvalidKeyException | ErrorResponseException | InsufficientDataException | InternalException
            | InvalidResponseException | NoSuchAlgorithmException | ServerException | XmlParserException
            | IllegalArgumentException | IOException e) {
            throw new StorageException(e);
        }
    }

    @Override
    public void deleteObject(String key) {
        deleteObject(defaultBucket, key);
    }

    private void deleteObject(String bucket, String key) {
        validateKey(key);
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(key).build());
        } catch (InvalidKeyException | ErrorResponseException | InsufficientDataException | InternalException
            | InvalidResponseException | NoSuchAlgorithmException | ServerException | XmlParserException
            | IllegalArgumentException | IOException e) {
            throw new StorageException(e);
        }
        log.info("S3 object deleted: " + bucket + "/" + key);
    }

    /**
     * Create a new Minio bucket.
     *
     * @param bucket bucket name
     */
    public void createBucket(String bucket) {
        try {
            boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
                log.info("S3 bucket created: " + bucket);
            }
        } catch (InvalidKeyException | ErrorResponseException | InsufficientDataException | InternalException
            | InvalidResponseException | NoSuchAlgorithmException | ServerException | XmlParserException
            | IllegalArgumentException | IOException e) {
            throw new StorageException(e);
        }
    }
}